Skip to content

Commit

Permalink
fix: upload custom theme issue (AppFlowy-IO#4317)
Browse files Browse the repository at this point in the history
* fix: FlowyDynamicPlugin encode issue

* chore: improve the default theme color

* fix: learn more button text invisiable

* fix: fix read the wrong theme mode file

* fix: prevent current custom theme being deleted

* chore: improve theme upload UI and error prompts

* chore: delete unnecessary LocaleKeys
  • Loading branch information
hyj1204 authored Jan 10, 2024
1 parent 239bf2f commit b1cc4e4
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ class ColorSchemeUploadPopover extends StatelessWidget {
},
),
),
if (!isBuiltin)
// when the custom theme is not the current theme, show the remove button
if (!isBuiltin && currentTheme != theme)
FlowyIconButton(
icon: const FlowySvg(
FlowySvgs.close_s,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export 'theme_confirm_delete_dialog.dart';
export 'theme_upload_button.dart';
export 'theme_upload_learn_more_button.dart';
export 'theme_upload_decoration.dart';
export 'theme_upload_failure_widget.dart';
export 'theme_upload_loading_widget.dart';
export 'theme_upload_view.dart';
export 'upload_new_theme_widget.dart';
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/theme_upload/theme_upload.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';

import 'theme_upload_button.dart';
import 'theme_upload_view.dart';

class ThemeUploadFailureWidget extends StatelessWidget {
const ThemeUploadFailureWidget({super.key});
const ThemeUploadFailureWidget({super.key, required this.errorMessage});

final String errorMessage;

@override
Widget build(BuildContext context) {
Expand All @@ -23,17 +21,21 @@ class ThemeUploadFailureWidget extends StatelessWidget {
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Spacer(),
FlowySvg(
FlowySvgs.close_m,
size: ThemeUploadWidget.iconSize,
color: Theme.of(context).colorScheme.onBackground,
),
FlowyText.medium(
LocaleKeys.settings_appearance_themeUpload_failure.tr(),
errorMessage,
overflow: TextOverflow.ellipsis,
),
ThemeUploadWidget.elementSpacer,
const ThemeUploadLearnMoreButton(),
ThemeUploadWidget.elementSpacer,
ThemeUploadButton(color: Theme.of(context).colorScheme.error),
ThemeUploadWidget.elementSpacer,
],
),
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/theme_upload/theme_upload_view.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/buttons/secondary_button.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

class ThemeUploadLearnMoreButton extends StatelessWidget {
const ThemeUploadLearnMoreButton({super.key});

static const learnMoreURL =
'https://appflowy.gitbook.io/docs/essential-documentation/themes';

@override
Widget build(BuildContext context) {
return SizedBox(
height: ThemeUploadWidget.buttonSize.height,
child: IntrinsicWidth(
child: SecondaryButton(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: FlowyText.medium(
fontSize: ThemeUploadWidget.buttonFontSize,
LocaleKeys.document_plugins_autoGeneratorLearnMore.tr(),
),
),
onPressed: () async {
final uri = Uri.parse(learnMoreURL);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
if (context.mounted) {
Dialogs.show(
context,
child: FlowyDialog(
child: FlowyErrorPage.message(
LocaleKeys
.settings_appearance_themeUpload_urlUploadFailure
.tr()
.replaceAll(
'{}',
uri.toString(),
),
howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(),
),
),
);
}
}
},
),
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ThemeUploadWidget extends StatefulWidget {

static const double borderRadius = 8;
static const double buttonFontSize = 14;
static const Size buttonSize = Size(72, 28);
static const Size buttonSize = Size(100, 32);
static const EdgeInsets padding = EdgeInsets.all(12.0);
static const Size iconSize = Size.square(48);
static const Widget elementSpacer = SizedBox(height: 12);
Expand Down Expand Up @@ -41,9 +41,10 @@ class _ThemeUploadWidgetState extends State<ThemeUploadWidget> {
key: Key('upload_theme_loading_widget'),
);
},
compilationFailure: () {
child = const ThemeUploadFailureWidget(
key: Key('upload_theme_failure_widget'),
compilationFailure: (errorMessage) {
child = ThemeUploadFailureWidget(
key: const Key('upload_theme_failure_widget'),
errorMessage: errorMessage,
);
},
compilationSuccess: () {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/theme_upload/theme_upload_button.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/theme_upload/theme_upload.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

import 'theme_upload_view.dart';

class UploadNewThemeWidget extends StatelessWidget {
const UploadNewThemeWidget({super.key});

static const learnMoreRedirect =
'https://appflowy.gitbook.io/docs/essential-documentation/themes';

@override
Widget build(BuildContext context) {
return Container(
Expand All @@ -28,6 +20,7 @@ class UploadNewThemeWidget extends StatelessWidget {
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Spacer(),
FlowySvg(
FlowySvgs.folder_m,
size: ThemeUploadWidget.iconSize,
Expand All @@ -38,51 +31,12 @@ class UploadNewThemeWidget extends StatelessWidget {
overflow: TextOverflow.ellipsis,
),
ThemeUploadWidget.elementSpacer,
SizedBox(
height: ThemeUploadWidget.buttonSize.height,
child: IntrinsicWidth(
child: FlowyButton(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Theme.of(context).colorScheme.onBackground,
),
hoverColor: Theme.of(context).colorScheme.onBackground,
text: FlowyText.medium(
fontSize: ThemeUploadWidget.buttonFontSize,
color: Theme.of(context).colorScheme.onPrimary,
LocaleKeys.document_plugins_autoGeneratorLearnMore.tr(),
),
onTap: () async {
final uri = Uri.parse(learnMoreRedirect);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
if (context.mounted) {
Dialogs.show(
context,
child: FlowyDialog(
child: FlowyErrorPage.message(
LocaleKeys
.settings_appearance_themeUpload_urlUploadFailure
.tr()
.replaceAll(
'{}',
uri.toString(),
),
howToFix:
LocaleKeys.errorDialog_howToFixFallback.tr(),
),
),
);
}
}
},
),
),
),
const ThemeUploadLearnMoreButton(),
ThemeUploadWidget.elementSpacer,
const Divider(),
ThemeUploadWidget.elementSpacer,
const ThemeUploadButton(),
ThemeUploadWidget.elementSpacer,
],
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ class DefaultColorScheme extends FlowyColorScheme {
onPrimary: _white,
hoverBG1: _lightBg2,
hoverBG2: _lightHover,
hoverBG3: _lightShader6,
hoverFG: _lightShader1,
questionBubbleBG: _lightSelector,
hoverBG3: _lightShader6,
progressBarBGColor: _lightTint9,
toolbarColor: _lightShader1,
toggleButtonBGColor: _lightShader5,
calendarWeekendBGColor: const Color(0xFFFBFBFC),
gridRowCountColor: const Color(0xff000000),
gridRowCountColor: _lightShader1,
);

const DefaultColorScheme.dark()
Expand Down Expand Up @@ -122,7 +122,7 @@ class DefaultColorScheme extends FlowyColorScheme {
progressBarBGColor: _darkShader3,
toolbarColor: _darkInput,
toggleButtonBGColor: _darkShader1,
calendarWeekendBGColor: const Color(0xff121212),
gridRowCountColor: _darkMain1,
calendarWeekendBGColor: _darkShader1,
gridRowCountColor: _darkShader5,
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ class DynamicPluginBloc extends Bloc<DynamicPluginEvent, DynamicPluginState> {
return;
}
await FlowyPluginService.instance.addPlugin(plugin);
} on PluginCompilationException {
return emit(const DynamicPluginState.compilationFailure());
} on PluginCompilationException catch (exception) {
return emit(DynamicPluginState.compilationFailure(
errorMessage: exception.message));
}

emit(const DynamicPluginState.compilationSuccess());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ class DynamicPluginState with _$DynamicPluginState {
required Iterable<FlowyDynamicPlugin> plugins,
}) = Ready;
const factory DynamicPluginState.processing() = _Processing;
const factory DynamicPluginState.compilationFailure() = _CompilationFailure;
const factory DynamicPluginState.compilationFailure(
{required String errorMessage}) = _CompilationFailure;
const factory DynamicPluginState.deletionFailure({
required String path,
}) = _DeletionFailure;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,21 @@ class FlowyDynamicPlugin {
/// compilation error will be thrown during the construction of this object.
Future<Directory> encode() async {
final fs = MemoryFileSystem();
final result = fs.directory(_fsPluginName)..createSync();
final directory = fs.directory(_fsPluginName)..createSync();

final lightPath = p.join(_fsPluginName, '$name.$lightExtension');
result.childFile(lightPath).createSync();
result
.childFile(lightPath)
final lightThemeFileName = '$name.$lightExtension';
directory.childFile(lightThemeFileName).createSync();
directory
.childFile(lightThemeFileName)
.writeAsStringSync(jsonEncode(theme!.lightTheme.toJson()));

final darkPath = p.join(_fsPluginName, '$name.$darkExtension');
result.childFile(darkPath).createSync();
result
.childFile(p.join(_fsPluginName, '$name.$darkExtension'))
final darkThemeFileName = '$name.$darkExtension';
directory.childFile(darkThemeFileName).createSync();
directory
.childFile(darkThemeFileName)
.writeAsStringSync(jsonEncode(theme!.darkTheme.toJson()));

return result;
return directory;
}

/// Theme plugins should have the following format.
Expand Down Expand Up @@ -119,13 +119,32 @@ class FlowyDynamicPlugin {
event is File && p.basename(event.path).contains(darkExtension))
.first as File;

late final FlowyColorScheme lightTheme;
late final FlowyColorScheme darkTheme;

try {
lightTheme = FlowyColorScheme.fromJson(
await jsonDecode(await light.readAsString()));
} catch (e) {
throw PluginCompilationException(
'The light theme json file is not valid.',
);
}

try {
darkTheme = FlowyColorScheme.fromJson(
await jsonDecode(await dark.readAsString()));
} catch (e) {
throw PluginCompilationException(
'The dark theme json file is not valid.',
);
}

final theme = AppTheme(
themeName: name,
builtIn: false,
lightTheme:
FlowyColorScheme.fromJson(jsonDecode(await light.readAsString())),
darkTheme:
FlowyColorScheme.fromJson(jsonDecode(await dark.readAsString())),
lightTheme: lightTheme,
darkTheme: darkTheme,
);

return FlowyDynamicPlugin._(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ class SecondaryButton extends StatelessWidget {
minWidth: size.width,
minHeight: size.height,
contentPadding: EdgeInsets.zero,
bgColor: Theme.of(context).colorScheme.surface,
outlineColor: Theme.of(context).colorScheme.primary,
bgColor: Colors.transparent,
outlineColor: Theme.of(context).colorScheme.onBackground,
borderRadius: mode.borderRadius,
onPressed: onPressed,
child: child,
Expand Down
1 change: 0 additions & 1 deletion frontend/resources/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,6 @@
"button": "Upload",
"uploadTheme": "Upload theme",
"description": "Upload your own AppFlowy theme using the button below.",
"failure": "The theme that was uploaded had an invalid format.",
"loading": "Please wait while we validate and upload your theme...",
"uploadSuccess": "Your theme was uploaded successfully",
"deletionFailure": "Failed to delete the theme. Try to delete it manually.",
Expand Down

0 comments on commit b1cc4e4

Please sign in to comment.