mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: add app setting test (#1361)
This commit is contained in:
parent
67e4a759c7
commit
18185cc90c
@ -19,9 +19,9 @@ class InitAppWidgetTask extends LaunchTask {
|
|||||||
Future<void> initialize(LaunchContext context) async {
|
Future<void> initialize(LaunchContext context) async {
|
||||||
final widget = context.getIt<EntryPoint>().create();
|
final widget = context.getIt<EntryPoint>().create();
|
||||||
final setting = await SettingsFFIService().getAppearanceSetting();
|
final setting = await SettingsFFIService().getAppearanceSetting();
|
||||||
final settingModel = AppearanceSetting(setting);
|
final appearanceSetting = AppearanceSetting(setting);
|
||||||
final app = ApplicationWidget(
|
final app = ApplicationWidget(
|
||||||
settingModel: settingModel,
|
appearanceSetting: appearanceSetting,
|
||||||
child: widget,
|
child: widget,
|
||||||
);
|
);
|
||||||
Bloc.observer = ApplicationBlocObserver();
|
Bloc.observer = ApplicationBlocObserver();
|
||||||
@ -61,23 +61,23 @@ class InitAppWidgetTask extends LaunchTask {
|
|||||||
|
|
||||||
class ApplicationWidget extends StatelessWidget {
|
class ApplicationWidget extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final AppearanceSetting settingModel;
|
final AppearanceSetting appearanceSetting;
|
||||||
|
|
||||||
const ApplicationWidget({
|
const ApplicationWidget({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.child,
|
required this.child,
|
||||||
required this.settingModel,
|
required this.appearanceSetting,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
value: settingModel,
|
value: appearanceSetting,
|
||||||
builder: (context, _) {
|
builder: (context, _) {
|
||||||
const ratio = 1.73;
|
const ratio = 1.73;
|
||||||
const minWidth = 600.0;
|
const minWidth = 600.0;
|
||||||
setWindowMinSize(const Size(minWidth, minWidth / ratio));
|
setWindowMinSize(const Size(minWidth, minWidth / ratio));
|
||||||
settingModel.readLocaleWhenAppLaunch(context);
|
appearanceSetting.readLocaleWhenAppLaunch(context);
|
||||||
AppTheme theme = context.select<AppearanceSetting, AppTheme>(
|
AppTheme theme = context.select<AppearanceSetting, AppTheme>(
|
||||||
(value) => value.theme,
|
(value) => value.theme,
|
||||||
);
|
);
|
||||||
|
@ -13,7 +13,6 @@ class AppearanceSetting extends ChangeNotifier with EquatableMixin {
|
|||||||
final AppearanceSettingsPB _setting;
|
final AppearanceSettingsPB _setting;
|
||||||
AppTheme _theme;
|
AppTheme _theme;
|
||||||
Locale _locale;
|
Locale _locale;
|
||||||
Timer? _debounceSaveOperation;
|
|
||||||
|
|
||||||
AppearanceSetting(AppearanceSettingsPB setting)
|
AppearanceSetting(AppearanceSettingsPB setting)
|
||||||
: _setting = setting,
|
: _setting = setting,
|
||||||
@ -83,10 +82,17 @@ class AppearanceSetting extends ChangeNotifier with EquatableMixin {
|
|||||||
} else {
|
} else {
|
||||||
_setting.settingKeyValue[key] = value;
|
_setting.settingKeyValue[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
_saveAppearSetting();
|
|
||||||
notifyListeners();
|
|
||||||
}
|
}
|
||||||
|
_saveAppearSetting();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
String? getValue(String key) {
|
||||||
|
if (key.isEmpty) {
|
||||||
|
Log.warn("The key should not be empty");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return _setting.settingKeyValue[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the application launch.
|
/// Called when the application launch.
|
||||||
@ -103,15 +109,12 @@ class AppearanceSetting extends ChangeNotifier with EquatableMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _saveAppearSetting() async {
|
Future<void> _saveAppearSetting() async {
|
||||||
_debounceSaveOperation?.cancel();
|
SettingsFFIService().setAppearanceSetting(_setting).then((result) {
|
||||||
_debounceSaveOperation = Timer(
|
result.fold(
|
||||||
const Duration(seconds: 1),
|
(l) => null,
|
||||||
() {
|
(error) => Log.error(error),
|
||||||
SettingsFFIService().setAppearanceSetting(_setting).then((result) {
|
);
|
||||||
result.fold((l) => null, (error) => Log.error(error));
|
});
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
import 'package:app_flowy/user/application/user_settings_service.dart';
|
||||||
|
import 'package:app_flowy/workspace/application/appearance.dart';
|
||||||
|
import 'package:flowy_infra/theme.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import '../../util.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// ignore: unused_local_variable
|
||||||
|
late AppFlowyUnitTest context;
|
||||||
|
setUpAll(() async {
|
||||||
|
context = await AppFlowyUnitTest.ensureInitialized();
|
||||||
|
});
|
||||||
|
|
||||||
|
group('$AppearanceSetting', () {
|
||||||
|
late AppearanceSetting appearanceSetting;
|
||||||
|
setUp(() async {
|
||||||
|
final setting = await SettingsFFIService().getAppearanceSetting();
|
||||||
|
appearanceSetting = AppearanceSetting(setting);
|
||||||
|
await blocResponseFuture();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('default theme', () {
|
||||||
|
expect(appearanceSetting.theme.ty, ThemeType.light);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('save key/value', () async {
|
||||||
|
appearanceSetting.setKeyValue("123", "456");
|
||||||
|
});
|
||||||
|
|
||||||
|
test('read key/value', () {
|
||||||
|
expect(appearanceSetting.getValue("123"), "456");
|
||||||
|
});
|
||||||
|
|
||||||
|
test('remove key/value', () {
|
||||||
|
appearanceSetting.setKeyValue("123", null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('read key/value', () {
|
||||||
|
expect(appearanceSetting.getValue("123"), null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -12,38 +12,42 @@ void main() {
|
|||||||
late AppFlowyUnitTest test;
|
late AppFlowyUnitTest test;
|
||||||
late AppPB app;
|
late AppPB app;
|
||||||
late AppBloc appBloc;
|
late AppBloc appBloc;
|
||||||
late List<ViewPB> allViews;
|
late TrashBloc trashBloc;
|
||||||
setUpAll(() async {
|
setUpAll(() async {
|
||||||
test = await AppFlowyUnitTest.ensureInitialized();
|
test = await AppFlowyUnitTest.ensureInitialized();
|
||||||
|
|
||||||
/// Create a new app with three documents
|
|
||||||
app = await test.createTestApp();
|
|
||||||
appBloc = AppBloc(app: app)
|
|
||||||
..add(const AppEvent.initial())
|
|
||||||
..add(AppEvent.createView(
|
|
||||||
"Document 1",
|
|
||||||
DocumentPluginBuilder(),
|
|
||||||
))
|
|
||||||
..add(AppEvent.createView(
|
|
||||||
"Document 2",
|
|
||||||
DocumentPluginBuilder(),
|
|
||||||
))
|
|
||||||
..add(
|
|
||||||
AppEvent.createView(
|
|
||||||
"Document 3",
|
|
||||||
DocumentPluginBuilder(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
await blocResponseFuture(millisecond: 200);
|
|
||||||
allViews = [...appBloc.state.app.belongings.items];
|
|
||||||
assert(allViews.length == 3);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 1. Create three views
|
||||||
|
// 2. Delete a view and check the state
|
||||||
|
// 3. Delete all views and check the state
|
||||||
|
// 4. Put back a view
|
||||||
|
// 5. Put back all views
|
||||||
group('$TrashBloc', () {
|
group('$TrashBloc', () {
|
||||||
late TrashBloc trashBloc;
|
|
||||||
late ViewPB deletedView;
|
late ViewPB deletedView;
|
||||||
|
late List<ViewPB> allViews;
|
||||||
setUpAll(() {});
|
setUpAll(() async {
|
||||||
|
/// Create a new app with three documents
|
||||||
|
app = await test.createTestApp();
|
||||||
|
appBloc = AppBloc(app: app)
|
||||||
|
..add(const AppEvent.initial())
|
||||||
|
..add(AppEvent.createView(
|
||||||
|
"Document 1",
|
||||||
|
DocumentPluginBuilder(),
|
||||||
|
))
|
||||||
|
..add(AppEvent.createView(
|
||||||
|
"Document 2",
|
||||||
|
DocumentPluginBuilder(),
|
||||||
|
))
|
||||||
|
..add(
|
||||||
|
AppEvent.createView(
|
||||||
|
"Document 3",
|
||||||
|
DocumentPluginBuilder(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await blocResponseFuture(millisecond: 200);
|
||||||
|
allViews = [...appBloc.state.app.belongings.items];
|
||||||
|
assert(allViews.length == 3);
|
||||||
|
});
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
trashBloc = TrashBloc()..add(const TrashEvent.initial());
|
trashBloc = TrashBloc()..add(const TrashEvent.initial());
|
||||||
@ -51,7 +55,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
blocTest<TrashBloc, TrashState>(
|
blocTest<TrashBloc, TrashState>(
|
||||||
"delete view",
|
"delete a view",
|
||||||
build: () => trashBloc,
|
build: () => trashBloc,
|
||||||
act: (bloc) async {
|
act: (bloc) async {
|
||||||
deletedView = appBloc.state.app.belongings.items[0];
|
deletedView = appBloc.state.app.belongings.items[0];
|
||||||
@ -82,7 +86,7 @@ void main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
blocTest<TrashBloc, TrashState>(
|
blocTest<TrashBloc, TrashState>(
|
||||||
"put back",
|
"put back a trash",
|
||||||
build: () => trashBloc,
|
build: () => trashBloc,
|
||||||
act: (bloc) async {
|
act: (bloc) async {
|
||||||
bloc.add(TrashEvent.putback(allViews[0].id));
|
bloc.add(TrashEvent.putback(allViews[0].id));
|
||||||
@ -94,7 +98,7 @@ void main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
blocTest<TrashBloc, TrashState>(
|
blocTest<TrashBloc, TrashState>(
|
||||||
"put back all",
|
"put back all trash",
|
||||||
build: () => trashBloc,
|
build: () => trashBloc,
|
||||||
act: (bloc) async {
|
act: (bloc) async {
|
||||||
bloc.add(const TrashEvent.restoreAll());
|
bloc.add(const TrashEvent.restoreAll());
|
||||||
@ -107,4 +111,69 @@ void main() {
|
|||||||
);
|
);
|
||||||
//
|
//
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 1. Create three views
|
||||||
|
// 2. Delete a trash permanently and check the state
|
||||||
|
// 3. Delete all views permanently
|
||||||
|
group('$TrashBloc', () {
|
||||||
|
setUpAll(() async {
|
||||||
|
/// Create a new app with three documents
|
||||||
|
app = await test.createTestApp();
|
||||||
|
appBloc = AppBloc(app: app)
|
||||||
|
..add(const AppEvent.initial())
|
||||||
|
..add(AppEvent.createView(
|
||||||
|
"Document 1",
|
||||||
|
DocumentPluginBuilder(),
|
||||||
|
))
|
||||||
|
..add(AppEvent.createView(
|
||||||
|
"Document 2",
|
||||||
|
DocumentPluginBuilder(),
|
||||||
|
))
|
||||||
|
..add(
|
||||||
|
AppEvent.createView(
|
||||||
|
"Document 3",
|
||||||
|
DocumentPluginBuilder(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await blocResponseFuture(millisecond: 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
trashBloc = TrashBloc()..add(const TrashEvent.initial());
|
||||||
|
await blocResponseFuture();
|
||||||
|
});
|
||||||
|
|
||||||
|
blocTest<TrashBloc, TrashState>(
|
||||||
|
"delete a view permanently",
|
||||||
|
build: () => trashBloc,
|
||||||
|
act: (bloc) async {
|
||||||
|
final view = appBloc.state.app.belongings.items[0];
|
||||||
|
appBloc.add(AppEvent.deleteView(view.id));
|
||||||
|
await blocResponseFuture();
|
||||||
|
|
||||||
|
trashBloc.add(TrashEvent.delete(trashBloc.state.objects[0]));
|
||||||
|
},
|
||||||
|
wait: blocResponseDuration(),
|
||||||
|
verify: (bloc) {
|
||||||
|
assert(appBloc.state.app.belongings.items.length == 2);
|
||||||
|
assert(bloc.state.objects.isEmpty);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
blocTest<TrashBloc, TrashState>(
|
||||||
|
"delete all view permanently",
|
||||||
|
build: () => trashBloc,
|
||||||
|
act: (bloc) async {
|
||||||
|
for (final view in appBloc.state.app.belongings.items) {
|
||||||
|
appBloc.add(AppEvent.deleteView(view.id));
|
||||||
|
}
|
||||||
|
await blocResponseFuture();
|
||||||
|
trashBloc.add(const TrashEvent.deleteAll());
|
||||||
|
},
|
||||||
|
wait: blocResponseDuration(),
|
||||||
|
verify: (bloc) {
|
||||||
|
assert(appBloc.state.app.belongings.items.isEmpty);
|
||||||
|
assert(bloc.state.objects.isEmpty);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user