-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] Dynamically Load Themes in AppFlowy #2670
Conversation
71eaddf
to
65ae1de
Compare
class ColorConverter implements JsonConverter<Color, String> { | ||
const ColorConverter(); | ||
|
||
static const Color fallback = Colors.transparent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the FlowyColorScheme
API changes. The parser will provide transparent
as the default value.
Another way to fail silently is to pass over dynamic themes that can't be parsed. I.e., they won't be included if the app is updated since the theme is invalid. I thought this would be the best way to fail silently.
/// This class can be modified to support loading node widget builders and other | ||
/// plugins that are dynamically loaded at runtime for the editor. For now, | ||
/// it only supports loading app themes. | ||
class FlowyPlugin { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about FlowyDynamicPlugin?
Note: after adding |
3496f08
to
3a3dbd3
Compare
55ffcf1
to
5e379fd
Compare
ede733f
to
7e88ee7
Compare
Codecov Report
@@ Coverage Diff @@
## main #2670 +/- ##
==========================================
- Coverage 67.28% 66.77% -0.52%
==========================================
Files 409 414 +5
Lines 19502 19664 +162
==========================================
+ Hits 13122 13130 +8
- Misses 6380 6534 +154
Flags with carried forward coverage won't be shown. Click here to find out more.
|
...er/lib/workspace/presentation/settings/widgets/theme_upload/theme_confirm_delete_dialog.dart
Outdated
Show resolved
Hide resolved
frontend/appflowy_flutter/packages/flowy_infra/lib/plugins/service/models/exceptions.dart
Outdated
Show resolved
Hide resolved
frontend/appflowy_flutter/packages/flowy_infra/lib/plugins/service/models/exceptions.dart
Outdated
Show resolved
Hide resolved
...d/appflowy_flutter/packages/flowy_infra/lib/plugins/service/models/flowy_dynamic_plugin.dart
Outdated
Show resolved
Hide resolved
frontend/appflowy_flutter/packages/flowy_infra/lib/plugins/service/plugin_service.dart
Outdated
Show resolved
Hide resolved
Working on testing some of the plugin infrastructure but |
|
||
import 'theme_upload_view.dart'; | ||
|
||
class ThemeUploadDecoration extends StatelessWidget { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better if we moved this widget to flowy_infra_ui and made it a configurable widget? Then it could be used for theme upload and file upload in the database.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will hold off on this because I'd like to keep all of the theme upload widgets together. Some of the theme upload widgets use LocaleKeys which requires AppFlowy.
frontend/appflowy_flutter/packages/flowy_infra/lib/plugins/bloc/dynamic_plugin_bloc.dart
Show resolved
Hide resolved
frontend/appflowy_flutter/packages/flowy_infra/lib/plugins/service/location_service.dart
Outdated
Show resolved
Hide resolved
Can we aim to release the MVP by the end of next week? |
Sure 👍 |
75099d4
to
0b46df2
Compare
42736eb
to
01892ab
Compare
AppFlowy.2023-06-29.12-18-23.mp4 |
final light = src | ||
.listSync() | ||
.where((event) => | ||
event is File && p.basename(event.path).contains(lightExtension)) | ||
.first as File; | ||
|
||
final dark = src | ||
.listSync() | ||
.where((event) => | ||
event is File && p.basename(event.path).contains(darkExtension)) | ||
.first as File; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm looking at this and I can't help but think if there is a better way to do it.
The only way I could think of introduced ~15 more lines of code though, not sure it's worth it.
~25 lines of code version
final srcAsList = src.listSync();
File? light;
File? dark;
for (int i = 0; i < srcAsList.length; i++) {
if (light != null && dark != null) {
break;
}
final event = srcAsList[i];
if (event is File) {
if (p.basename(event.path).contains(lightExtension)) {
light = event;
} else if (p.basename(event.path).contains(darkExtension)) {
dark = event;
}
}
}
if (light == null || dark == null) {
throw PluginCompilationException(
'The theme plugin does not contain both a light and dark version: `theme.light.json` and `theme.dark.json`.',
);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least this way, we're only listing the directory once. This is a good review comment. Let me try to expand on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha @Xazin, if we're code golfing it then you can try to beat this :)
final files = src.listSync().whereType<File>().toList();
File? light, dark;
for (int i = 0; i < files.length || (light == null && dark == null); ++i) {
final file = files[i];
if (p.basename(file.path).contains(lightExtension)) {
light = file;
} else if (p.basename(file.path).contains(darkExtension)) {
dark = file;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either way we still get the benefit of only listing the directory once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that is indeed better. Semantically it's the same, but more readable.
Feature Preview
dynamic_theme_demo.mp4
Loads themes from a JSON file at runtime.
TODO
InvalidType
build_runner errors.FlowyColorScheme
API changes and the old theme is incompatible with the new API.path_provider
getApplicationDocumentsDirectory()
).AppFlowy.2023-06-06.20-56-36.mp4
AppFlowy.2023-06-09.12-05-53.mp4
Better prompt messagesBetter error messagesdevelop
intomain
Issues #1070. It does not fix but makes it easier to experiment with new themes.
PR Checklist