AppFlowy/frontend/app_flowy/lib/startup/startup.dart
Lucas.Xu 5d7008edd7
feat: Customize the storage folder path (#1538)
* feat: support customize folder path

* feat: add l10n and optimize the logic

* chore: code refactor

* feat: add file read/write permission for macOS

* fix: add toast for restoring path

* feat: fetch apps and show them

* feat: fetch apps and show them

* feat: implement select document logic

* feat: l10n and add select item callback

* feat: add space between tile

* chore: move file exporter to settings

* chore: update UI

* feat: support customizing folder when launching the app

* feat: auto register after customizing folder

* feat: l10n

* feat: l10n

* chore: reinitialize flowy sdk when calling init_sdk

* chore: remove flowysdk const keyword to make sure it can be rebuild

* chore: clear kv values when user logout

* chore: replace current workspace id key in kv.db

* feat: add config.name as a part of seesion_cache_key

* feat: support open folder when launching

* chore: fix some bugs

* chore: dart fix & flutter analyze

* chore: wrap 'sign up with ramdom user' as interface

* feat: dismiss settings view after changing the folder

* fix: read kv value after initializaing with new path

* chore: remove user_id prefix from current workspace key

* fix: move open latest view action to bloc

* test: add test utils for integration tests

* chore: move integration_test to its parent directory

* test: add integration_test ci

* test: switch to B from A, then switch to A again

* chore: fix warings and format code and fix tests

* chore: remove comment out codes

* chore: rename some properties name and optimize the logic

* chore: abstract logic of settings file exporter widget to cubit

* chore: abstract location customizer view from file system view

* chore: abstract settings page index to enum type

* chore: remove the redundant underscore

* test: fix integration test error

* chore: enable integration test for windows and ubuntu

* feat: abstract file picker as service and mock it under integration test

* chore: fix bloc test

Co-authored-by: nathan <nathan@appflowy.io>
2022-12-20 11:14:42 +08:00

152 lines
4.4 KiB
Dart

import 'dart:io';
import 'package:flowy_sdk/flowy_sdk.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import '../workspace/application/settings/settings_location_cubit.dart';
import 'deps_resolver.dart';
import 'launch_configuration.dart';
import 'plugin/plugin.dart';
import 'tasks/prelude.dart';
// [[diagram: flowy startup flow]]
// ┌──────────┐
// │ FlowyApp │
// └──────────┘
// │ impl
// ▼
// ┌────────┐ 1.run ┌──────────┐
// │ System │───┬───▶│EntryPoint│
// └────────┘ │ └──────────┘ ┌─────────────────┐
// │ ┌──▶ │ RustSDKInitTask │
// │ ┌───────────┐ │ └─────────────────┘
// └──▶ │AppLauncher│───┤
// 2.launch └───────────┘ │ ┌─────────────┐ ┌──────────────────┐ ┌───────────────┐
// └───▶│AppWidgetTask│────────▶│ApplicationWidget │─────▶│ SplashScreen │
// └─────────────┘ └──────────────────┘ └───────────────┘
//
// 3.build MeterialApp
final getIt = GetIt.instance;
abstract class EntryPoint {
Widget create(LaunchConfiguration config);
}
class FlowyRunner {
static Future<void> run(
EntryPoint f, {
LaunchConfiguration config =
const LaunchConfiguration(autoRegistrationSupported: false),
}) async {
// Clear all the states in case of rebuilding.
await getIt.reset();
// Specify the env
final env = integrationEnv();
initGetIt(getIt, env, f, config);
final directory = getIt<SettingsLocationCubit>()
.fetchLocation()
.then((value) => Directory(value));
// add task
getIt<AppLauncher>().addTask(InitRustSDKTask(directory: directory));
getIt<AppLauncher>().addTask(PluginLoadTask());
if (!env.isTest()) {
getIt<AppLauncher>().addTask(InitAppWidgetTask());
getIt<AppLauncher>().addTask(InitPlatformServiceTask());
}
// execute the tasks
await getIt<AppLauncher>().launch();
}
}
Future<void> initGetIt(
GetIt getIt,
IntegrationMode env,
EntryPoint f,
LaunchConfiguration config,
) async {
getIt.registerFactory<EntryPoint>(() => f);
getIt.registerLazySingleton<FlowySDK>(() {
return FlowySDK();
});
getIt.registerLazySingleton<AppLauncher>(
() => AppLauncher(
context: LaunchContext(
getIt,
env,
config,
),
),
);
getIt.registerSingleton<PluginSandbox>(PluginSandbox());
await DependencyResolver.resolve(getIt);
}
class LaunchContext {
GetIt getIt;
IntegrationMode env;
LaunchConfiguration config;
LaunchContext(this.getIt, this.env, this.config);
}
enum LaunchTaskType {
dataProcessing,
appLauncher,
}
/// The interface of an app launch task, which will trigger
/// some nonresident indispensable task in app launching task.
abstract class LaunchTask {
LaunchTaskType get type => LaunchTaskType.dataProcessing;
Future<void> initialize(LaunchContext context);
}
class AppLauncher {
List<LaunchTask> tasks;
final LaunchContext context;
AppLauncher({required this.context}) : tasks = List.from([]);
void addTask(LaunchTask task) {
tasks.add(task);
}
Future<void> launch() async {
for (var task in tasks) {
await task.initialize(context);
}
}
}
enum IntegrationMode {
develop,
release,
test,
}
extension IntegrationEnvExt on IntegrationMode {
bool isTest() {
return this == IntegrationMode.test;
}
}
IntegrationMode integrationEnv() {
if (Platform.environment.containsKey('FLUTTER_TEST')) {
return IntegrationMode.test;
}
if (kReleaseMode) {
return IntegrationMode.release;
}
return IntegrationMode.develop;
}