Skip to content

Commit b1cc4e4

Browse files
authored
fix: upload custom theme issue (#4317)
* 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
1 parent 239bf2f commit b1cc4e4

File tree

12 files changed

+131
-87
lines changed

12 files changed

+131
-87
lines changed

frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_appearance/color_scheme.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ class ColorSchemeUploadPopover extends StatelessWidget {
157157
},
158158
),
159159
),
160-
if (!isBuiltin)
160+
// when the custom theme is not the current theme, show the remove button
161+
if (!isBuiltin && currentTheme != theme)
161162
FlowyIconButton(
162163
icon: const FlowySvg(
163164
FlowySvgs.close_s,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export 'theme_confirm_delete_dialog.dart';
2+
export 'theme_upload_button.dart';
3+
export 'theme_upload_learn_more_button.dart';
4+
export 'theme_upload_decoration.dart';
5+
export 'theme_upload_failure_widget.dart';
6+
export 'theme_upload_loading_widget.dart';
7+
export 'theme_upload_view.dart';
8+
export 'upload_new_theme_widget.dart';

frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/theme_upload/theme_upload_failure_widget.dart

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import 'package:appflowy/generated/flowy_svgs.g.dart';
2-
import 'package:appflowy/generated/locale_keys.g.dart';
3-
import 'package:easy_localization/easy_localization.dart';
2+
import 'package:appflowy/workspace/presentation/settings/widgets/theme_upload/theme_upload.dart';
43
import 'package:flowy_infra_ui/style_widget/text.dart';
54
import 'package:flutter/material.dart';
65

7-
import 'theme_upload_button.dart';
8-
import 'theme_upload_view.dart';
9-
106
class ThemeUploadFailureWidget extends StatelessWidget {
11-
const ThemeUploadFailureWidget({super.key});
7+
const ThemeUploadFailureWidget({super.key, required this.errorMessage});
8+
9+
final String errorMessage;
1210

1311
@override
1412
Widget build(BuildContext context) {
@@ -23,17 +21,21 @@ class ThemeUploadFailureWidget extends StatelessWidget {
2321
mainAxisSize: MainAxisSize.max,
2422
mainAxisAlignment: MainAxisAlignment.center,
2523
children: [
24+
const Spacer(),
2625
FlowySvg(
2726
FlowySvgs.close_m,
2827
size: ThemeUploadWidget.iconSize,
2928
color: Theme.of(context).colorScheme.onBackground,
3029
),
3130
FlowyText.medium(
32-
LocaleKeys.settings_appearance_themeUpload_failure.tr(),
31+
errorMessage,
3332
overflow: TextOverflow.ellipsis,
3433
),
3534
ThemeUploadWidget.elementSpacer,
35+
const ThemeUploadLearnMoreButton(),
36+
ThemeUploadWidget.elementSpacer,
3637
ThemeUploadButton(color: Theme.of(context).colorScheme.error),
38+
ThemeUploadWidget.elementSpacer,
3739
],
3840
),
3941
);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import 'package:appflowy/generated/locale_keys.g.dart';
2+
import 'package:appflowy/workspace/presentation/settings/widgets/theme_upload/theme_upload_view.dart';
3+
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
4+
import 'package:easy_localization/easy_localization.dart';
5+
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
6+
import 'package:flowy_infra_ui/widget/buttons/secondary_button.dart';
7+
import 'package:flowy_infra_ui/widget/error_page.dart';
8+
import 'package:flutter/material.dart';
9+
import 'package:url_launcher/url_launcher.dart';
10+
11+
class ThemeUploadLearnMoreButton extends StatelessWidget {
12+
const ThemeUploadLearnMoreButton({super.key});
13+
14+
static const learnMoreURL =
15+
'https://appflowy.gitbook.io/docs/essential-documentation/themes';
16+
17+
@override
18+
Widget build(BuildContext context) {
19+
return SizedBox(
20+
height: ThemeUploadWidget.buttonSize.height,
21+
child: IntrinsicWidth(
22+
child: SecondaryButton(
23+
child: Padding(
24+
padding: const EdgeInsets.symmetric(horizontal: 8),
25+
child: FlowyText.medium(
26+
fontSize: ThemeUploadWidget.buttonFontSize,
27+
LocaleKeys.document_plugins_autoGeneratorLearnMore.tr(),
28+
),
29+
),
30+
onPressed: () async {
31+
final uri = Uri.parse(learnMoreURL);
32+
if (await canLaunchUrl(uri)) {
33+
await launchUrl(uri);
34+
} else {
35+
if (context.mounted) {
36+
Dialogs.show(
37+
context,
38+
child: FlowyDialog(
39+
child: FlowyErrorPage.message(
40+
LocaleKeys
41+
.settings_appearance_themeUpload_urlUploadFailure
42+
.tr()
43+
.replaceAll(
44+
'{}',
45+
uri.toString(),
46+
),
47+
howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(),
48+
),
49+
),
50+
);
51+
}
52+
}
53+
},
54+
),
55+
),
56+
);
57+
}
58+
}

frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/theme_upload/theme_upload_view.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class ThemeUploadWidget extends StatefulWidget {
1313

1414
static const double borderRadius = 8;
1515
static const double buttonFontSize = 14;
16-
static const Size buttonSize = Size(72, 28);
16+
static const Size buttonSize = Size(100, 32);
1717
static const EdgeInsets padding = EdgeInsets.all(12.0);
1818
static const Size iconSize = Size.square(48);
1919
static const Widget elementSpacer = SizedBox(height: 12);
@@ -41,9 +41,10 @@ class _ThemeUploadWidgetState extends State<ThemeUploadWidget> {
4141
key: Key('upload_theme_loading_widget'),
4242
);
4343
},
44-
compilationFailure: () {
45-
child = const ThemeUploadFailureWidget(
46-
key: Key('upload_theme_failure_widget'),
44+
compilationFailure: (errorMessage) {
45+
child = ThemeUploadFailureWidget(
46+
key: const Key('upload_theme_failure_widget'),
47+
errorMessage: errorMessage,
4748
);
4849
},
4950
compilationSuccess: () {

frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/theme_upload/upload_new_theme_widget.dart

Lines changed: 5 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
import 'package:appflowy/generated/flowy_svgs.g.dart';
22
import 'package:appflowy/generated/locale_keys.g.dart';
3-
import 'package:appflowy/workspace/presentation/settings/widgets/theme_upload/theme_upload_button.dart';
4-
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
3+
import 'package:appflowy/workspace/presentation/settings/widgets/theme_upload/theme_upload.dart';
54
import 'package:easy_localization/easy_localization.dart';
65
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
7-
import 'package:flowy_infra_ui/widget/error_page.dart';
86
import 'package:flutter/material.dart';
9-
import 'package:url_launcher/url_launcher.dart';
10-
11-
import 'theme_upload_view.dart';
127

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

16-
static const learnMoreRedirect =
17-
'https://appflowy.gitbook.io/docs/essential-documentation/themes';
18-
1911
@override
2012
Widget build(BuildContext context) {
2113
return Container(
@@ -28,6 +20,7 @@ class UploadNewThemeWidget extends StatelessWidget {
2820
mainAxisSize: MainAxisSize.max,
2921
mainAxisAlignment: MainAxisAlignment.center,
3022
children: [
23+
const Spacer(),
3124
FlowySvg(
3225
FlowySvgs.folder_m,
3326
size: ThemeUploadWidget.iconSize,
@@ -38,51 +31,12 @@ class UploadNewThemeWidget extends StatelessWidget {
3831
overflow: TextOverflow.ellipsis,
3932
),
4033
ThemeUploadWidget.elementSpacer,
41-
SizedBox(
42-
height: ThemeUploadWidget.buttonSize.height,
43-
child: IntrinsicWidth(
44-
child: FlowyButton(
45-
decoration: BoxDecoration(
46-
borderRadius: BorderRadius.circular(8),
47-
color: Theme.of(context).colorScheme.onBackground,
48-
),
49-
hoverColor: Theme.of(context).colorScheme.onBackground,
50-
text: FlowyText.medium(
51-
fontSize: ThemeUploadWidget.buttonFontSize,
52-
color: Theme.of(context).colorScheme.onPrimary,
53-
LocaleKeys.document_plugins_autoGeneratorLearnMore.tr(),
54-
),
55-
onTap: () async {
56-
final uri = Uri.parse(learnMoreRedirect);
57-
if (await canLaunchUrl(uri)) {
58-
await launchUrl(uri);
59-
} else {
60-
if (context.mounted) {
61-
Dialogs.show(
62-
context,
63-
child: FlowyDialog(
64-
child: FlowyErrorPage.message(
65-
LocaleKeys
66-
.settings_appearance_themeUpload_urlUploadFailure
67-
.tr()
68-
.replaceAll(
69-
'{}',
70-
uri.toString(),
71-
),
72-
howToFix:
73-
LocaleKeys.errorDialog_howToFixFallback.tr(),
74-
),
75-
),
76-
);
77-
}
78-
}
79-
},
80-
),
81-
),
82-
),
34+
const ThemeUploadLearnMoreButton(),
35+
ThemeUploadWidget.elementSpacer,
8336
const Divider(),
8437
ThemeUploadWidget.elementSpacer,
8538
const ThemeUploadButton(),
39+
ThemeUploadWidget.elementSpacer,
8640
],
8741
),
8842
);

frontend/appflowy_flutter/packages/flowy_infra/lib/colorscheme/default_colorscheme.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,14 @@ class DefaultColorScheme extends FlowyColorScheme {
6464
onPrimary: _white,
6565
hoverBG1: _lightBg2,
6666
hoverBG2: _lightHover,
67+
hoverBG3: _lightShader6,
6768
hoverFG: _lightShader1,
6869
questionBubbleBG: _lightSelector,
69-
hoverBG3: _lightShader6,
7070
progressBarBGColor: _lightTint9,
7171
toolbarColor: _lightShader1,
7272
toggleButtonBGColor: _lightShader5,
7373
calendarWeekendBGColor: const Color(0xFFFBFBFC),
74-
gridRowCountColor: const Color(0xff000000),
74+
gridRowCountColor: _lightShader1,
7575
);
7676

7777
const DefaultColorScheme.dark()
@@ -122,7 +122,7 @@ class DefaultColorScheme extends FlowyColorScheme {
122122
progressBarBGColor: _darkShader3,
123123
toolbarColor: _darkInput,
124124
toggleButtonBGColor: _darkShader1,
125-
calendarWeekendBGColor: const Color(0xff121212),
126-
gridRowCountColor: _darkMain1,
125+
calendarWeekendBGColor: _darkShader1,
126+
gridRowCountColor: _darkShader5,
127127
);
128128
}

frontend/appflowy_flutter/packages/flowy_infra/lib/plugins/bloc/dynamic_plugin_bloc.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ class DynamicPluginBloc extends Bloc<DynamicPluginEvent, DynamicPluginState> {
3737
return;
3838
}
3939
await FlowyPluginService.instance.addPlugin(plugin);
40-
} on PluginCompilationException {
41-
return emit(const DynamicPluginState.compilationFailure());
40+
} on PluginCompilationException catch (exception) {
41+
return emit(DynamicPluginState.compilationFailure(
42+
errorMessage: exception.message));
4243
}
4344

4445
emit(const DynamicPluginState.compilationSuccess());

frontend/appflowy_flutter/packages/flowy_infra/lib/plugins/bloc/dynamic_plugin_state.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ class DynamicPluginState with _$DynamicPluginState {
1111
required Iterable<FlowyDynamicPlugin> plugins,
1212
}) = Ready;
1313
const factory DynamicPluginState.processing() = _Processing;
14-
const factory DynamicPluginState.compilationFailure() = _CompilationFailure;
14+
const factory DynamicPluginState.compilationFailure(
15+
{required String errorMessage}) = _CompilationFailure;
1516
const factory DynamicPluginState.deletionFailure({
1617
required String path,
1718
}) = _DeletionFailure;

frontend/appflowy_flutter/packages/flowy_infra/lib/plugins/service/models/flowy_dynamic_plugin.dart

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,21 @@ class FlowyDynamicPlugin {
7474
/// compilation error will be thrown during the construction of this object.
7575
Future<Directory> encode() async {
7676
final fs = MemoryFileSystem();
77-
final result = fs.directory(_fsPluginName)..createSync();
77+
final directory = fs.directory(_fsPluginName)..createSync();
7878

79-
final lightPath = p.join(_fsPluginName, '$name.$lightExtension');
80-
result.childFile(lightPath).createSync();
81-
result
82-
.childFile(lightPath)
79+
final lightThemeFileName = '$name.$lightExtension';
80+
directory.childFile(lightThemeFileName).createSync();
81+
directory
82+
.childFile(lightThemeFileName)
8383
.writeAsStringSync(jsonEncode(theme!.lightTheme.toJson()));
8484

85-
final darkPath = p.join(_fsPluginName, '$name.$darkExtension');
86-
result.childFile(darkPath).createSync();
87-
result
88-
.childFile(p.join(_fsPluginName, '$name.$darkExtension'))
85+
final darkThemeFileName = '$name.$darkExtension';
86+
directory.childFile(darkThemeFileName).createSync();
87+
directory
88+
.childFile(darkThemeFileName)
8989
.writeAsStringSync(jsonEncode(theme!.darkTheme.toJson()));
9090

91-
return result;
91+
return directory;
9292
}
9393

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

122+
late final FlowyColorScheme lightTheme;
123+
late final FlowyColorScheme darkTheme;
124+
125+
try {
126+
lightTheme = FlowyColorScheme.fromJson(
127+
await jsonDecode(await light.readAsString()));
128+
} catch (e) {
129+
throw PluginCompilationException(
130+
'The light theme json file is not valid.',
131+
);
132+
}
133+
134+
try {
135+
darkTheme = FlowyColorScheme.fromJson(
136+
await jsonDecode(await dark.readAsString()));
137+
} catch (e) {
138+
throw PluginCompilationException(
139+
'The dark theme json file is not valid.',
140+
);
141+
}
142+
122143
final theme = AppTheme(
123144
themeName: name,
124145
builtIn: false,
125-
lightTheme:
126-
FlowyColorScheme.fromJson(jsonDecode(await light.readAsString())),
127-
darkTheme:
128-
FlowyColorScheme.fromJson(jsonDecode(await dark.readAsString())),
146+
lightTheme: lightTheme,
147+
darkTheme: darkTheme,
129148
);
130149

131150
return FlowyDynamicPlugin._(

0 commit comments

Comments
 (0)