startup.dart 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import 'dart:io';
  2. import 'package:appflowy_backend/appflowy_backend.dart';
  3. import 'package:flutter/foundation.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:get_it/get_it.dart';
  6. import '../workspace/application/settings/settings_location_cubit.dart';
  7. import 'deps_resolver.dart';
  8. import 'launch_configuration.dart';
  9. import 'plugin/plugin.dart';
  10. import 'tasks/prelude.dart';
  11. // [[diagram: flowy startup flow]]
  12. // ┌──────────┐
  13. // │ FlowyApp │
  14. // └──────────┘
  15. // │ impl
  16. // ▼
  17. // ┌────────┐ 1.run ┌──────────┐
  18. // │ System │───┬───▶│EntryPoint│
  19. // └────────┘ │ └──────────┘ ┌─────────────────┐
  20. // │ ┌──▶ │ RustSDKInitTask │
  21. // │ ┌───────────┐ │ └─────────────────┘
  22. // └──▶ │AppLauncher│───┤
  23. // 2.launch └───────────┘ │ ┌─────────────┐ ┌──────────────────┐ ┌───────────────┐
  24. // └───▶│AppWidgetTask│────────▶│ApplicationWidget │─────▶│ SplashScreen │
  25. // └─────────────┘ └──────────────────┘ └───────────────┘
  26. //
  27. // 3.build MaterialApp
  28. final getIt = GetIt.instance;
  29. abstract class EntryPoint {
  30. Widget create(LaunchConfiguration config);
  31. }
  32. class FlowyRunner {
  33. static Future<void> run(
  34. EntryPoint f, {
  35. LaunchConfiguration config = const LaunchConfiguration(
  36. autoRegistrationSupported: false,
  37. ),
  38. }) async {
  39. // Clear all the states in case of rebuilding.
  40. await getIt.reset();
  41. // Specify the env
  42. final env = integrationEnv();
  43. initGetIt(getIt, env, f, config);
  44. final directory = getIt<SettingsLocationCubit>()
  45. .fetchLocation()
  46. .then((value) => Directory(value));
  47. // add task
  48. final launcher = getIt<AppLauncher>();
  49. launcher.addTasks(
  50. [
  51. // handle platform errors.
  52. const PlatformErrorCatcherTask(),
  53. // localization
  54. const InitLocalizationTask(),
  55. // init the app window
  56. const InitAppWindowTask(),
  57. // Init Rust SDK
  58. InitRustSDKTask(directory: directory),
  59. // Load Plugins, like document, grid ...
  60. const PluginLoadTask(),
  61. // init the app widget
  62. // ignore in test mode
  63. if (!env.isTest()) ...[
  64. const HotKeyTask(),
  65. const InitAppWidgetTask(),
  66. const InitPlatformServiceTask()
  67. ],
  68. ],
  69. );
  70. await launcher.launch(); // execute the tasks
  71. }
  72. }
  73. Future<void> initGetIt(
  74. GetIt getIt,
  75. IntegrationMode env,
  76. EntryPoint f,
  77. LaunchConfiguration config,
  78. ) async {
  79. getIt.registerFactory<EntryPoint>(() => f);
  80. getIt.registerLazySingleton<FlowySDK>(() {
  81. return FlowySDK();
  82. });
  83. getIt.registerLazySingleton<AppLauncher>(
  84. () => AppLauncher(
  85. context: LaunchContext(
  86. getIt,
  87. env,
  88. config,
  89. ),
  90. ),
  91. );
  92. getIt.registerSingleton<PluginSandbox>(PluginSandbox());
  93. await DependencyResolver.resolve(getIt);
  94. }
  95. class LaunchContext {
  96. GetIt getIt;
  97. IntegrationMode env;
  98. LaunchConfiguration config;
  99. LaunchContext(this.getIt, this.env, this.config);
  100. }
  101. enum LaunchTaskType {
  102. dataProcessing,
  103. appLauncher,
  104. }
  105. /// The interface of an app launch task, which will trigger
  106. /// some nonresident indispensable task in app launching task.
  107. abstract class LaunchTask {
  108. const LaunchTask();
  109. LaunchTaskType get type => LaunchTaskType.dataProcessing;
  110. Future<void> initialize(LaunchContext context);
  111. }
  112. class AppLauncher {
  113. AppLauncher({
  114. required this.context,
  115. });
  116. final LaunchContext context;
  117. final List<LaunchTask> tasks = [];
  118. void addTask(LaunchTask task) {
  119. tasks.add(task);
  120. }
  121. void addTasks(Iterable<LaunchTask> tasks) {
  122. this.tasks.addAll(tasks);
  123. }
  124. Future<void> launch() async {
  125. for (final task in tasks) {
  126. await task.initialize(context);
  127. }
  128. }
  129. }
  130. enum IntegrationMode {
  131. develop,
  132. release,
  133. test,
  134. }
  135. extension IntegrationEnvExt on IntegrationMode {
  136. bool isTest() {
  137. return this == IntegrationMode.test;
  138. }
  139. }
  140. IntegrationMode integrationEnv() {
  141. if (Platform.environment.containsKey('FLUTTER_TEST')) {
  142. return IntegrationMode.test;
  143. }
  144. if (kReleaseMode) {
  145. return IntegrationMode.release;
  146. }
  147. return IntegrationMode.develop;
  148. }