Skip to content

Commit

Permalink
Allow branding to be preserved in download-for-edit (BL-13110)
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnThomson committed Mar 6, 2024
1 parent 08eb0d9 commit e08630e
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 31 deletions.
4 changes: 4 additions & 0 deletions DistFiles/localization/en/Bloom.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -4634,6 +4634,10 @@ Do you want to go ahead?</note>
<note>ID: PublishTab.UploadCollisionDialog.AlreadyIn</note>
<note>This is the header for the book that is in bloomlibrary.org already.</note>
</trans-unit>
<trans-unit id="PublishTab.UploadCollisionDialog.ChangeBranding" translate="no">
<source xml:lang="en">The branding was "{0}" but is now "{1}". This may change logos and other material. Check this box if this is what you want.</source>
<note>ID: PublishTab.UploadCollisionDialog.ChangeBranding</note>
</trans-unit>
<trans-unit id="PublishTab.UploadCollisionDialog.ChangeUploader" translate="no">
<source xml:lang="en">Change the official uploader to {0}. (Bloom Library will hide part of your email address)</source>
<note>ID: PublishTab.UploadCollisionDialog.ChangeUploader</note>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import { BloomSplitButton } from "../../react_components/bloomSplitButton";
import { ErrorBox, WaitBox } from "../../react_components/boxes";
import {
IUploadCollisionDlgData,
IUploadCollisionDlgProps,
showUploadCollisionDialog,
UploadCollisionDlg
} from "./uploadCollisionDlg";
Expand Down
72 changes: 65 additions & 7 deletions src/BloomBrowserUI/publish/LibraryPublish/uploadCollisionDlg.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export interface IUploadCollisionDlgData {
existingBookUrl: string;
existingThumbUrl?: string;
uploader?: string;
oldBranding?: string;
newBranding?: string;
onCancel?: () => void;
dialogEnvironment?: IBloomDialogEnvironmentParams;
permissions?: IPermissions;
Expand Down Expand Up @@ -88,6 +90,7 @@ export const UploadCollisionDlg: React.FunctionComponent<IUploadCollisionDlgProp
);

const [doChangeUploader, setDoChangeUploader] = useState(false);
const [doChangeBranding, setDoChangeBranding] = useState(false);

const kAskForHelpColor = "#D65649";
const kDarkerSecondaryTextColor = "#555555";
Expand Down Expand Up @@ -137,6 +140,14 @@ export const UploadCollisionDlg: React.FunctionComponent<IUploadCollisionDlgProp
"This is explanatory commentary on a radio button."
);

const changeBrandingMessage = useL10n(
'The branding was "{0}" but is now "{1}". This may change logos and other material. Check this box if this is what you want.',
"PublishTab.UploadCollisionDialog.ChangeBranding",
"Thi is the label of a checkbox",
props.oldBranding,
props.newBranding
);

const sameBookRadioLabel = useL10n(
"Yes, I want to update this book",
"PublishTab.UploadCollisionDialog.Radio.SameBook2",
Expand Down Expand Up @@ -247,6 +258,9 @@ export const UploadCollisionDlg: React.FunctionComponent<IUploadCollisionDlgProp
</div>
);

const needChangeBranding =
props.oldBranding && props.oldBranding !== props.newBranding;

const differentBooksRadioCommentary = (): JSX.Element => (
<div
css={css`
Expand Down Expand Up @@ -286,6 +300,15 @@ export const UploadCollisionDlg: React.FunctionComponent<IUploadCollisionDlgProp
closeDialog();
}

const cssForCheckboxes = css`
margin-left: 37px;
.MuiFormControlLabel-root {
// The default 10px margin seems to me to visually break the connection between the checkboxes and
// their parent radio button.
padding-top: 2px !important;
}
`;

return (
<BloomDialog
onCancel={() => {
Expand Down Expand Up @@ -482,15 +505,49 @@ export const UploadCollisionDlg: React.FunctionComponent<IUploadCollisionDlgProp
ariaLabel="Same book radio button"
commentaryChildren={sameBookRadioCommentary()}
/>
{canUpload && needChangeBranding && (
<div css={cssForCheckboxes}>
{/* The checkbox has an icon prop we could use instead of making it part of
the label, but the mockup has it wrapping as part of the first line of the
label, whereas our BloomCheckbox class puts it out to the left of all the lines
of label, and does something funny with positioning so that neither the icon nor
the text aligns with the text of the other checkbox when both are present. */}
<BloomCheckbox
label={
<p>
<WarningIcon
color="warning"
css={css`
// Aligns it with the text baseline
position: relative;
top: 2px;
// Makes it a little smaller than using 'small' as the fontSize prop.
// more in line with the mockup.
font-size: 1em;
margin-right: 5px;
`}
/>
{changeBrandingMessage}
</p>
}
alreadyLocalized={true}
l10nKey="ignored"
checked={doChangeBranding}
onCheckChanged={() => {
// Enhance: it would probably be nice to select the appropriate radio button
// if it isn't already, but this is a rare special case (branding is rarely
// changed), we're trying to discourage doing it by accident, and it's not
// easy to actually take control of the radio button embedded in the
// RadioWithLabelAndCommentary from here. So for now, the user must do both.)
setDoChangeBranding(!doChangeBranding);
}}
></BloomCheckbox>
</div>
)}
{canUpload &&
canBecomeUploader &&
props.uploader !== props.userEmail && (
<div
css={css`
margin-left: 37px;
margin-top: -12px;
`}
>
<div css={cssForCheckboxes}>
<BloomCheckbox
label={changeTheUploader}
alreadyLocalized={true}
Expand Down Expand Up @@ -538,7 +595,8 @@ export const UploadCollisionDlg: React.FunctionComponent<IUploadCollisionDlgProp
enabled={
// If we don't have permission to overwrite, we can only upload using a new ID
buttonState !== RadioState.Indeterminate &&
(canUpload || buttonState === RadioState.Different)
(canUpload || buttonState === RadioState.Different) &&
(doChangeBranding || !needChangeBranding)
}
size="large"
onClick={() => {
Expand Down
2 changes: 2 additions & 0 deletions src/BloomExe/Book/BookSelection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public void SelectBook(Book book, bool aboutToEdit = false)
// BringUpToDate, typically only in unit tests.
if (book != null && book.BookData != null && book.IsSaveable)
{
// Before we bring it up to date, so it updates to the right branding
book.CollectionSettings.SetCurrentBook(book);
book.EnsureUpToDate();
}

Expand Down
123 changes: 116 additions & 7 deletions src/BloomExe/Collection/CollectionSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
using Bloom.Api;
using Bloom.Book;
using Bloom.MiscUI;
using Bloom.Publish.BloomLibrary;
using Bloom.Publish.BloomPub;
using Bloom.Utils;
using Bloom.web.controllers;
using DesktopAnalytics;
using L10NSharp;
using Newtonsoft.Json.Linq;
using SIL.Code;
using SIL.Extensions;
using SIL.IO;
Expand Down Expand Up @@ -384,6 +386,25 @@ public static string CollectionIdFromCollectionFolder(string collectionFolder)
}
}

/// <summary>
/// Get the branding that the settings file specifies, without checking the subscription code
/// as we would do if creating the object from the settings file.
/// </summary>
public static string LoadBranding(string pathToCollectionFile)
{
try
{
var settingsContent = RobustFile.ReadAllText(pathToCollectionFile, Encoding.UTF8);
var xml = XElement.Parse(settingsContent);
return ReadString(xml, "BrandingProjectName", "");
}
catch (Exception ex)
{
Bloom.Utils.MiscUtils.SuppressUnusedExceptionVarWarning(ex);
return "";
}
}

/// ------------------------------------------------------------------------------------
public void Load()
{
Expand Down Expand Up @@ -662,7 +683,55 @@ internal IEnumerable<string> GetAllLanguageTags()
}

// e.g. "ABC2020" or "Kyrgyzstan2020[English]"
public string BrandingProjectKey { get; set; }
public string BrandingProjectKey
{
get => _overrideBrandingForEditDownload ?? _brandingProjectKey;
set
{
_brandingProjectKey = value;
_overrideBrandingForEditDownload = null;
}
}

private string _overrideBrandingForEditDownload;

public void SetCurrentBook(Book.Book book)
{
if (book == null)
return;
// We allow a previous override to stand until some other book is selected.
// One reason is that CollectionModel.BringBookUpToDate changes the selection to null during the update,
// but we would like it to get updated to the right branding.
_overrideBrandingForEditDownload = null;
var downloadEditPath = Path.Combine(
Path.GetDirectoryName(book.FolderPath),
BloomLibraryPublishModel.kNameOfDownloadForEditFile
);
if (!RobustFile.Exists(downloadEditPath))
return;
try
{
var bookOfCollectionData = JObject.Parse(RobustFile.ReadAllText(downloadEditPath));
//var databaseId = bookOfCollectionData["databaseId"];
var instanceId = bookOfCollectionData["instanceId"]?.ToString();
var bookFolder = bookOfCollectionData["bookFolder"]?.ToString();
var branding = bookOfCollectionData["branding"]?.ToString();
if (
string.IsNullOrEmpty(branding)
|| instanceId != book.ID
|| bookFolder != book.FolderPath.Replace("\\", "/")
)
return; // not validating as the one special book we can edit without the code (or it never had one)
// Now, the final question: has the user reset that branding? If not...if it's just Default in the
// variable because we don't have a code...then we'll do the override.
if (branding == LoadBranding(SettingsFilePath))
_overrideBrandingForEditDownload = branding;
}
catch (Exception)
{
// If we can't process the file, just treat it as not the special book.
}
}

public string GetBrandingFlavor()
{
Expand All @@ -680,17 +749,41 @@ out var flavor
return folderName;
}

public string SubscriptionCode { get; set; }
public string SubscriptionCode
{
get => _subscriptionCode;
set => _subscriptionCode = value;
}

public int OneTimeCheckVersionNumber { get; set; }
public int OneTimeCheckVersionNumber
{
get => _oneTimeCheckVersionNumber;
set => _oneTimeCheckVersionNumber = value;
}

public bool AllowNewBooks { get; set; }
public bool AllowNewBooks
{
get => _allowNewBooks;
set => _allowNewBooks = value;
}

public TalkingBookApi.AudioRecordingMode AudioRecordingMode { get; set; }
public TalkingBookApi.AudioRecordingMode AudioRecordingMode
{
get => _audioRecordingMode;
set => _audioRecordingMode = value;
}

public int AudioRecordingTrimEndMilliseconds { get; set; }
public int AudioRecordingTrimEndMilliseconds
{
get => _audioRecordingTrimEndMilliseconds;
set => _audioRecordingTrimEndMilliseconds = value;
}

public int BooksOnWebGoal { get; set; }
public int BooksOnWebGoal
{
get => _booksOnWebGoal;
set => _booksOnWebGoal = value;
}

public BulkBloomPubPublishSettings BulkPublishBloomPubSettings =
new BulkBloomPubPublishSettings
Expand Down Expand Up @@ -847,6 +940,22 @@ public string CharactersForDigitsForPageNumbers
private readonly Dictionary<string, string> ColorPalettes =
new Dictionary<string, string>();

private string _invalidBranding;
private bool _isSourceCollection;
private string _collectionName;
private string _settingsFilePath;
private string _country;
private string _province;
private string _district;
private string _pageNumberStyle;
private string _brandingProjectKey;
private string _subscriptionCode;
private int _oneTimeCheckVersionNumber;
private bool _allowNewBooks;
private TalkingBookApi.AudioRecordingMode _audioRecordingMode;
private int _audioRecordingTrimEndMilliseconds;
private int _booksOnWebGoal;

public string GetColorPaletteAsJson(string paletteTag)
{
var colorElementList = new List<string>();
Expand Down
2 changes: 0 additions & 2 deletions src/BloomExe/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1310,8 +1310,6 @@ private static void HandleProjectWindowActivated(object sender, EventArgs e)
// Sometimes after closing the splash screen the project window
// looses focus, so do this.
_projectContext.ProjectWindow.Activate();

(_projectContext.ProjectWindow as Shell).CheckForInvalidBranding();
}

/// ------------------------------------------------------------------------------------
Expand Down
28 changes: 22 additions & 6 deletions src/BloomExe/Publish/BloomLibrary/BloomLibraryPublishModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,19 @@ internal dynamic GetConflictingBookInfoFromServer(int index)
return result;
}

public static JObject GetDownloadForEditData(string pathToBookFolder)
{
var filePath = Path.Combine(
Path.GetDirectoryName(pathToBookFolder),
kNameOfDownloadForEditFile
);
if (RobustFile.Exists(filePath))
{
return JObject.Parse(RobustFile.ReadAllText(filePath));
}
return null;
}

/// <summary>
/// If we have multiple conflicting books, we want to sort them in a way that makes sense to the user.
/// If we're in a collection that was made for editing one particular book, and this is the book,
Expand Down Expand Up @@ -174,13 +187,9 @@ Func<string, bool> canUpload
return books;
var remaining = books.ToList();
var bookList = new List<dynamic>();
var filePath = Path.Combine(
Path.GetDirectoryName(pathToBookFolder),
kNameOfDownloadForEditFile
);
if (File.Exists(filePath))
var bookOfCollectionData = GetDownloadForEditData(pathToBookFolder);
if (bookOfCollectionData != null)
{
var bookOfCollectionData = JObject.Parse(RobustFile.ReadAllText(filePath));
var databaseId = bookOfCollectionData["databaseId"];
var instanceId = bookOfCollectionData["instanceId"];
var bookFolder = bookOfCollectionData["bookFolder"]?.ToString();
Expand Down Expand Up @@ -788,6 +797,11 @@ out string[] existingLanguages
var updatedDate = updatedDateTime.ToString("d", CultureInfo.CurrentCulture);
var existingThumbUrl = GetBloomLibraryThumbnailUrl(existingBookInfo);

// We could get it from the data about the download-for-edit book, but why limit this to those books?
//var bookDownloadForEditData = GetDownloadForEditData(Book.FolderPath);
//var oldBranding = bookDownloadForEditData?["branding"]?.ToString();
var oldBranding = existingBookInfo.brandingProjectName?.ToString();

// Must match IUploadCollisionDlgProps in uploadCollisionDlg.tsx.
return new
{
Expand All @@ -803,6 +817,8 @@ out string[] existingLanguages
existingUpdatedDate = updatedDate,
existingBookUrl,
existingThumbUrl,
newBranding = Book.BookInfo.BrandingProjectKey,
oldBranding,
uploader = existingBookInfo.uploader.email,
count = existingBookInfo.count,
permissions = existingBookInfo.permissions
Expand Down
5 changes: 0 additions & 5 deletions src/BloomExe/Shell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,6 @@ AudioRecording audioRecording
SetWindowText(null);
}

public void CheckForInvalidBranding()
{
_workspaceView.CheckForInvalidBranding();
}

protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
Expand Down
Loading

0 comments on commit e08630e

Please sign in to comment.