Skip to content

Commit

Permalink
Allow cover to be full-bleed image (BL-13271)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-polk committed Nov 20, 2024
1 parent a53d13a commit 86faf05
Show file tree
Hide file tree
Showing 12 changed files with 287 additions and 34 deletions.
12 changes: 12 additions & 0 deletions DistFiles/localization/en/BloomMediumPriority.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
<note>We are in the process of moving strings from Bloom.xlf to BloomMediumPriority.xlf and BloomLowPriority.xlf while trying very hard to preserve translations and approval status.</note>
</header>
<body>
<trans-unit id="AvailableWithEnterprise" translate="no">
<source xml:lang="en">Available with your Enterprise Subscription</source>
<note>ID: AvailableWithEnterprise</note>
</trans-unit>
<!-- Drag Activity Tool -->
<trans-unit id="EditTab.Toolbox.DragActivity.Check">
<source xml:lang="en">Check</source>
Expand Down Expand Up @@ -600,6 +604,14 @@
<source xml:lang="en">Cover</source>
<note>BookSettings.CoverGroupLabel</note>
</trans-unit>
<trans-unit id="BookSettings.CoverIsImage" sil:dynamic="true" translate="no">
<source xml:lang="en">Fill the front cover with a single image</source>
<note>BookSettings.CoverIsImage</note>
</trans-unit>
<trans-unit id="BookSettings.CoverIsImage.Description" sil:dynamic="true" translate="no">
<source xml:lang="en">Using this option turns on the [Print Bleed](https://docs.bloomlibrary.org) indicators on paper layouts. See [Full Page Cover Images](https://docs.bloomlibrary.org) for information on sizing your image to fit.</source>
<note>BookSettings.CoverIsImage.Description</note>
</trans-unit>
<trans-unit id="BookSettings.ContentPagesGroupLabel" sil:dynamic="true">
<source xml:lang="en">Content Pages</source>
<note>BookSettings.ContentPagesGroupLabel</note>
Expand Down
46 changes: 45 additions & 1 deletion src/BloomBrowserUI/bookEdit/bookSettings/BookSettingsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ import { default as TrashIcon } from "@mui/icons-material/Delete";
import { PWithLink } from "../../react_components/pWithLink";
import { FieldVisibilityGroup } from "./FieldVisibilityGroup";
import { StyleAndFontTable } from "./StyleAndFontTable";
import {
BloomEnterpriseIndicatorIconAndText,
useEnterpriseAvailable
} from "../../react_components/requiresBloomEnterprise";

let isOpenAlready = false;

Expand Down Expand Up @@ -208,6 +212,16 @@ export const BookSettingsDialog: React.FunctionComponent<{
"BookSettings.TopLevelTextPadding.1emLabel"
);

const coverIsImageLabel = useL10n(
"Fill the front cover with a single image",
"BookSettings.CoverIsImage"
);
//TODO real links (and change .xlf)
const coverIsImageDescription = useL10n(
"Using this option turns on the [Print Bleed](https://docs.bloomlibrary.org) indicators on paper layouts. See [Full Page Cover Images](https://docs.bloomlibrary.org) for information on sizing your image to fit.",
"BookSettings.CoverIsImage.Description"
);

// This is a helper function to make it easier to pass the override information
function getAdditionalProps<T>(
subPath: string
Expand Down Expand Up @@ -306,6 +320,8 @@ export const BookSettingsDialog: React.FunctionComponent<{
setMigratedTheme("");
};

const enterpriseAvailable = useEnterpriseAvailable();

function saveSettingsAndCloseDialog() {
if (settingsToReturnLater) {
// If nothing changed, we don't get any...and don't need to make this call.
Expand Down Expand Up @@ -353,7 +369,7 @@ export const BookSettingsDialog: React.FunctionComponent<{
height: 600px;
// This odd width was chosen to make the customBookStyles alert box format nicely.
// See BL-12956. It's not that important, but I don't think anything else is affected
// much by the exact witdh.
// much by the exact width.
width: 638px;
#groups {
margin-right: 10px; // make room for the scrollbar
Expand Down Expand Up @@ -398,6 +414,34 @@ export const BookSettingsDialog: React.FunctionComponent<{
label={whatToShowOnCoverLabel}
path={`appearance`}
>
<div>
<ConfigrBoolean
label={coverIsImageLabel}
description={coverIsImageDescription}
{...getAdditionalProps<boolean>(
`coverIsImage`
)}
disabled={
appearanceDisabled ||
!enterpriseAvailable
}
/>
<div
css={css`
display: flex;
padding-bottom: 5px;
font-size: 12px;
font-weight: bold;
`}
>
<BloomEnterpriseIndicatorIconAndText
css={css`
margin-left: auto;
`}
disabled={appearanceDisabled}
/>
</div>
</div>
<FieldVisibilityGroup
field="cover-title"
labelFrame="Show Title in {0}"
Expand Down
44 changes: 43 additions & 1 deletion src/BloomBrowserUI/react_components/requiresBloomEnterprise.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { get, post } from "../utils/bloomApi";
import Button from "@mui/material/Button";
import { kBloomBlue50Transparent, lightTheme } from "../bloomMaterialUITheme";
import { ThemeProvider, StyledEngineProvider } from "@mui/material/styles";
import { Div } from "./l10nComponents";
import { Div, Span } from "./l10nComponents";
import { useL10n } from "./l10nHooks";
import { WireUpForWinforms } from "../utils/WireUpWinform";
import { Dialog, DialogActions, DialogContent } from "@mui/material";
Expand Down Expand Up @@ -490,6 +490,48 @@ export const RequiresBloomEnterpriseDialog: React.FunctionComponent<{
);
};

export const BloomEnterpriseIndicatorIconAndText: React.FunctionComponent<{
disabled?: boolean;
className?: string;
}> = props => {
const enterpriseAvailable = useEnterpriseAvailable();

return (
<div
onClick={() => {
enterpriseAvailable ||
props.disabled ||
openBloomEnterpriseSettings();
}}
css={css`
display: flex;
align-items: center;
${enterpriseAvailable || props.disabled || "cursor:pointer"};
opacity: ${props.disabled ? kBloomDisabledOpacity : 1.0};
`}
className={props.className}
>
<img
src={badgeUrl}
css={css`
height: 1.5em;
padding-right: 0.5em;
`}
/>
{enterpriseAvailable ? (
<Span l10nKey={"AvailableWithEnterprise"}>
Available with your Enterprise Subscription
</Span>
) : (
<Span l10nKey={"Common.EnterpriseRequired"}>
Enterprise Required
</Span>
)}
</div>
);
};

function openBloomEnterpriseSettings() {
post("common/showSettingsDialog?tab=enterprise");
}
Expand Down
125 changes: 106 additions & 19 deletions src/BloomExe/Book/AppearanceSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ public class AppearanceSettings
public AppearanceSettings()
{
_properties = new ExpandoObject();
if (_substitutinator == null)
if (_appearanceMigrator == null)
{
_substitutinator = new AppearanceMigrator();
_appearanceMigrator = new AppearanceMigrator();
}

// copy in the default values from each definition
Expand All @@ -43,7 +43,7 @@ public AppearanceSettings()
public static string kDoShowValueForDisplay = "doShow-css-will-ignore-this-and-use-default"; // by using an illegal value, we just get a no-op rule, which is what we want
public static string kHideValueForDisplay = "none";
public static string kOverrideGroupsArrayKey = "groupsToOverrideFromParent"; // e.g. "coverFields, xmatter"
private static AppearanceMigrator _substitutinator;
private static AppearanceMigrator _appearanceMigrator;

// A representation of the content of Appearance.json
internal dynamic _properties;
Expand Down Expand Up @@ -108,7 +108,19 @@ public string FirstPossiblyOffendingCssFile
// The default here is rarely if ever relevant. Usually a newly created instance will be initialized from a folder, and the default will be overwritten,
// either to whatever we find in appearance.json, or to "legacy-5-6" if there is no appearance.json.
new StringPropertyDef("cssThemeName", "cssThemeName", "default"),
// BooleanPropertyDef, not CssXDef because this is not a css variable.
new BooleanPropertyDef(
"coverIsImage",
"coverIsImage",
defaultValue: false,
requiresXmatterUpdate: true
), // If true, cover page is just a full bleed image.
// Not implemented yet. When it is, it needs to be tied together with the coverIsImage setting
// such that coverIsImage cannot be true unless fullBleed is also true.
//new BooleanPropertyDef("fullBleed", "fullBleed", false), // If true, book is full bleed.

new CssStringVariableDef("cover-background-color", "colors"),
// User can turn the visibility of these fields on and off in the dialog.
new CssDisplayVariableDef("cover-title-L1-show", "coverFields", true),
new CssDisplayVariableDef("cover-title-L2-show", "coverFields", true),
new CssDisplayVariableDef("cover-title-L3-show", "coverFields", false),
Expand Down Expand Up @@ -156,9 +168,62 @@ public string FirstPossiblyOffendingCssFile
public string CssThemeName
{
get { return _properties.cssThemeName; }
set { _properties.cssThemeName = value; }
set
{
_properties.cssThemeName = value;
SetRequiredValuesIfLegacyTheme();
}
}

// Some setting values are not allowed in legacy mode.
private void SetRequiredValuesIfLegacyTheme()
{
if (CssThemeName != "legacy-5-6") // Can't use UsingLegacy here because it includes logic about the syncing of files which we don't want.
return;

var propertyValuesRequiredByLegacyTheme = new Dictionary<string, object>()
{
//REVIEW: I think that some of the other properties should also be here.
// This concept of forcing a value based on the legacy theme was introduced at the time coverIsImage was added.
// But I think the properties which existed before that and which get disabled by setting the theme
// to legacy should also be here.
// e.g. cover-topic-show
// Without this, the user can set the theme to non-legacy, change the property to whatever he wants,
// then change the theme back to legacy.
{ "coverIsImage", false }
};
foreach (var property in propertyValuesRequiredByLegacyTheme)
SetProperty(property);
}

private void SetProperty(KeyValuePair<string, object> property)
{
if (
!Properties.ContainsKey(property.Key)
|| !Properties[property.Key].Equals(property.Value)
)
{
var propDef = propertyDefinitions.FirstOrDefault(pd => pd.Name == property.Key);
if (propDef?.RequiresXmatterUpdate == true)
PendingChangeRequiresXmatterUpdate = true;
}

Properties[property.Key] = property.Value;
}

public bool CoverIsImage
{
get { return _properties.coverIsImage; }
}

//public bool FullBleed
//{
// get { return _properties.fullBleed; }
// set { _properties.fullBleed = value; }
//}

public bool PendingChangeRequiresXmatterUpdate;

/// <summary>
/// Usually, this is simply the theme name, but if the book doesn't have one (that is, it was made by
/// an earlier Bloom and has not been migrated), it answers "none". Currently this is used only
Expand Down Expand Up @@ -682,9 +747,9 @@ public string GetCssOwnPropsDeclaration(dynamic properties, AppearanceSettings p
}
}

if (definition is CssPropertyDef)
if (definition is CssPropertyDef cssPropertydefinition)
{
var setting = ((PropertyDef)definition).GetCssVariableDeclaration(keyValuePair);
var setting = cssPropertydefinition.GetCssVariableDeclaration(keyValuePair);
if (!string.IsNullOrEmpty(setting))
cssBuilder.AppendLine("\t" + setting);
}
Expand Down Expand Up @@ -801,13 +866,14 @@ internal void UpdateFromJson(string json)
{
// parse the json into an object
var x = JsonConvert.DeserializeObject<ExpandoObject>(json);
//and then for each property, copy into the _properties object
// For backwards capabilty, if the json we are reading has a null for a value,
// do not override the default value that we already have loaded.

// and then for each property, copy into the Properties object.
// The original comment here also said: For backwards capability, if the json we are reading has a null for a value, do not override the default value that we already have loaded.
// But the code didn't seem to implement that when I got here. (AP, Aug 2024)
foreach (var property in (IDictionary<string, object>)x)
{
Properties[property.Key] = property.Value;
}
SetProperty(property);

SetRequiredValuesIfLegacyTheme();
}

/// <summary>
Expand Down Expand Up @@ -971,6 +1037,7 @@ public abstract class PropertyDef
{
public string Name;
public dynamic DefaultValue;
public bool RequiresXmatterUpdate;

public void SetDefault(dynamic prop)
{
Expand All @@ -981,27 +1048,47 @@ public void SetDefault(dynamic prop)
/// The name of the group of properties that can a book can override from a collection, or a page can override from a book.
/// </summary>
public string OverrideGroup;

public abstract string GetCssVariableDeclaration(dynamic property);
}

public abstract class CssPropertyDef : PropertyDef { }

// StringPropertyDefs and BooleanPropertyDefs get written to appearance.json but not appearance.css
public class StringPropertyDef : PropertyDef
{
public StringPropertyDef(string name, string overrideGroup, string defaultValue)
public StringPropertyDef(
string name,
string overrideGroup,
string defaultValue,
bool requiresXmatterUpdate = false
)
{
Name = name;
DefaultValue = defaultValue;
OverrideGroup = overrideGroup;
RequiresXmatterUpdate = requiresXmatterUpdate;
}
}

public override string GetCssVariableDeclaration(dynamic property)
public class BooleanPropertyDef : PropertyDef
{
public BooleanPropertyDef(
string name,
string overrideGroup,
bool defaultValue,
bool requiresXmatterUpdate = false
)
{
return $"--{Name}: {property.Value};";
Name = name;
OverrideGroup = overrideGroup;
DefaultValue = defaultValue;
RequiresXmatterUpdate = requiresXmatterUpdate;
}
}

// CssPropertyDefs get written to appearance.json and appearance.css
public abstract class CssPropertyDef : PropertyDef
{
public abstract string GetCssVariableDeclaration(dynamic property);
}

public class CssStringVariableDef : CssPropertyDef
{
public CssStringVariableDef(string name, string overrideGroup, string defaultValue = null)
Expand Down
Loading

0 comments on commit 86faf05

Please sign in to comment.