Pārlūkot izejas kodu

monitor network state

appflowy 3 gadi atpakaļ
vecāks
revīzija
31efacb274
27 mainītis faili ar 570 papildinājumiem un 50 dzēšanām
  1. 4 1
      frontend/app_flowy/lib/startup/startup.dart
  2. 0 0
      frontend/app_flowy/lib/startup/tasks/application_widget.dart
  3. 14 0
      frontend/app_flowy/lib/startup/tasks/init_platform_service.dart
  4. 1 1
      frontend/app_flowy/lib/startup/tasks/init_sdk.dart
  5. 2 2
      frontend/app_flowy/lib/startup/tasks/prelude.dart
  6. 4 0
      frontend/app_flowy/lib/user/infrastructure/deps_resolver.dart
  7. 55 0
      frontend/app_flowy/lib/user/infrastructure/network_monitor.dart
  8. 1 1
      frontend/app_flowy/lib/workspace/presentation/widgets/dialogs.dart
  9. 2 0
      frontend/app_flowy/macos/Flutter/GeneratedPluginRegistrant.swift
  10. 17 0
      frontend/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart
  11. 2 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbenum.dart
  12. 2 1
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbjson.dart
  13. 51 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/observable.pb.dart
  14. 19 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/observable.pbenum.dart
  15. 23 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/observable.pbjson.dart
  16. 56 0
      frontend/app_flowy/pubspec.lock
  17. 1 0
      frontend/app_flowy/pubspec.yaml
  18. 10 7
      frontend/rust-lib/flowy-user/src/event.rs
  19. 8 0
      frontend/rust-lib/flowy-user/src/handlers/user_handler.rs
  20. 1 0
      frontend/rust-lib/flowy-user/src/module.rs
  21. 19 1
      frontend/rust-lib/flowy-user/src/notify/observable.rs
  22. 26 20
      frontend/rust-lib/flowy-user/src/protobuf/model/event.rs
  23. 236 16
      frontend/rust-lib/flowy-user/src/protobuf/model/observable.rs
  24. 1 0
      frontend/rust-lib/flowy-user/src/protobuf/proto/event.proto
  25. 9 0
      frontend/rust-lib/flowy-user/src/protobuf/proto/observable.proto
  26. 4 0
      frontend/rust-lib/flowy-user/src/services/user/user_session.rs
  27. 2 0
      shared-lib/flowy-derive/src/derive_cache/derive_cache.rs

+ 4 - 1
frontend/app_flowy/lib/startup/startup.dart

@@ -6,6 +6,8 @@ import 'package:app_flowy/workspace/infrastructure/deps_resolver.dart';
 import 'package:app_flowy/user/infrastructure/deps_resolver.dart';
 import 'package:flowy_sdk/flowy_sdk.dart';
 
+import 'tasks/init_platform_service.dart';
+
 // [[diagram: flowy startup flow]]
 //                   ┌──────────┐
 //                   │ FlowyApp │
@@ -44,8 +46,9 @@ class System {
     resolveDependencies(env);
 
     // add task
-    getIt<AppLauncher>().addTask(RustSDKInitTask());
+    getIt<AppLauncher>().addTask(InitRustSDKTask());
     getIt<AppLauncher>().addTask(AppWidgetTask());
+    getIt<AppLauncher>().addTask(InitPlatformService());
 
     // execute the tasks
     getIt<AppLauncher>().launch();

+ 0 - 0
frontend/app_flowy/lib/startup/tasks/application_task.dart → frontend/app_flowy/lib/startup/tasks/application_widget.dart


+ 14 - 0
frontend/app_flowy/lib/startup/tasks/init_platform_service.dart

@@ -0,0 +1,14 @@
+import 'package:app_flowy/startup/launcher.dart';
+import 'package:app_flowy/user/infrastructure/network_monitor.dart';
+
+import '../startup.dart';
+
+class InitPlatformService extends LaunchTask {
+  @override
+  LaunchTaskType get type => LaunchTaskType.dataProcessing;
+
+  @override
+  Future<void> initialize(LaunchContext context) async {
+    getIt<NetworkMonitor>().start();
+  }
+}

+ 1 - 1
frontend/app_flowy/lib/startup/tasks/sdk_task.dart → frontend/app_flowy/lib/startup/tasks/init_sdk.dart

@@ -5,7 +5,7 @@ import 'package:path_provider/path_provider.dart';
 import 'package:flowy_sdk/flowy_sdk.dart';
 import 'package:flutter/material.dart';
 
-class RustSDKInitTask extends LaunchTask {
+class InitRustSDKTask extends LaunchTask {
   @override
   LaunchTaskType get type => LaunchTaskType.dataProcessing;
 

+ 2 - 2
frontend/app_flowy/lib/startup/tasks/prelude.dart

@@ -1,2 +1,2 @@
-export 'application_task.dart';
-export 'sdk_task.dart';
+export 'application_widget.dart';
+export 'init_sdk.dart';

+ 4 - 0
frontend/app_flowy/lib/user/infrastructure/deps_resolver.dart

@@ -13,6 +13,8 @@ import 'package:app_flowy/workspace/domain/i_user.dart';
 import 'package:app_flowy/workspace/infrastructure/i_user_impl.dart';
 import 'package:get_it/get_it.dart';
 
+import 'network_monitor.dart';
+
 class UserDepsResolver {
   static Future<void> resolve(GetIt getIt) async {
     getIt.registerFactory<AuthRepository>(() => AuthRepository());
@@ -36,5 +38,7 @@ class UserDepsResolver {
         getIt<IUserListener>(param1: user),
       ),
     );
+
+    getIt.registerLazySingleton<NetworkMonitor>(() => NetworkMonitor());
   }
 }

+ 55 - 0
frontend/app_flowy/lib/user/infrastructure/network_monitor.dart

@@ -0,0 +1,55 @@
+import 'dart:async';
+
+import 'package:connectivity_plus/connectivity_plus.dart';
+import 'package:flowy_log/flowy_log.dart';
+import 'package:flowy_sdk/dispatch/dispatch.dart';
+import 'package:flowy_sdk/protobuf/flowy-user/observable.pb.dart';
+import 'package:flutter/services.dart';
+
+class NetworkMonitor {
+  final Connectivity _connectivity = Connectivity();
+  late StreamSubscription<ConnectivityResult> _connectivitySubscription;
+
+  NetworkMonitor() {
+    _connectivitySubscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
+  }
+
+  Future<void> start() async {
+    late ConnectivityResult result;
+    // Platform messages may fail, so we use a try/catch PlatformException.
+    try {
+      result = await _connectivity.checkConnectivity();
+    } on PlatformException catch (e) {
+      Log.error('Couldn\'t check connectivity status. $e');
+      return;
+    }
+    return _updateConnectionStatus(result);
+  }
+
+  void stop() {
+    _connectivitySubscription.cancel();
+  }
+
+  Future<void> _updateConnectionStatus(ConnectivityResult result) async {
+    final networkType = () {
+      switch (result) {
+        case ConnectivityResult.wifi:
+          return NetworkType.Wifi;
+        case ConnectivityResult.ethernet:
+          return NetworkType.Ethernet;
+        case ConnectivityResult.mobile:
+          return NetworkType.Cell;
+        case ConnectivityResult.none:
+          return NetworkType.UnknownNetworkType;
+      }
+    }();
+    Log.info("Network type: $networkType");
+    final state = NetworkState.create()..ty = networkType;
+    UserEventUpdateNetworkType(state).send().then((result) {
+      result.fold(
+        (l) {},
+        (e) => Log.error(e),
+      );
+    });
+  }
+}

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/widgets/dialogs.dart

@@ -7,7 +7,7 @@ import 'package:flowy_infra_ui/widget/buttons/secondary_button.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flutter/material.dart';
 import 'package:provider/provider.dart';
-import 'package:app_flowy/startup/tasks/application_task.dart';
+import 'package:app_flowy/startup/tasks/application_widget.dart';
 import 'package:flowy_infra/size.dart';
 import 'package:flowy_infra_ui/style_widget/text_input.dart';
 import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';

+ 2 - 0
frontend/app_flowy/macos/Flutter/GeneratedPluginRegistrant.swift

@@ -5,6 +5,7 @@
 import FlutterMacOS
 import Foundation
 
+import connectivity_plus_macos
 import flowy_infra_ui
 import flowy_sdk
 import package_info_plus_macos
@@ -13,6 +14,7 @@ import url_launcher_macos
 import window_size
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
+  ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
   FlowyInfraUIPlugin.register(with: registry.registrar(forPlugin: "FlowyInfraUIPlugin"))
   FlowySdkPlugin.register(with: registry.registrar(forPlugin: "FlowySdkPlugin"))
   FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))

+ 17 - 0
frontend/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart

@@ -519,3 +519,20 @@ class UserEventCheckUser {
     }
 }
 
+class UserEventUpdateNetworkType {
+     NetworkState request;
+     UserEventUpdateNetworkType(this.request);
+
+    Future<Either<Unit, UserError>> send() {
+    final request = FFIRequest.create()
+          ..event = UserEvent.UpdateNetworkType.toString()
+          ..payload = requestToBytes(this.request);
+
+    return Dispatch.asyncRequest(request)
+        .then((bytesResult) => bytesResult.fold(
+           (bytes) => left(unit),
+           (errBytes) => right(UserError.fromBuffer(errBytes)),
+        ));
+    }
+}
+

+ 2 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbenum.dart

@@ -17,6 +17,7 @@ class UserEvent extends $pb.ProtobufEnum {
   static const UserEvent UpdateUser = UserEvent._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateUser');
   static const UserEvent GetUserProfile = UserEvent._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetUserProfile');
   static const UserEvent CheckUser = UserEvent._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CheckUser');
+  static const UserEvent UpdateNetworkType = UserEvent._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateNetworkType');
 
   static const $core.List<UserEvent> values = <UserEvent> [
     InitUser,
@@ -26,6 +27,7 @@ class UserEvent extends $pb.ProtobufEnum {
     UpdateUser,
     GetUserProfile,
     CheckUser,
+    UpdateNetworkType,
   ];
 
   static final $core.Map<$core.int, UserEvent> _byValue = $pb.ProtobufEnum.initByValue(values);

+ 2 - 1
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/event.pbjson.dart

@@ -19,8 +19,9 @@ const UserEvent$json = const {
     const {'1': 'UpdateUser', '2': 4},
     const {'1': 'GetUserProfile', '2': 5},
     const {'1': 'CheckUser', '2': 6},
+    const {'1': 'UpdateNetworkType', '2': 10},
   ],
 };
 
 /// Descriptor for `UserEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List userEventDescriptor = $convert.base64Decode('CglVc2VyRXZlbnQSDAoISW5pdFVzZXIQABIKCgZTaWduSW4QARIKCgZTaWduVXAQAhILCgdTaWduT3V0EAMSDgoKVXBkYXRlVXNlchAEEhIKDkdldFVzZXJQcm9maWxlEAUSDQoJQ2hlY2tVc2VyEAY=');
+final $typed_data.Uint8List userEventDescriptor = $convert.base64Decode('CglVc2VyRXZlbnQSDAoISW5pdFVzZXIQABIKCgZTaWduSW4QARIKCgZTaWduVXAQAhILCgdTaWduT3V0EAMSDgoKVXBkYXRlVXNlchAEEhIKDkdldFVzZXJQcm9maWxlEAUSDQoJQ2hlY2tVc2VyEAYSFQoRVXBkYXRlTmV0d29ya1R5cGUQCg==');

+ 51 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/observable.pb.dart

@@ -7,5 +7,56 @@
 
 import 'dart:core' as $core;
 
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'observable.pbenum.dart';
+
 export 'observable.pbenum.dart';
 
+class NetworkState extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'NetworkState', createEmptyInstance: create)
+    ..e<NetworkType>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: NetworkType.UnknownNetworkType, valueOf: NetworkType.valueOf, enumValues: NetworkType.values)
+    ..hasRequiredFields = false
+  ;
+
+  NetworkState._() : super();
+  factory NetworkState({
+    NetworkType? ty,
+  }) {
+    final _result = create();
+    if (ty != null) {
+      _result.ty = ty;
+    }
+    return _result;
+  }
+  factory NetworkState.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory NetworkState.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  NetworkState clone() => NetworkState()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  NetworkState copyWith(void Function(NetworkState) updates) => super.copyWith((message) => updates(message as NetworkState)) as NetworkState; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static NetworkState create() => NetworkState._();
+  NetworkState createEmptyInstance() => create();
+  static $pb.PbList<NetworkState> createRepeated() => $pb.PbList<NetworkState>();
+  @$core.pragma('dart2js:noInline')
+  static NetworkState getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<NetworkState>(create);
+  static NetworkState? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  NetworkType get ty => $_getN(0);
+  @$pb.TagNumber(1)
+  set ty(NetworkType v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasTy() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearTy() => clearField(1);
+}
+

+ 19 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/observable.pbenum.dart

@@ -30,3 +30,22 @@ class UserNotification extends $pb.ProtobufEnum {
   const UserNotification._($core.int v, $core.String n) : super(v, n);
 }
 
+class NetworkType extends $pb.ProtobufEnum {
+  static const NetworkType UnknownNetworkType = NetworkType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UnknownNetworkType');
+  static const NetworkType Wifi = NetworkType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Wifi');
+  static const NetworkType Cell = NetworkType._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Cell');
+  static const NetworkType Ethernet = NetworkType._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Ethernet');
+
+  static const $core.List<NetworkType> values = <NetworkType> [
+    UnknownNetworkType,
+    Wifi,
+    Cell,
+    Ethernet,
+  ];
+
+  static final $core.Map<$core.int, NetworkType> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static NetworkType? valueOf($core.int value) => _byValue[value];
+
+  const NetworkType._($core.int v, $core.String n) : super(v, n);
+}
+

+ 23 - 0
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/observable.pbjson.dart

@@ -22,3 +22,26 @@ const UserNotification$json = const {
 
 /// Descriptor for `UserNotification`. Decode as a `google.protobuf.EnumDescriptorProto`.
 final $typed_data.Uint8List userNotificationDescriptor = $convert.base64Decode('ChBVc2VyTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABITCg9Vc2VyQXV0aENoYW5nZWQQARIWChJVc2VyUHJvZmlsZVVwZGF0ZWQQAhIUChBVc2VyVW5hdXRob3JpemVkEAMSHQoZVXNlcldzQ29ubmVjdFN0YXRlQ2hhbmdlZBAE');
+@$core.Deprecated('Use networkTypeDescriptor instead')
+const NetworkType$json = const {
+  '1': 'NetworkType',
+  '2': const [
+    const {'1': 'UnknownNetworkType', '2': 0},
+    const {'1': 'Wifi', '2': 1},
+    const {'1': 'Cell', '2': 2},
+    const {'1': 'Ethernet', '2': 3},
+  ],
+};
+
+/// Descriptor for `NetworkType`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List networkTypeDescriptor = $convert.base64Decode('CgtOZXR3b3JrVHlwZRIWChJVbmtub3duTmV0d29ya1R5cGUQABIICgRXaWZpEAESCAoEQ2VsbBACEgwKCEV0aGVybmV0EAM=');
+@$core.Deprecated('Use networkStateDescriptor instead')
+const NetworkState$json = const {
+  '1': 'NetworkState',
+  '2': const [
+    const {'1': 'ty', '3': 1, '4': 1, '5': 14, '6': '.NetworkType', '10': 'ty'},
+  ],
+};
+
+/// Descriptor for `NetworkState`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List networkStateDescriptor = $convert.base64Decode('CgxOZXR3b3JrU3RhdGUSHAoCdHkYASABKA4yDC5OZXR3b3JrVHlwZVICdHk=');

+ 56 - 0
frontend/app_flowy/pubspec.lock

@@ -162,6 +162,48 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.15.0"
+  connectivity_plus:
+    dependency: "direct main"
+    description:
+      name: connectivity_plus
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.1.0"
+  connectivity_plus_linux:
+    dependency: transitive
+    description:
+      name: connectivity_plus_linux
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.1.1"
+  connectivity_plus_macos:
+    dependency: transitive
+    description:
+      name: connectivity_plus_macos
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.2.1"
+  connectivity_plus_platform_interface:
+    dependency: transitive
+    description:
+      name: connectivity_plus_platform_interface
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.1.1"
+  connectivity_plus_web:
+    dependency: transitive
+    description:
+      name: connectivity_plus_web
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.1.0+1"
+  connectivity_plus_windows:
+    dependency: transitive
+    description:
+      name: connectivity_plus_windows
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.2.0"
   convert:
     dependency: transitive
     description:
@@ -211,6 +253,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "0.10.0-nullsafety.2"
+  dbus:
+    dependency: transitive
+    description:
+      name: dbus
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.6.6"
   diff_match_patch:
     dependency: transitive
     description:
@@ -592,6 +641,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.0.0"
+  nm:
+    dependency: transitive
+    description:
+      name: nm
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.4.1"
   package_config:
     dependency: transitive
     description:

+ 1 - 0
frontend/app_flowy/pubspec.yaml

@@ -64,6 +64,7 @@ dependencies:
   url_launcher: ^6.0.2
   # file_picker: ^4.2.1
   clipboard: ^0.1.3
+  connectivity_plus: ^2.1.0
 
   # The following adds the Cupertino Icons font to your application.
   # Use with the CupertinoIcons class for iOS style icons.

+ 10 - 7
frontend/rust-lib/flowy-user/src/event.rs

@@ -5,23 +5,26 @@ use strum_macros::Display;
 #[event_err = "UserError"]
 pub enum UserEvent {
     #[event()]
-    InitUser       = 0,
+    InitUser          = 0,
 
     #[event(input = "SignInRequest", output = "UserProfile")]
-    SignIn         = 1,
+    SignIn            = 1,
 
     #[event(input = "SignUpRequest", output = "UserProfile")]
-    SignUp         = 2,
+    SignUp            = 2,
 
     #[event(passthrough)]
-    SignOut        = 3,
+    SignOut           = 3,
 
     #[event(input = "UpdateUserRequest")]
-    UpdateUser     = 4,
+    UpdateUser        = 4,
 
     #[event(output = "UserProfile")]
-    GetUserProfile = 5,
+    GetUserProfile    = 5,
 
     #[event(output = "UserProfile")]
-    CheckUser      = 6,
+    CheckUser         = 6,
+
+    #[event(input = "NetworkState")]
+    UpdateNetworkType = 10,
 }

+ 8 - 0
frontend/rust-lib/flowy-user/src/handlers/user_handler.rs

@@ -1,6 +1,7 @@
 use crate::{entities::*, errors::UserError, services::user::UserSession};
 use lib_dispatch::prelude::*;
 
+use crate::notify::NetworkState;
 use std::{convert::TryInto, sync::Arc};
 
 #[tracing::instrument(skip(session))]
@@ -36,3 +37,10 @@ pub async fn update_user_handler(
     session.update_user(params).await?;
     Ok(())
 }
+
+#[tracing::instrument(name = "update_user", skip(data, session))]
+pub async fn update_network_ty(data: Data<NetworkState>, session: Unit<Arc<UserSession>>) -> Result<(), UserError> {
+    let network_state = data.into_inner();
+    session.update_network_state(network_state);
+    Ok(())
+}

+ 1 - 0
frontend/rust-lib/flowy-user/src/module.rs

@@ -14,4 +14,5 @@ pub fn create(user_session: Arc<UserSession>) -> Module {
         .event(UserEvent::SignOut, sign_out)
         .event(UserEvent::UpdateUser, update_user_handler)
         .event(UserEvent::CheckUser, check_user_handler)
+        .event(UserEvent::UpdateNetworkType, update_network_ty)
 }

+ 19 - 1
frontend/rust-lib/flowy-user/src/notify/observable.rs

@@ -1,4 +1,4 @@
-use flowy_derive::ProtoBuf_Enum;
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 
 use dart_notify::DartNotifyBuilder;
 
@@ -24,3 +24,21 @@ impl std::convert::From<UserNotification> for i32 {
 pub(crate) fn dart_notify(id: &str, ty: UserNotification) -> DartNotifyBuilder {
     DartNotifyBuilder::new(id, ty, OBSERVABLE_CATEGORY)
 }
+
+#[derive(ProtoBuf_Enum, Debug)]
+pub enum NetworkType {
+    UnknownNetworkType = 0,
+    Wifi               = 1,
+    Cell               = 2,
+    Ethernet           = 3,
+}
+
+impl std::default::Default for NetworkType {
+    fn default() -> Self { NetworkType::UnknownNetworkType }
+}
+
+#[derive(ProtoBuf, Debug, Default)]
+pub struct NetworkState {
+    #[pb(index = 1)]
+    pub ty: NetworkType,
+}

+ 26 - 20
frontend/rust-lib/flowy-user/src/protobuf/model/event.rs

@@ -32,6 +32,7 @@ pub enum UserEvent {
     UpdateUser = 4,
     GetUserProfile = 5,
     CheckUser = 6,
+    UpdateNetworkType = 10,
 }
 
 impl ::protobuf::ProtobufEnum for UserEvent {
@@ -48,6 +49,7 @@ impl ::protobuf::ProtobufEnum for UserEvent {
             4 => ::std::option::Option::Some(UserEvent::UpdateUser),
             5 => ::std::option::Option::Some(UserEvent::GetUserProfile),
             6 => ::std::option::Option::Some(UserEvent::CheckUser),
+            10 => ::std::option::Option::Some(UserEvent::UpdateNetworkType),
             _ => ::std::option::Option::None
         }
     }
@@ -61,6 +63,7 @@ impl ::protobuf::ProtobufEnum for UserEvent {
             UserEvent::UpdateUser,
             UserEvent::GetUserProfile,
             UserEvent::CheckUser,
+            UserEvent::UpdateNetworkType,
         ];
         values
     }
@@ -89,26 +92,29 @@ impl ::protobuf::reflect::ProtobufValue for UserEvent {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0bevent.proto*q\n\tUserEvent\x12\x0c\n\x08InitUser\x10\0\x12\n\n\x06\
-    SignIn\x10\x01\x12\n\n\x06SignUp\x10\x02\x12\x0b\n\x07SignOut\x10\x03\
-    \x12\x0e\n\nUpdateUser\x10\x04\x12\x12\n\x0eGetUserProfile\x10\x05\x12\r\
-    \n\tCheckUser\x10\x06J\xc9\x02\n\x06\x12\x04\0\0\n\x01\n\x08\n\x01\x0c\
-    \x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\n\x01\n\n\n\x03\x05\0\x01\
-    \x12\x03\x02\x05\x0e\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x11\n\x0c\n\
-    \x05\x05\0\x02\0\x01\x12\x03\x03\x04\x0c\n\x0c\n\x05\x05\0\x02\0\x02\x12\
-    \x03\x03\x0f\x10\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x0f\n\x0c\n\
-    \x05\x05\0\x02\x01\x01\x12\x03\x04\x04\n\n\x0c\n\x05\x05\0\x02\x01\x02\
-    \x12\x03\x04\r\x0e\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x0f\n\x0c\n\
-    \x05\x05\0\x02\x02\x01\x12\x03\x05\x04\n\n\x0c\n\x05\x05\0\x02\x02\x02\
-    \x12\x03\x05\r\x0e\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x10\n\x0c\n\
-    \x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x0b\n\x0c\n\x05\x05\0\x02\x03\x02\
-    \x12\x03\x06\x0e\x0f\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x07\x04\x13\n\x0c\
-    \n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x0e\n\x0c\n\x05\x05\0\x02\x04\
-    \x02\x12\x03\x07\x11\x12\n\x0b\n\x04\x05\0\x02\x05\x12\x03\x08\x04\x17\n\
-    \x0c\n\x05\x05\0\x02\x05\x01\x12\x03\x08\x04\x12\n\x0c\n\x05\x05\0\x02\
-    \x05\x02\x12\x03\x08\x15\x16\n\x0b\n\x04\x05\0\x02\x06\x12\x03\t\x04\x12\
-    \n\x0c\n\x05\x05\0\x02\x06\x01\x12\x03\t\x04\r\n\x0c\n\x05\x05\0\x02\x06\
-    \x02\x12\x03\t\x10\x11b\x06proto3\
+    \n\x0bevent.proto*\x88\x01\n\tUserEvent\x12\x0c\n\x08InitUser\x10\0\x12\
+    \n\n\x06SignIn\x10\x01\x12\n\n\x06SignUp\x10\x02\x12\x0b\n\x07SignOut\
+    \x10\x03\x12\x0e\n\nUpdateUser\x10\x04\x12\x12\n\x0eGetUserProfile\x10\
+    \x05\x12\r\n\tCheckUser\x10\x06\x12\x15\n\x11UpdateNetworkType\x10\nJ\
+    \xf2\x02\n\x06\x12\x04\0\0\x0b\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\
+    \x02\x05\0\x12\x04\x02\0\x0b\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x0e\
+    \n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x11\n\x0c\n\x05\x05\0\x02\0\x01\
+    \x12\x03\x03\x04\x0c\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x0f\x10\n\
+    \x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x0f\n\x0c\n\x05\x05\0\x02\x01\
+    \x01\x12\x03\x04\x04\n\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\r\x0e\n\
+    \x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x0f\n\x0c\n\x05\x05\0\x02\x02\
+    \x01\x12\x03\x05\x04\n\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\r\x0e\n\
+    \x0b\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x10\n\x0c\n\x05\x05\0\x02\x03\
+    \x01\x12\x03\x06\x04\x0b\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\x06\x0e\
+    \x0f\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x07\x04\x13\n\x0c\n\x05\x05\0\x02\
+    \x04\x01\x12\x03\x07\x04\x0e\n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x07\
+    \x11\x12\n\x0b\n\x04\x05\0\x02\x05\x12\x03\x08\x04\x17\n\x0c\n\x05\x05\0\
+    \x02\x05\x01\x12\x03\x08\x04\x12\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\
+    \x08\x15\x16\n\x0b\n\x04\x05\0\x02\x06\x12\x03\t\x04\x12\n\x0c\n\x05\x05\
+    \0\x02\x06\x01\x12\x03\t\x04\r\n\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\t\
+    \x10\x11\n\x0b\n\x04\x05\0\x02\x07\x12\x03\n\x04\x1b\n\x0c\n\x05\x05\0\
+    \x02\x07\x01\x12\x03\n\x04\x15\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\n\
+    \x18\x1ab\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 236 - 16
frontend/rust-lib/flowy-user/src/protobuf/model/observable.rs

@@ -23,6 +23,154 @@
 /// of protobuf runtime.
 // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
 
+#[derive(PartialEq,Clone,Default)]
+pub struct NetworkState {
+    // message fields
+    pub ty: NetworkType,
+    // special fields
+    pub unknown_fields: ::protobuf::UnknownFields,
+    pub cached_size: ::protobuf::CachedSize,
+}
+
+impl<'a> ::std::default::Default for &'a NetworkState {
+    fn default() -> &'a NetworkState {
+        <NetworkState as ::protobuf::Message>::default_instance()
+    }
+}
+
+impl NetworkState {
+    pub fn new() -> NetworkState {
+        ::std::default::Default::default()
+    }
+
+    // .NetworkType ty = 1;
+
+
+    pub fn get_ty(&self) -> NetworkType {
+        self.ty
+    }
+    pub fn clear_ty(&mut self) {
+        self.ty = NetworkType::UnknownNetworkType;
+    }
+
+    // Param is passed by value, moved
+    pub fn set_ty(&mut self, v: NetworkType) {
+        self.ty = v;
+    }
+}
+
+impl ::protobuf::Message for NetworkState {
+    fn is_initialized(&self) -> bool {
+        true
+    }
+
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        while !is.eof()? {
+            let (field_number, wire_type) = is.read_tag_unpack()?;
+            match field_number {
+                1 => {
+                    ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 1, &mut self.unknown_fields)?
+                },
+                _ => {
+                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                },
+            };
+        }
+        ::std::result::Result::Ok(())
+    }
+
+    // Compute sizes of nested messages
+    #[allow(unused_variables)]
+    fn compute_size(&self) -> u32 {
+        let mut my_size = 0;
+        if self.ty != NetworkType::UnknownNetworkType {
+            my_size += ::protobuf::rt::enum_size(1, self.ty);
+        }
+        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
+        self.cached_size.set(my_size);
+        my_size
+    }
+
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        if self.ty != NetworkType::UnknownNetworkType {
+            os.write_enum(1, ::protobuf::ProtobufEnum::value(&self.ty))?;
+        }
+        os.write_unknown_fields(self.get_unknown_fields())?;
+        ::std::result::Result::Ok(())
+    }
+
+    fn get_cached_size(&self) -> u32 {
+        self.cached_size.get()
+    }
+
+    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
+        &self.unknown_fields
+    }
+
+    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
+        &mut self.unknown_fields
+    }
+
+    fn as_any(&self) -> &dyn (::std::any::Any) {
+        self as &dyn (::std::any::Any)
+    }
+    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
+        self as &mut dyn (::std::any::Any)
+    }
+    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
+        self
+    }
+
+    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
+        Self::descriptor_static()
+    }
+
+    fn new() -> NetworkState {
+        NetworkState::new()
+    }
+
+    fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
+        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
+        descriptor.get(|| {
+            let mut fields = ::std::vec::Vec::new();
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<NetworkType>>(
+                "ty",
+                |m: &NetworkState| { &m.ty },
+                |m: &mut NetworkState| { &mut m.ty },
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<NetworkState>(
+                "NetworkState",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static NetworkState {
+        static instance: ::protobuf::rt::LazyV2<NetworkState> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(NetworkState::new)
+    }
+}
+
+impl ::protobuf::Clear for NetworkState {
+    fn clear(&mut self) {
+        self.ty = NetworkType::UnknownNetworkType;
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for NetworkState {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for NetworkState {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
 pub enum UserNotification {
     Unknown = 0,
@@ -82,23 +230,95 @@ impl ::protobuf::reflect::ProtobufValue for UserNotification {
     }
 }
 
+#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+pub enum NetworkType {
+    UnknownNetworkType = 0,
+    Wifi = 1,
+    Cell = 2,
+    Ethernet = 3,
+}
+
+impl ::protobuf::ProtobufEnum for NetworkType {
+    fn value(&self) -> i32 {
+        *self as i32
+    }
+
+    fn from_i32(value: i32) -> ::std::option::Option<NetworkType> {
+        match value {
+            0 => ::std::option::Option::Some(NetworkType::UnknownNetworkType),
+            1 => ::std::option::Option::Some(NetworkType::Wifi),
+            2 => ::std::option::Option::Some(NetworkType::Cell),
+            3 => ::std::option::Option::Some(NetworkType::Ethernet),
+            _ => ::std::option::Option::None
+        }
+    }
+
+    fn values() -> &'static [Self] {
+        static values: &'static [NetworkType] = &[
+            NetworkType::UnknownNetworkType,
+            NetworkType::Wifi,
+            NetworkType::Cell,
+            NetworkType::Ethernet,
+        ];
+        values
+    }
+
+    fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
+        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
+        descriptor.get(|| {
+            ::protobuf::reflect::EnumDescriptor::new_pb_name::<NetworkType>("NetworkType", file_descriptor_proto())
+        })
+    }
+}
+
+impl ::std::marker::Copy for NetworkType {
+}
+
+impl ::std::default::Default for NetworkType {
+    fn default() -> Self {
+        NetworkType::UnknownNetworkType
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for NetworkType {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
+    }
+}
+
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x10observable.proto*\x81\x01\n\x10UserNotification\x12\x0b\n\x07Unkno\
-    wn\x10\0\x12\x13\n\x0fUserAuthChanged\x10\x01\x12\x16\n\x12UserProfileUp\
-    dated\x10\x02\x12\x14\n\x10UserUnauthorized\x10\x03\x12\x1d\n\x19UserWsC\
-    onnectStateChanged\x10\x04J\xf7\x01\n\x06\x12\x04\0\0\x08\x01\n\x08\n\
-    \x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\x08\x01\n\n\n\x03\
-    \x05\0\x01\x12\x03\x02\x05\x15\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\
-    \x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x03\x04\x0b\n\x0c\n\x05\x05\0\
-    \x02\0\x02\x12\x03\x03\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\
-    \x18\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\x04\x13\n\x0c\n\x05\x05\0\
-    \x02\x01\x02\x12\x03\x04\x16\x17\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\
-    \x04\x1b\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x05\x04\x16\n\x0c\n\x05\
-    \x05\0\x02\x02\x02\x12\x03\x05\x19\x1a\n\x0b\n\x04\x05\0\x02\x03\x12\x03\
-    \x06\x04\x19\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x14\n\x0c\n\
-    \x05\x05\0\x02\x03\x02\x12\x03\x06\x17\x18\n\x0b\n\x04\x05\0\x02\x04\x12\
-    \x03\x07\x04\"\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x1d\n\x0c\n\
-    \x05\x05\0\x02\x04\x02\x12\x03\x07\x20!b\x06proto3\
+    \n\x10observable.proto\",\n\x0cNetworkState\x12\x1c\n\x02ty\x18\x01\x20\
+    \x01(\x0e2\x0c.NetworkTypeR\x02ty*\x81\x01\n\x10UserNotification\x12\x0b\
+    \n\x07Unknown\x10\0\x12\x13\n\x0fUserAuthChanged\x10\x01\x12\x16\n\x12Us\
+    erProfileUpdated\x10\x02\x12\x14\n\x10UserUnauthorized\x10\x03\x12\x1d\n\
+    \x19UserWsConnectStateChanged\x10\x04*G\n\x0bNetworkType\x12\x16\n\x12Un\
+    knownNetworkType\x10\0\x12\x08\n\x04Wifi\x10\x01\x12\x08\n\x04Cell\x10\
+    \x02\x12\x0c\n\x08Ethernet\x10\x03J\x82\x04\n\x06\x12\x04\0\0\x11\x01\n\
+    \x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\n\
+    \n\x03\x04\0\x01\x12\x03\x02\x08\x14\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\
+    \x04\x17\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x03\x04\x0f\n\x0c\n\x05\x04\
+    \0\x02\0\x01\x12\x03\x03\x10\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\
+    \x15\x16\n\n\n\x02\x05\0\x12\x04\x05\0\x0b\x01\n\n\n\x03\x05\0\x01\x12\
+    \x03\x05\x05\x15\n\x0b\n\x04\x05\0\x02\0\x12\x03\x06\x04\x10\n\x0c\n\x05\
+    \x05\0\x02\0\x01\x12\x03\x06\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\
+    \x06\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x07\x04\x18\n\x0c\n\x05\
+    \x05\0\x02\x01\x01\x12\x03\x07\x04\x13\n\x0c\n\x05\x05\0\x02\x01\x02\x12\
+    \x03\x07\x16\x17\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x08\x04\x1b\n\x0c\n\
+    \x05\x05\0\x02\x02\x01\x12\x03\x08\x04\x16\n\x0c\n\x05\x05\0\x02\x02\x02\
+    \x12\x03\x08\x19\x1a\n\x0b\n\x04\x05\0\x02\x03\x12\x03\t\x04\x19\n\x0c\n\
+    \x05\x05\0\x02\x03\x01\x12\x03\t\x04\x14\n\x0c\n\x05\x05\0\x02\x03\x02\
+    \x12\x03\t\x17\x18\n\x0b\n\x04\x05\0\x02\x04\x12\x03\n\x04\"\n\x0c\n\x05\
+    \x05\0\x02\x04\x01\x12\x03\n\x04\x1d\n\x0c\n\x05\x05\0\x02\x04\x02\x12\
+    \x03\n\x20!\n\n\n\x02\x05\x01\x12\x04\x0c\0\x11\x01\n\n\n\x03\x05\x01\
+    \x01\x12\x03\x0c\x05\x10\n\x0b\n\x04\x05\x01\x02\0\x12\x03\r\x04\x1b\n\
+    \x0c\n\x05\x05\x01\x02\0\x01\x12\x03\r\x04\x16\n\x0c\n\x05\x05\x01\x02\0\
+    \x02\x12\x03\r\x19\x1a\n\x0b\n\x04\x05\x01\x02\x01\x12\x03\x0e\x04\r\n\
+    \x0c\n\x05\x05\x01\x02\x01\x01\x12\x03\x0e\x04\x08\n\x0c\n\x05\x05\x01\
+    \x02\x01\x02\x12\x03\x0e\x0b\x0c\n\x0b\n\x04\x05\x01\x02\x02\x12\x03\x0f\
+    \x04\r\n\x0c\n\x05\x05\x01\x02\x02\x01\x12\x03\x0f\x04\x08\n\x0c\n\x05\
+    \x05\x01\x02\x02\x02\x12\x03\x0f\x0b\x0c\n\x0b\n\x04\x05\x01\x02\x03\x12\
+    \x03\x10\x04\x11\n\x0c\n\x05\x05\x01\x02\x03\x01\x12\x03\x10\x04\x0c\n\
+    \x0c\n\x05\x05\x01\x02\x03\x02\x12\x03\x10\x0f\x10b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 1 - 0
frontend/rust-lib/flowy-user/src/protobuf/proto/event.proto

@@ -8,4 +8,5 @@ enum UserEvent {
     UpdateUser = 4;
     GetUserProfile = 5;
     CheckUser = 6;
+    UpdateNetworkType = 10;
 }

+ 9 - 0
frontend/rust-lib/flowy-user/src/protobuf/proto/observable.proto

@@ -1,5 +1,8 @@
 syntax = "proto3";
 
+message NetworkState {
+    NetworkType ty = 1;
+}
 enum UserNotification {
     Unknown = 0;
     UserAuthChanged = 1;
@@ -7,3 +10,9 @@ enum UserNotification {
     UserUnauthorized = 3;
     UserWsConnectStateChanged = 4;
 }
+enum NetworkType {
+    UnknownNetworkType = 0;
+    Wifi = 1;
+    Cell = 2;
+    Ethernet = 3;
+}

+ 4 - 0
frontend/rust-lib/flowy-user/src/services/user/user_session.rs

@@ -211,6 +211,10 @@ impl UserSession {
     pub fn add_ws_handler(&self, handler: Arc<dyn WsMessageHandler>) {
         let _ = self.ws_controller.add_handler(handler);
     }
+
+    pub fn update_network_state(&self, state: NetworkState) {
+        log::info!("{:?}", state);
+    }
 }
 
 impl UserSession {

+ 2 - 0
shared-lib/flowy-derive/src/derive_cache/derive_cache.rs

@@ -23,6 +23,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "FFIResponse"
         | "SubscribeObject"
         | "UserError"
+        | "NetworkState"
         | "QueryAppRequest"
         | "AppIdentifier"
         | "CreateAppRequest"
@@ -86,6 +87,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "FFIStatusCode"
         | "UserEvent"
         | "UserNotification"
+        | "NetworkType"
         | "TrashType"
         | "ViewType"
         | "ExportType"