startup.dart 4.3 KB

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