startup.dart 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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/prelude.dart';
  12. final getIt = GetIt.instance;
  13. abstract class EntryPoint {
  14. Widget create(LaunchConfiguration config);
  15. }
  16. class FlowyRunnerContext {
  17. final Directory applicationDataDirectory;
  18. FlowyRunnerContext({required this.applicationDataDirectory});
  19. }
  20. Future<void> runAppFlowy() async {
  21. await FlowyRunner.run(
  22. FlowyApp(),
  23. integrationMode(),
  24. );
  25. }
  26. class FlowyRunner {
  27. static Future<FlowyRunnerContext> run(
  28. EntryPoint f,
  29. IntegrationMode mode, {
  30. LaunchConfiguration config = const LaunchConfiguration(
  31. autoRegistrationSupported: false,
  32. ),
  33. }) async {
  34. // Clear all the states in case of rebuilding.
  35. await getIt.reset();
  36. // Specify the env
  37. initGetIt(getIt, mode, f, config);
  38. final applicationDataDirectory =
  39. await getIt<ApplicationDataStorage>().getPath().then(
  40. (value) => Directory(value),
  41. );
  42. // add task
  43. final launcher = getIt<AppLauncher>();
  44. launcher.addTasks(
  45. [
  46. // this task should be first task, for handling platform errors.
  47. // don't catch errors in test mode
  48. if (!mode.isUnitTest) const PlatformErrorCatcherTask(),
  49. // localization
  50. const InitLocalizationTask(),
  51. // init the app window
  52. const InitAppWindowTask(),
  53. // Init Rust SDK
  54. InitRustSDKTask(directory: applicationDataDirectory),
  55. // Load Plugins, like document, grid ...
  56. const PluginLoadTask(),
  57. // init the app widget
  58. // ignore in test mode
  59. if (!mode.isUnitTest) ...[
  60. const HotKeyTask(),
  61. InitSupabaseTask(),
  62. const InitAppWidgetTask(),
  63. const InitPlatformServiceTask()
  64. ],
  65. ],
  66. );
  67. await launcher.launch(); // execute the tasks
  68. return FlowyRunnerContext(
  69. applicationDataDirectory: applicationDataDirectory,
  70. );
  71. }
  72. }
  73. Future<void> initGetIt(
  74. GetIt getIt,
  75. IntegrationMode mode,
  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. mode,
  88. config,
  89. ),
  90. ),
  91. );
  92. getIt.registerSingleton<PluginSandbox>(PluginSandbox());
  93. await DependencyResolver.resolve(getIt, mode);
  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. unitTest,
  134. integrationTest;
  135. // test mode
  136. bool get isTest => isUnitTest || isIntegrationTest;
  137. bool get isUnitTest => this == IntegrationMode.unitTest;
  138. bool get isIntegrationTest => this == IntegrationMode.integrationTest;
  139. // release mode
  140. bool get isRelease => this == IntegrationMode.release;
  141. // develop mode
  142. bool get isDevelop => this == IntegrationMode.develop;
  143. }
  144. IntegrationMode integrationMode() {
  145. if (Platform.environment.containsKey('FLUTTER_TEST')) {
  146. return IntegrationMode.unitTest;
  147. }
  148. if (kReleaseMode) {
  149. return IntegrationMode.release;
  150. }
  151. return IntegrationMode.develop;
  152. }