diff --git a/app_flowy/analysis_options.yaml b/app_flowy/analysis_options.yaml index e9def11a1c..eb5b057c3c 100644 --- a/app_flowy/analysis_options.yaml +++ b/app_flowy/analysis_options.yaml @@ -15,6 +15,7 @@ analyzer: - "**/*.g.dart" - "**/*.freezed.dart" - "packages/flowy_editor/**" + - "packages/flowy_infra_ui/**" linter: # The lint rules applied to this project can be customized in the diff --git a/app_flowy/lib/home/application/app/app_bloc.dart b/app_flowy/lib/home/application/app/app_bloc.dart new file mode 100644 index 0000000000..4efc79332c --- /dev/null +++ b/app_flowy/lib/home/application/app/app_bloc.dart @@ -0,0 +1,20 @@ +import 'package:app_flowy/home/domain/i_app.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:dartz/dartz.dart'; + +part 'app_event.dart'; +part 'app_state.dart'; +part 'app_bloc.freezed.dart'; + +class AppBloc extends Bloc { + final IApp iAppImpl; + AppBloc(this.iAppImpl) : super(AppState.initial()); + + @override + Stream mapEventToState( + AppEvent event, + ) async* {} +} diff --git a/app_flowy/lib/home/application/app/app_bloc.freezed.dart b/app_flowy/lib/home/application/app/app_bloc.freezed.dart new file mode 100644 index 0000000000..464b2dcb1f --- /dev/null +++ b/app_flowy/lib/home/application/app/app_bloc.freezed.dart @@ -0,0 +1,361 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'app_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$AppEventTearOff { + const _$AppEventTearOff(); + + AppsReceived appsReceived(Either, WorkspaceError> appsOrFail) { + return AppsReceived( + appsOrFail, + ); + } +} + +/// @nodoc +const $AppEvent = _$AppEventTearOff(); + +/// @nodoc +mixin _$AppEvent { + Either, WorkspaceError> get appsOrFail => + throw _privateConstructorUsedError; + + @optionalTypeArgs + TResult when({ + required TResult Function(Either, WorkspaceError> appsOrFail) + appsReceived, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(Either, WorkspaceError> appsOrFail)? + appsReceived, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(AppsReceived value) appsReceived, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(AppsReceived value)? appsReceived, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $AppEventCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AppEventCopyWith<$Res> { + factory $AppEventCopyWith(AppEvent value, $Res Function(AppEvent) then) = + _$AppEventCopyWithImpl<$Res>; + $Res call({Either, WorkspaceError> appsOrFail}); +} + +/// @nodoc +class _$AppEventCopyWithImpl<$Res> implements $AppEventCopyWith<$Res> { + _$AppEventCopyWithImpl(this._value, this._then); + + final AppEvent _value; + // ignore: unused_field + final $Res Function(AppEvent) _then; + + @override + $Res call({ + Object? appsOrFail = freezed, + }) { + return _then(_value.copyWith( + appsOrFail: appsOrFail == freezed + ? _value.appsOrFail + : appsOrFail // ignore: cast_nullable_to_non_nullable + as Either, WorkspaceError>, + )); + } +} + +/// @nodoc +abstract class $AppsReceivedCopyWith<$Res> implements $AppEventCopyWith<$Res> { + factory $AppsReceivedCopyWith( + AppsReceived value, $Res Function(AppsReceived) then) = + _$AppsReceivedCopyWithImpl<$Res>; + @override + $Res call({Either, WorkspaceError> appsOrFail}); +} + +/// @nodoc +class _$AppsReceivedCopyWithImpl<$Res> extends _$AppEventCopyWithImpl<$Res> + implements $AppsReceivedCopyWith<$Res> { + _$AppsReceivedCopyWithImpl( + AppsReceived _value, $Res Function(AppsReceived) _then) + : super(_value, (v) => _then(v as AppsReceived)); + + @override + AppsReceived get _value => super._value as AppsReceived; + + @override + $Res call({ + Object? appsOrFail = freezed, + }) { + return _then(AppsReceived( + appsOrFail == freezed + ? _value.appsOrFail + : appsOrFail // ignore: cast_nullable_to_non_nullable + as Either, WorkspaceError>, + )); + } +} + +/// @nodoc + +class _$AppsReceived implements AppsReceived { + const _$AppsReceived(this.appsOrFail); + + @override + final Either, WorkspaceError> appsOrFail; + + @override + String toString() { + return 'AppEvent.appsReceived(appsOrFail: $appsOrFail)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is AppsReceived && + (identical(other.appsOrFail, appsOrFail) || + const DeepCollectionEquality() + .equals(other.appsOrFail, appsOrFail))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(appsOrFail); + + @JsonKey(ignore: true) + @override + $AppsReceivedCopyWith get copyWith => + _$AppsReceivedCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(Either, WorkspaceError> appsOrFail) + appsReceived, + }) { + return appsReceived(appsOrFail); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(Either, WorkspaceError> appsOrFail)? + appsReceived, + required TResult orElse(), + }) { + if (appsReceived != null) { + return appsReceived(appsOrFail); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(AppsReceived value) appsReceived, + }) { + return appsReceived(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(AppsReceived value)? appsReceived, + required TResult orElse(), + }) { + if (appsReceived != null) { + return appsReceived(this); + } + return orElse(); + } +} + +abstract class AppsReceived implements AppEvent { + const factory AppsReceived(Either, WorkspaceError> appsOrFail) = + _$AppsReceived; + + @override + Either, WorkspaceError> get appsOrFail => + throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + $AppsReceivedCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +class _$AppStateTearOff { + const _$AppStateTearOff(); + + _AppState call( + {required Option> apps, + required Either successOrFailure}) { + return _AppState( + apps: apps, + successOrFailure: successOrFailure, + ); + } +} + +/// @nodoc +const $AppState = _$AppStateTearOff(); + +/// @nodoc +mixin _$AppState { + Option> get apps => throw _privateConstructorUsedError; + Either get successOrFailure => + throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $AppStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AppStateCopyWith<$Res> { + factory $AppStateCopyWith(AppState value, $Res Function(AppState) then) = + _$AppStateCopyWithImpl<$Res>; + $Res call( + {Option> apps, Either successOrFailure}); +} + +/// @nodoc +class _$AppStateCopyWithImpl<$Res> implements $AppStateCopyWith<$Res> { + _$AppStateCopyWithImpl(this._value, this._then); + + final AppState _value; + // ignore: unused_field + final $Res Function(AppState) _then; + + @override + $Res call({ + Object? apps = freezed, + Object? successOrFailure = freezed, + }) { + return _then(_value.copyWith( + apps: apps == freezed + ? _value.apps + : apps // ignore: cast_nullable_to_non_nullable + as Option>, + successOrFailure: successOrFailure == freezed + ? _value.successOrFailure + : successOrFailure // ignore: cast_nullable_to_non_nullable + as Either, + )); + } +} + +/// @nodoc +abstract class _$AppStateCopyWith<$Res> implements $AppStateCopyWith<$Res> { + factory _$AppStateCopyWith(_AppState value, $Res Function(_AppState) then) = + __$AppStateCopyWithImpl<$Res>; + @override + $Res call( + {Option> apps, Either successOrFailure}); +} + +/// @nodoc +class __$AppStateCopyWithImpl<$Res> extends _$AppStateCopyWithImpl<$Res> + implements _$AppStateCopyWith<$Res> { + __$AppStateCopyWithImpl(_AppState _value, $Res Function(_AppState) _then) + : super(_value, (v) => _then(v as _AppState)); + + @override + _AppState get _value => super._value as _AppState; + + @override + $Res call({ + Object? apps = freezed, + Object? successOrFailure = freezed, + }) { + return _then(_AppState( + apps: apps == freezed + ? _value.apps + : apps // ignore: cast_nullable_to_non_nullable + as Option>, + successOrFailure: successOrFailure == freezed + ? _value.successOrFailure + : successOrFailure // ignore: cast_nullable_to_non_nullable + as Either, + )); + } +} + +/// @nodoc + +class _$_AppState implements _AppState { + const _$_AppState({required this.apps, required this.successOrFailure}); + + @override + final Option> apps; + @override + final Either successOrFailure; + + @override + String toString() { + return 'AppState(apps: $apps, successOrFailure: $successOrFailure)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _AppState && + (identical(other.apps, apps) || + const DeepCollectionEquality().equals(other.apps, apps)) && + (identical(other.successOrFailure, successOrFailure) || + const DeepCollectionEquality() + .equals(other.successOrFailure, successOrFailure))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(apps) ^ + const DeepCollectionEquality().hash(successOrFailure); + + @JsonKey(ignore: true) + @override + _$AppStateCopyWith<_AppState> get copyWith => + __$AppStateCopyWithImpl<_AppState>(this, _$identity); +} + +abstract class _AppState implements AppState { + const factory _AppState( + {required Option> apps, + required Either successOrFailure}) = _$_AppState; + + @override + Option> get apps => throw _privateConstructorUsedError; + @override + Either get successOrFailure => + throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$AppStateCopyWith<_AppState> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/app_flowy/lib/home/application/app/app_event.dart b/app_flowy/lib/home/application/app/app_event.dart new file mode 100644 index 0000000000..eb606d3003 --- /dev/null +++ b/app_flowy/lib/home/application/app/app_event.dart @@ -0,0 +1,7 @@ +part of 'app_bloc.dart'; + +@freezed +abstract class AppEvent with _$AppEvent { + const factory AppEvent.appsReceived( + Either, WorkspaceError> appsOrFail) = AppsReceived; +} diff --git a/app_flowy/lib/home/application/app/app_state.dart b/app_flowy/lib/home/application/app/app_state.dart new file mode 100644 index 0000000000..a8cd0ac68c --- /dev/null +++ b/app_flowy/lib/home/application/app/app_state.dart @@ -0,0 +1,14 @@ +part of 'app_bloc.dart'; + +@freezed +abstract class AppState implements _$AppState { + const factory AppState({ + required Option> apps, + required Either successOrFailure, + }) = _AppState; + + factory AppState.initial() => AppState( + apps: none(), + successOrFailure: left(unit), + ); +} diff --git a/app_flowy/lib/home/application/menu/menu_bloc.dart b/app_flowy/lib/home/application/menu/menu_bloc.dart index 3c1278a0a2..5bd8951d15 100644 --- a/app_flowy/lib/home/application/menu/menu_bloc.dart +++ b/app_flowy/lib/home/application/menu/menu_bloc.dart @@ -1,6 +1,8 @@ import 'dart:async'; +import 'package:app_flowy/home/domain/i_app.dart'; import 'package:app_flowy/home/domain/page_context.dart'; import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart'; import 'package:flutter/material.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -9,7 +11,8 @@ part 'menu_state.dart'; part 'menu_bloc.freezed.dart'; class MenuBloc extends Bloc { - MenuBloc() : super(MenuState.initial()); + final IApp iAppImpl; + MenuBloc(this.iAppImpl) : super(MenuState.initial()); @override Stream mapEventToState( @@ -23,8 +26,8 @@ class MenuBloc extends Bloc { openPage: (e) async* { yield* _performActionOnOpenPage(e); }, - createApp: (e) async* { - yield* _performActionOnCreateApp(e); + createApp: (event) async* { + yield* _performActionOnCreateApp(event); }, ); } @@ -33,8 +36,17 @@ class MenuBloc extends Bloc { yield state.copyWith(pageContext: some(e.context)); } - Stream _performActionOnCreateApp(_CreateApp val) async* { - yield state; + Stream _performActionOnCreateApp(_CreateApp event) async* { + await iAppImpl + .createApp(name: event.name, desc: event.desc) + .then((result) async* { + result.fold( + (app) => {}, + (error) async* { + yield state.copyWith(successOrFailure: right(error)); + }, + ); + }); } @override diff --git a/app_flowy/lib/home/application/menu/menu_bloc.freezed.dart b/app_flowy/lib/home/application/menu/menu_bloc.freezed.dart index 8bfbf24366..b9f0adfe72 100644 --- a/app_flowy/lib/home/application/menu/menu_bloc.freezed.dart +++ b/app_flowy/lib/home/application/menu/menu_bloc.freezed.dart @@ -26,9 +26,10 @@ class _$MenuEventTearOff { ); } - _CreateApp createApp(String appName) { + _CreateApp createApp(String name, {String? desc}) { return _CreateApp( - appName, + name, + desc: desc, ); } } @@ -42,14 +43,14 @@ mixin _$MenuEvent { TResult when({ required TResult Function() collapse, required TResult Function(PageContext context) openPage, - required TResult Function(String appName) createApp, + required TResult Function(String name, String? desc) createApp, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function()? collapse, TResult Function(PageContext context)? openPage, - TResult Function(String appName)? createApp, + TResult Function(String name, String? desc)? createApp, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -124,7 +125,7 @@ class _$Collapse implements Collapse { TResult when({ required TResult Function() collapse, required TResult Function(PageContext context) openPage, - required TResult Function(String appName) createApp, + required TResult Function(String name, String? desc) createApp, }) { return collapse(); } @@ -134,7 +135,7 @@ class _$Collapse implements Collapse { TResult maybeWhen({ TResult Function()? collapse, TResult Function(PageContext context)? openPage, - TResult Function(String appName)? createApp, + TResult Function(String name, String? desc)? createApp, required TResult orElse(), }) { if (collapse != null) { @@ -236,7 +237,7 @@ class _$_OpenPage implements _OpenPage { TResult when({ required TResult Function() collapse, required TResult Function(PageContext context) openPage, - required TResult Function(String appName) createApp, + required TResult Function(String name, String? desc) createApp, }) { return openPage(context); } @@ -246,7 +247,7 @@ class _$_OpenPage implements _OpenPage { TResult maybeWhen({ TResult Function()? collapse, TResult Function(PageContext context)? openPage, - TResult Function(String appName)? createApp, + TResult Function(String name, String? desc)? createApp, required TResult orElse(), }) { if (openPage != null) { @@ -294,7 +295,7 @@ abstract class _$CreateAppCopyWith<$Res> { factory _$CreateAppCopyWith( _CreateApp value, $Res Function(_CreateApp) then) = __$CreateAppCopyWithImpl<$Res>; - $Res call({String appName}); + $Res call({String name, String? desc}); } /// @nodoc @@ -308,13 +309,18 @@ class __$CreateAppCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res> @override $Res call({ - Object? appName = freezed, + Object? name = freezed, + Object? desc = freezed, }) { return _then(_CreateApp( - appName == freezed - ? _value.appName - : appName // ignore: cast_nullable_to_non_nullable + name == freezed + ? _value.name + : name // ignore: cast_nullable_to_non_nullable as String, + desc: desc == freezed + ? _value.desc + : desc // ignore: cast_nullable_to_non_nullable + as String?, )); } } @@ -322,27 +328,33 @@ class __$CreateAppCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res> /// @nodoc class _$_CreateApp implements _CreateApp { - const _$_CreateApp(this.appName); + const _$_CreateApp(this.name, {this.desc}); @override - final String appName; + final String name; + @override + final String? desc; @override String toString() { - return 'MenuEvent.createApp(appName: $appName)'; + return 'MenuEvent.createApp(name: $name, desc: $desc)'; } @override bool operator ==(dynamic other) { return identical(this, other) || (other is _CreateApp && - (identical(other.appName, appName) || - const DeepCollectionEquality().equals(other.appName, appName))); + (identical(other.name, name) || + const DeepCollectionEquality().equals(other.name, name)) && + (identical(other.desc, desc) || + const DeepCollectionEquality().equals(other.desc, desc))); } @override int get hashCode => - runtimeType.hashCode ^ const DeepCollectionEquality().hash(appName); + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(name) ^ + const DeepCollectionEquality().hash(desc); @JsonKey(ignore: true) @override @@ -354,9 +366,9 @@ class _$_CreateApp implements _CreateApp { TResult when({ required TResult Function() collapse, required TResult Function(PageContext context) openPage, - required TResult Function(String appName) createApp, + required TResult Function(String name, String? desc) createApp, }) { - return createApp(appName); + return createApp(name, desc); } @override @@ -364,11 +376,11 @@ class _$_CreateApp implements _CreateApp { TResult maybeWhen({ TResult Function()? collapse, TResult Function(PageContext context)? openPage, - TResult Function(String appName)? createApp, + TResult Function(String name, String? desc)? createApp, required TResult orElse(), }) { if (createApp != null) { - return createApp(appName); + return createApp(name, desc); } return orElse(); } @@ -399,9 +411,10 @@ class _$_CreateApp implements _CreateApp { } abstract class _CreateApp implements MenuEvent { - const factory _CreateApp(String appName) = _$_CreateApp; + const factory _CreateApp(String name, {String? desc}) = _$_CreateApp; - String get appName => throw _privateConstructorUsedError; + String get name => throw _privateConstructorUsedError; + String? get desc => throw _privateConstructorUsedError; @JsonKey(ignore: true) _$CreateAppCopyWith<_CreateApp> get copyWith => throw _privateConstructorUsedError; @@ -412,10 +425,13 @@ class _$MenuStateTearOff { const _$MenuStateTearOff(); _MenuState call( - {required bool isCollapse, required Option pageContext}) { + {required bool isCollapse, + required Option pageContext, + required Either successOrFailure}) { return _MenuState( isCollapse: isCollapse, pageContext: pageContext, + successOrFailure: successOrFailure, ); } } @@ -427,6 +443,8 @@ const $MenuState = _$MenuStateTearOff(); mixin _$MenuState { bool get isCollapse => throw _privateConstructorUsedError; Option get pageContext => throw _privateConstructorUsedError; + Either get successOrFailure => + throw _privateConstructorUsedError; @JsonKey(ignore: true) $MenuStateCopyWith get copyWith => @@ -437,7 +455,10 @@ mixin _$MenuState { abstract class $MenuStateCopyWith<$Res> { factory $MenuStateCopyWith(MenuState value, $Res Function(MenuState) then) = _$MenuStateCopyWithImpl<$Res>; - $Res call({bool isCollapse, Option pageContext}); + $Res call( + {bool isCollapse, + Option pageContext, + Either successOrFailure}); } /// @nodoc @@ -452,6 +473,7 @@ class _$MenuStateCopyWithImpl<$Res> implements $MenuStateCopyWith<$Res> { $Res call({ Object? isCollapse = freezed, Object? pageContext = freezed, + Object? successOrFailure = freezed, }) { return _then(_value.copyWith( isCollapse: isCollapse == freezed @@ -462,6 +484,10 @@ class _$MenuStateCopyWithImpl<$Res> implements $MenuStateCopyWith<$Res> { ? _value.pageContext : pageContext // ignore: cast_nullable_to_non_nullable as Option, + successOrFailure: successOrFailure == freezed + ? _value.successOrFailure + : successOrFailure // ignore: cast_nullable_to_non_nullable + as Either, )); } } @@ -472,7 +498,10 @@ abstract class _$MenuStateCopyWith<$Res> implements $MenuStateCopyWith<$Res> { _MenuState value, $Res Function(_MenuState) then) = __$MenuStateCopyWithImpl<$Res>; @override - $Res call({bool isCollapse, Option pageContext}); + $Res call( + {bool isCollapse, + Option pageContext, + Either successOrFailure}); } /// @nodoc @@ -488,6 +517,7 @@ class __$MenuStateCopyWithImpl<$Res> extends _$MenuStateCopyWithImpl<$Res> $Res call({ Object? isCollapse = freezed, Object? pageContext = freezed, + Object? successOrFailure = freezed, }) { return _then(_MenuState( isCollapse: isCollapse == freezed @@ -498,6 +528,10 @@ class __$MenuStateCopyWithImpl<$Res> extends _$MenuStateCopyWithImpl<$Res> ? _value.pageContext : pageContext // ignore: cast_nullable_to_non_nullable as Option, + successOrFailure: successOrFailure == freezed + ? _value.successOrFailure + : successOrFailure // ignore: cast_nullable_to_non_nullable + as Either, )); } } @@ -505,16 +539,21 @@ class __$MenuStateCopyWithImpl<$Res> extends _$MenuStateCopyWithImpl<$Res> /// @nodoc class _$_MenuState implements _MenuState { - const _$_MenuState({required this.isCollapse, required this.pageContext}); + const _$_MenuState( + {required this.isCollapse, + required this.pageContext, + required this.successOrFailure}); @override final bool isCollapse; @override final Option pageContext; + @override + final Either successOrFailure; @override String toString() { - return 'MenuState(isCollapse: $isCollapse, pageContext: $pageContext)'; + return 'MenuState(isCollapse: $isCollapse, pageContext: $pageContext, successOrFailure: $successOrFailure)'; } @override @@ -526,14 +565,18 @@ class _$_MenuState implements _MenuState { .equals(other.isCollapse, isCollapse)) && (identical(other.pageContext, pageContext) || const DeepCollectionEquality() - .equals(other.pageContext, pageContext))); + .equals(other.pageContext, pageContext)) && + (identical(other.successOrFailure, successOrFailure) || + const DeepCollectionEquality() + .equals(other.successOrFailure, successOrFailure))); } @override int get hashCode => runtimeType.hashCode ^ const DeepCollectionEquality().hash(isCollapse) ^ - const DeepCollectionEquality().hash(pageContext); + const DeepCollectionEquality().hash(pageContext) ^ + const DeepCollectionEquality().hash(successOrFailure); @JsonKey(ignore: true) @override @@ -544,13 +587,17 @@ class _$_MenuState implements _MenuState { abstract class _MenuState implements MenuState { const factory _MenuState( {required bool isCollapse, - required Option pageContext}) = _$_MenuState; + required Option pageContext, + required Either successOrFailure}) = _$_MenuState; @override bool get isCollapse => throw _privateConstructorUsedError; @override Option get pageContext => throw _privateConstructorUsedError; @override + Either get successOrFailure => + throw _privateConstructorUsedError; + @override @JsonKey(ignore: true) _$MenuStateCopyWith<_MenuState> get copyWith => throw _privateConstructorUsedError; diff --git a/app_flowy/lib/home/application/menu/menu_event.dart b/app_flowy/lib/home/application/menu/menu_event.dart index fabde31bd3..1d088b6451 100644 --- a/app_flowy/lib/home/application/menu/menu_event.dart +++ b/app_flowy/lib/home/application/menu/menu_event.dart @@ -4,5 +4,5 @@ part of 'menu_bloc.dart'; abstract class MenuEvent with _$MenuEvent { const factory MenuEvent.collapse() = Collapse; const factory MenuEvent.openPage(PageContext context) = _OpenPage; - const factory MenuEvent.createApp(String appName) = _CreateApp; + const factory MenuEvent.createApp(String name, {String? desc}) = _CreateApp; } diff --git a/app_flowy/lib/home/application/menu/menu_state.dart b/app_flowy/lib/home/application/menu/menu_state.dart index 548459be0d..269ec011b0 100644 --- a/app_flowy/lib/home/application/menu/menu_state.dart +++ b/app_flowy/lib/home/application/menu/menu_state.dart @@ -5,10 +5,12 @@ abstract class MenuState implements _$MenuState { const factory MenuState({ required bool isCollapse, required Option pageContext, + required Either successOrFailure, }) = _MenuState; factory MenuState.initial() => MenuState( isCollapse: false, pageContext: none(), + successOrFailure: left(unit), ); } diff --git a/app_flowy/lib/home/domain/i_app.dart b/app_flowy/lib/home/domain/i_app.dart new file mode 100644 index 0000000000..04d99cdf8f --- /dev/null +++ b/app_flowy/lib/home/domain/i_app.dart @@ -0,0 +1,18 @@ +import 'package:flowy_sdk/protobuf/flowy-workspace/protobuf.dart'; +import 'package:dartz/dartz.dart'; + +abstract class IApp { + Future> createApp( + {required String name, String? desc}); + + Future, WorkspaceError>> getApps( + {required String workspaceId}); + + Future, WorkspaceError>> getViews({required String appId}); + + Future> createView( + {required String appId, + required String name, + String? desc, + required ViewTypeIdentifier viewType}); +} diff --git a/app_flowy/lib/home/infrastructure/app_repo.dart b/app_flowy/lib/home/infrastructure/app_repo.dart new file mode 100644 index 0000000000..c42f66db16 --- /dev/null +++ b/app_flowy/lib/home/infrastructure/app_repo.dart @@ -0,0 +1,65 @@ +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/dispatch/dispatch.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/app_query.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_query.pb.dart'; + +class AppRepository { + Future> createApp(String appName, String desc) { + return WorkspaceEventGetCurWorkspace().send().then((result) { + return result.fold( + (workspace) { + final request = CreateAppRequest.create() + ..name = appName + ..workspaceId = workspace.id + ..desc = desc; + return WorkspaceEventCreateApp(request).send(); + }, + (error) { + return right(error); + }, + ); + }); + } + + Future, WorkspaceError>> getApps( + {required String workspaceId}) { + final request = QueryWorkspaceRequest.create() + ..workspaceId = workspaceId + ..readApps = true; + + return WorkspaceEventGetWorkspace(request).send().then((result) { + return result.fold( + (workspace) => left(workspace.apps.items), + (error) => right(error), + ); + }); + } + + Future, WorkspaceError>> getViews({required String appId}) { + final request = QueryAppRequest.create() + ..appId = appId + ..readViews = true; + + return WorkspaceEventGetApp(request).send().then((result) { + return result.fold( + (app) => left(app.views.items), + (error) => right(error), + ); + }); + } + + Future> createView( + String appId, String name, String desc, ViewTypeIdentifier viewType) { + final request = CreateViewRequest.create() + ..appId = appId + ..name = name + ..desc = desc + ..viewType = viewType; + + return WorkspaceEventCreateView(request).send(); + } +} diff --git a/app_flowy/lib/home/infrastructure/deps_resolver.dart b/app_flowy/lib/home/infrastructure/deps_resolver.dart new file mode 100644 index 0000000000..5ca9d072c7 --- /dev/null +++ b/app_flowy/lib/home/infrastructure/deps_resolver.dart @@ -0,0 +1,16 @@ +import 'package:app_flowy/home/application/menu/menu_bloc.dart'; +import 'package:app_flowy/home/infrastructure/app_repo.dart'; +import 'package:app_flowy/home/infrastructure/i_app_impl.dart'; +import 'package:get_it/get_it.dart'; + +class HomeDepsResolver { + static Future resolve(GetIt getIt) async { + getIt.registerLazySingleton(() => AppRepository()); + + //Interface implementation + getIt.registerFactory(() => IAppImpl(repo: getIt())); + + //Bloc + getIt.registerFactory(() => MenuBloc(getIt())); + } +} diff --git a/app_flowy/lib/home/infrastructure/i_app_impl.dart b/app_flowy/lib/home/infrastructure/i_app_impl.dart new file mode 100644 index 0000000000..6206bf7938 --- /dev/null +++ b/app_flowy/lib/home/infrastructure/i_app_impl.dart @@ -0,0 +1,41 @@ +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart'; +import 'package:app_flowy/home/domain/i_app.dart'; +import 'package:app_flowy/home/infrastructure/app_repo.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; + +export 'package:app_flowy/home/domain/i_app.dart'; + +class IAppImpl extends IApp { + AppRepository repo; + IAppImpl({ + required this.repo, + }); + + @override + Future> createApp( + {required String name, String? desc}) { + return repo.createApp(name, desc ?? ""); + } + + @override + Future, WorkspaceError>> getApps( + {required String workspaceId}) { + return repo.getApps(workspaceId: workspaceId); + } + + @override + Future, WorkspaceError>> getViews({required String appId}) { + return repo.getViews(appId: appId); + } + + @override + Future> createView( + {required String appId, + required String name, + String? desc, + required ViewTypeIdentifier viewType}) { + return repo.createView(appId, name, desc ?? "", viewType); + } +} diff --git a/app_flowy/lib/home/presentation/widgets/menu/home_menu.dart b/app_flowy/lib/home/presentation/widgets/menu/home_menu.dart index d92e4436ec..3d9e4d45c5 100644 --- a/app_flowy/lib/home/presentation/widgets/menu/home_menu.dart +++ b/app_flowy/lib/home/presentation/widgets/menu/home_menu.dart @@ -57,8 +57,9 @@ class HomeMenu extends StatelessWidget { const MenuTopBar(), Expanded(child: Container()), NewAppButton( - createAppCallback: (appName) => - context.read().add(MenuEvent.createApp(appName)), + createAppCallback: (appName) => context + .read() + .add(MenuEvent.createApp(appName, desc: "")), ), ], ).padding(horizontal: Insets.sm), diff --git a/app_flowy/lib/startup/deps_inject/prelude.dart b/app_flowy/lib/startup/deps_inject/prelude.dart index 3811e93bd0..06f7f54a68 100644 --- a/app_flowy/lib/startup/deps_inject/prelude.dart +++ b/app_flowy/lib/startup/deps_inject/prelude.dart @@ -1,7 +1,8 @@ +import 'package:app_flowy/home/infrastructure/deps_resolver.dart'; import 'package:app_flowy/startup/launch.dart'; import 'package:app_flowy/startup/startup.dart'; -import 'package:app_flowy/user/infrastructure/interface_impl.dart'; -import 'package:app_flowy/welcome/infrastructure/interface_impl.dart'; +import 'package:app_flowy/user/infrastructure/deps_resolver.dart'; +import 'package:app_flowy/welcome/infrastructure/deps_resolver.dart'; import 'package:flowy_sdk/flowy_sdk.dart'; import 'package:get_it/get_it.dart'; @@ -16,4 +17,5 @@ Future initGetIt( await WelcomeDepsResolver.resolve(getIt); await UserDepsResolver.resolve(getIt); + await HomeDepsResolver.resolve(getIt); } diff --git a/app_flowy/lib/user/application/sign_in/sign_in_bloc.dart b/app_flowy/lib/user/application/sign_in/sign_in_bloc.dart index 08d8d71aac..c17bcadd1e 100644 --- a/app_flowy/lib/user/application/sign_in/sign_in_bloc.dart +++ b/app_flowy/lib/user/application/sign_in/sign_in_bloc.dart @@ -1,4 +1,4 @@ -import 'package:app_flowy/user/domain/interface.dart'; +import 'package:app_flowy/user/domain/i_auth.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; diff --git a/app_flowy/lib/user/domain/interface.dart b/app_flowy/lib/user/domain/i_auth.dart similarity index 100% rename from app_flowy/lib/user/domain/interface.dart rename to app_flowy/lib/user/domain/i_auth.dart diff --git a/app_flowy/lib/user/infrastructure/deps_resolver.dart b/app_flowy/lib/user/infrastructure/deps_resolver.dart new file mode 100644 index 0000000000..92df6eef03 --- /dev/null +++ b/app_flowy/lib/user/infrastructure/deps_resolver.dart @@ -0,0 +1,17 @@ +import 'package:app_flowy/user/application/sign_in/sign_in_bloc.dart'; +import 'package:app_flowy/user/domain/i_auth.dart'; +import 'package:app_flowy/user/infrastructure/repos/auth_repo.dart'; +import 'package:app_flowy/user/infrastructure/i_auth_impl.dart'; +import 'package:get_it/get_it.dart'; + +class UserDepsResolver { + static Future resolve(GetIt getIt) async { + getIt.registerLazySingleton(() => AuthRepository()); + + //Interface implementation + getIt.registerFactory(() => AuthImpl(repo: getIt())); + + //Bloc + getIt.registerFactory(() => SignInBloc(getIt())); + } +} diff --git a/app_flowy/lib/user/infrastructure/interface_impl.dart b/app_flowy/lib/user/infrastructure/i_auth_impl.dart similarity index 52% rename from app_flowy/lib/user/infrastructure/interface_impl.dart rename to app_flowy/lib/user/infrastructure/i_auth_impl.dart index f7ddd74da4..580637cdcf 100644 --- a/app_flowy/lib/user/infrastructure/interface_impl.dart +++ b/app_flowy/lib/user/infrastructure/i_auth_impl.dart @@ -1,22 +1,7 @@ -import 'package:app_flowy/user/application/sign_in/sign_in_bloc.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart'; -import 'package:get_it/get_it.dart'; - -import 'package:app_flowy/user/domain/interface.dart'; -import 'package:app_flowy/user/infrastructure/auth_repo.dart'; - -class UserDepsResolver { - static Future resolve(GetIt getIt) async { - getIt.registerLazySingleton(() => AuthRepository()); - - //Interface implementation - getIt.registerFactory(() => AuthImpl(repo: getIt())); - - //Bloc - getIt.registerFactory(() => SignInBloc(getIt())); - } -} +import 'package:app_flowy/user/domain/i_auth.dart'; +import 'package:app_flowy/user/infrastructure/repos/auth_repo.dart'; class AuthImpl extends IAuth { AuthRepository repo; diff --git a/app_flowy/lib/user/infrastructure/auth_repo.dart b/app_flowy/lib/user/infrastructure/repos/auth_repo.dart similarity index 100% rename from app_flowy/lib/user/infrastructure/auth_repo.dart rename to app_flowy/lib/user/infrastructure/repos/auth_repo.dart diff --git a/app_flowy/lib/welcome/application/welcome_bloc.dart b/app_flowy/lib/welcome/application/welcome_bloc.dart index b8bfe9efb8..39a142fd56 100644 --- a/app_flowy/lib/welcome/application/welcome_bloc.dart +++ b/app_flowy/lib/welcome/application/welcome_bloc.dart @@ -1,5 +1,5 @@ import 'package:app_flowy/welcome/domain/auth_state.dart'; -import 'package:app_flowy/welcome/domain/interface.dart'; +import 'package:app_flowy/welcome/domain/i_welcome.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; diff --git a/app_flowy/lib/welcome/domain/interface.dart b/app_flowy/lib/welcome/domain/i_welcome.dart similarity index 100% rename from app_flowy/lib/welcome/domain/interface.dart rename to app_flowy/lib/welcome/domain/i_welcome.dart diff --git a/app_flowy/lib/welcome/infrastructure/deps_resolver.dart b/app_flowy/lib/welcome/infrastructure/deps_resolver.dart new file mode 100644 index 0000000000..9ac3f0a0b7 --- /dev/null +++ b/app_flowy/lib/welcome/infrastructure/deps_resolver.dart @@ -0,0 +1,19 @@ +import 'package:app_flowy/home/application/edit_pannel/edit_pannel_bloc.dart'; +import 'package:app_flowy/home/application/home_bloc.dart'; +import 'package:app_flowy/home/application/watcher/home_watcher_bloc.dart'; +import 'package:app_flowy/welcome/application/welcome_bloc.dart'; +import 'package:app_flowy/welcome/infrastructure/i_welcome_impl.dart'; +import 'package:get_it/get_it.dart'; + +class WelcomeDepsResolver { + static Future resolve(GetIt getIt) async { + getIt.registerFactory(() => WelcomeAuthImpl()); + getIt.registerFactory(() => WelcomeRoute()); + getIt.registerFactory(() => HomeBloc()); + getIt.registerFactory(() => HomeWatcherBloc()); + getIt.registerFactory(() => EditPannelBloc()); + + getIt + .registerFactory(() => WelcomeBloc(getIt())); + } +} diff --git a/app_flowy/lib/welcome/infrastructure/interface_impl.dart b/app_flowy/lib/welcome/infrastructure/i_welcome_impl.dart similarity index 57% rename from app_flowy/lib/welcome/infrastructure/interface_impl.dart rename to app_flowy/lib/welcome/infrastructure/i_welcome_impl.dart index d060aff1e1..cf9c6882d9 100644 --- a/app_flowy/lib/welcome/infrastructure/interface_impl.dart +++ b/app_flowy/lib/welcome/infrastructure/i_welcome_impl.dart @@ -1,32 +1,16 @@ import 'package:app_flowy/home/application/edit_pannel/edit_pannel_bloc.dart'; import 'package:app_flowy/home/application/home_bloc.dart'; -import 'package:app_flowy/home/application/menu/menu_bloc.dart'; -import 'package:app_flowy/home/application/watcher/home_watcher_bloc.dart'; + import 'package:app_flowy/home/presentation/home_screen.dart'; import 'package:app_flowy/user/presentation/sign_in/sign_in_screen.dart'; -import 'package:app_flowy/welcome/application/welcome_bloc.dart'; import 'package:app_flowy/welcome/domain/auth_state.dart'; -import 'package:app_flowy/welcome/domain/interface.dart'; +import 'package:app_flowy/welcome/domain/i_welcome.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; -import 'package:get_it/get_it.dart'; -class WelcomeDepsResolver { - static Future resolve(GetIt getIt) async { - getIt.registerFactory(() => WelcomeAuthImpl()); - getIt.registerFactory(() => WelcomeRoute()); - getIt.registerFactory(() => HomeBloc()); - getIt.registerFactory(() => HomeWatcherBloc()); - getIt.registerFactory(() => EditPannelBloc()); - - getIt.registerFactory(() => MenuBloc()); - - getIt - .registerFactory(() => WelcomeBloc(getIt())); - } -} +export 'package:app_flowy/welcome/domain/i_welcome.dart'; class WelcomeAuthImpl implements IWelcomeAuth { @override diff --git a/app_flowy/lib/welcome/presentation/welcome_screen.dart b/app_flowy/lib/welcome/presentation/welcome_screen.dart index b4ef56cf4d..82fc4cfcfa 100644 --- a/app_flowy/lib/welcome/presentation/welcome_screen.dart +++ b/app_flowy/lib/welcome/presentation/welcome_screen.dart @@ -1,4 +1,4 @@ -import 'package:app_flowy/welcome/domain/interface.dart'; +import 'package:app_flowy/welcome/domain/i_welcome.dart'; import 'package:app_flowy/welcome/domain/auth_state.dart'; import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/welcome/application/welcome_bloc.dart'; diff --git a/app_flowy/packages/flowy_sdk/lib/ffi.dart b/app_flowy/packages/flowy_sdk/lib/ffi.dart index df3ff0de61..f794b4202c 100644 --- a/app_flowy/packages/flowy_sdk/lib/ffi.dart +++ b/app_flowy/packages/flowy_sdk/lib/ffi.dart @@ -80,6 +80,22 @@ typedef _init_sdk_Dart = int Function( Pointer path, ); + +/// C function `init_stream`. +int set_stream_port(int port) { + return _set_stream_port(port); +} + +final _set_stream_port_Dart _set_stream_port = +_dl.lookupFunction<_set_stream_port_C, _set_stream_port_Dart>('set_stream_port'); + +typedef _set_stream_port_C = Int32 Function( + Int64 port, + ); +typedef _set_stream_port_Dart = int Function( + int port, + ); + /// C function `link_me_please`. void link_me_please() { _link_me_please(); diff --git a/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart b/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart index 5ea973daa9..ff386f2bf7 100644 --- a/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart +++ b/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart @@ -1,6 +1,7 @@ export 'package:async/async.dart'; import 'dart:io'; import 'dart:async'; +import 'package:flowy_sdk/rust_stream.dart'; import 'package:flutter/services.dart'; import 'dart:ffi'; import 'ffi.dart' as ffi; @@ -18,6 +19,9 @@ class FlowySDK { void dispose() {} Future init(Directory sdkDir) async { + final port = RustStreamReceiver.shared.port; + ffi.set_stream_port(port); + ffi.store_dart_post_cobject(NativeApi.postCObject); ffi.init_sdk(sdkDir.path.toNativeUtf8()); } diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/protobuf.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/protobuf.dart new file mode 100644 index 0000000000..6f21b675f3 --- /dev/null +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/protobuf.dart @@ -0,0 +1,2 @@ +// Auto-generated, do not edit +export './subject.pb.dart'; diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pb.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pb.dart new file mode 100644 index 0000000000..fee3f5e319 --- /dev/null +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pb.dart @@ -0,0 +1,113 @@ +/// +// Generated code. Do not modify. +// source: subject.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +enum ObservableSubject_OneOfSubjectPayload { + subjectPayload, + notSet +} + +class ObservableSubject extends $pb.GeneratedMessage { + static const $core.Map<$core.int, ObservableSubject_OneOfSubjectPayload> _ObservableSubject_OneOfSubjectPayloadByTag = { + 4 : ObservableSubject_OneOfSubjectPayload.subjectPayload, + 0 : ObservableSubject_OneOfSubjectPayload.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ObservableSubject', createEmptyInstance: create) + ..oo(0, [4]) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'category') + ..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.O3) + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'subjectId') + ..a<$core.List<$core.int>>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'subjectPayload', $pb.PbFieldType.OY) + ..hasRequiredFields = false + ; + + ObservableSubject._() : super(); + factory ObservableSubject({ + $core.String? category, + $core.int? ty, + $core.String? subjectId, + $core.List<$core.int>? subjectPayload, + }) { + final _result = create(); + if (category != null) { + _result.category = category; + } + if (ty != null) { + _result.ty = ty; + } + if (subjectId != null) { + _result.subjectId = subjectId; + } + if (subjectPayload != null) { + _result.subjectPayload = subjectPayload; + } + return _result; + } + factory ObservableSubject.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory ObservableSubject.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') + ObservableSubject clone() => ObservableSubject()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + ObservableSubject copyWith(void Function(ObservableSubject) updates) => super.copyWith((message) => updates(message as ObservableSubject)) as ObservableSubject; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static ObservableSubject create() => ObservableSubject._(); + ObservableSubject createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static ObservableSubject getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static ObservableSubject? _defaultInstance; + + ObservableSubject_OneOfSubjectPayload whichOneOfSubjectPayload() => _ObservableSubject_OneOfSubjectPayloadByTag[$_whichOneof(0)]!; + void clearOneOfSubjectPayload() => clearField($_whichOneof(0)); + + @$pb.TagNumber(1) + $core.String get category => $_getSZ(0); + @$pb.TagNumber(1) + set category($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasCategory() => $_has(0); + @$pb.TagNumber(1) + void clearCategory() => clearField(1); + + @$pb.TagNumber(2) + $core.int get ty => $_getIZ(1); + @$pb.TagNumber(2) + set ty($core.int v) { $_setSignedInt32(1, v); } + @$pb.TagNumber(2) + $core.bool hasTy() => $_has(1); + @$pb.TagNumber(2) + void clearTy() => clearField(2); + + @$pb.TagNumber(3) + $core.String get subjectId => $_getSZ(2); + @$pb.TagNumber(3) + set subjectId($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasSubjectId() => $_has(2); + @$pb.TagNumber(3) + void clearSubjectId() => clearField(3); + + @$pb.TagNumber(4) + $core.List<$core.int> get subjectPayload => $_getN(3); + @$pb.TagNumber(4) + set subjectPayload($core.List<$core.int> v) { $_setBytes(3, v); } + @$pb.TagNumber(4) + $core.bool hasSubjectPayload() => $_has(3); + @$pb.TagNumber(4) + void clearSubjectPayload() => clearField(4); +} + diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pbenum.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pbenum.dart new file mode 100644 index 0000000000..7ae7ff12c2 --- /dev/null +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pbenum.dart @@ -0,0 +1,7 @@ +/// +// Generated code. Do not modify. +// source: subject.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pbjson.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pbjson.dart new file mode 100644 index 0000000000..d81e160f35 --- /dev/null +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pbjson.dart @@ -0,0 +1,26 @@ +/// +// Generated code. Do not modify. +// source: subject.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use observableSubjectDescriptor instead') +const ObservableSubject$json = const { + '1': 'ObservableSubject', + '2': const [ + const {'1': 'category', '3': 1, '4': 1, '5': 9, '10': 'category'}, + const {'1': 'ty', '3': 2, '4': 1, '5': 5, '10': 'ty'}, + const {'1': 'subject_id', '3': 3, '4': 1, '5': 9, '10': 'subjectId'}, + const {'1': 'subject_payload', '3': 4, '4': 1, '5': 12, '9': 0, '10': 'subjectPayload'}, + ], + '8': const [ + const {'1': 'one_of_subject_payload'}, + ], +}; + +/// Descriptor for `ObservableSubject`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List observableSubjectDescriptor = $convert.base64Decode('ChFPYnNlcnZhYmxlU3ViamVjdBIaCghjYXRlZ29yeRgBIAEoCVIIY2F0ZWdvcnkSDgoCdHkYAiABKAVSAnR5Eh0KCnN1YmplY3RfaWQYAyABKAlSCXN1YmplY3RJZBIpCg9zdWJqZWN0X3BheWxvYWQYBCABKAxIAFIOc3ViamVjdFBheWxvYWRCGAoWb25lX29mX3N1YmplY3RfcGF5bG9hZA=='); diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pbserver.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pbserver.dart new file mode 100644 index 0000000000..1e092ab75a --- /dev/null +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-observable/subject.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: subject.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'subject.pb.dart'; + diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pb.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pb.dart new file mode 100644 index 0000000000..f1a6d9fcdb --- /dev/null +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pb.dart @@ -0,0 +1,11 @@ +/// +// Generated code. Do not modify. +// source: observable.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +export 'observable.pbenum.dart'; + diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbenum.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbenum.dart new file mode 100644 index 0000000000..38e98519cd --- /dev/null +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbenum.dart @@ -0,0 +1,28 @@ +/// +// Generated code. Do not modify. +// source: observable.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +// ignore_for_file: UNDEFINED_SHOWN_NAME +import 'dart:core' as $core; +import 'package:protobuf/protobuf.dart' as $pb; + +class ObservableType extends $pb.ProtobufEnum { + static const ObservableType Unknown = ObservableType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown'); + static const ObservableType WorkspaceDidUpdate = ObservableType._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceDidUpdate'); + static const ObservableType AppDidUpdate = ObservableType._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppDidUpdate'); + + static const $core.List values = [ + Unknown, + WorkspaceDidUpdate, + AppDidUpdate, + ]; + + static final $core.Map<$core.int, ObservableType> _byValue = $pb.ProtobufEnum.initByValue(values); + static ObservableType? valueOf($core.int value) => _byValue[value]; + + const ObservableType._($core.int v, $core.String n) : super(v, n); +} + diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbjson.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbjson.dart new file mode 100644 index 0000000000..0b2b0d47f6 --- /dev/null +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbjson.dart @@ -0,0 +1,22 @@ +/// +// Generated code. Do not modify. +// source: observable.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use observableTypeDescriptor instead') +const ObservableType$json = const { + '1': 'ObservableType', + '2': const [ + const {'1': 'Unknown', '2': 0}, + const {'1': 'WorkspaceDidUpdate', '2': 10}, + const {'1': 'AppDidUpdate', '2': 11}, + ], +}; + +/// Descriptor for `ObservableType`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List observableTypeDescriptor = $convert.base64Decode('Cg5PYnNlcnZhYmxlVHlwZRILCgdVbmtub3duEAASFgoSV29ya3NwYWNlRGlkVXBkYXRlEAoSEAoMQXBwRGlkVXBkYXRlEAs='); diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbserver.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbserver.dart new file mode 100644 index 0000000000..d0e7d97b5d --- /dev/null +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/observable.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: observable.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'observable.pb.dart'; + diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/protobuf.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/protobuf.dart index b389c05394..6e005b8da3 100644 --- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/protobuf.dart +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/protobuf.dart @@ -1,5 +1,6 @@ // Auto-generated, do not edit export './app_query.pb.dart'; +export './observable.pb.dart'; export './errors.pb.dart'; export './workspace_update.pb.dart'; export './app_create.pb.dart'; diff --git a/app_flowy/packages/flowy_sdk/lib/rust_stream.dart b/app_flowy/packages/flowy_sdk/lib/rust_stream.dart new file mode 100644 index 0000000000..b812c59497 --- /dev/null +++ b/app_flowy/packages/flowy_sdk/lib/rust_stream.dart @@ -0,0 +1,54 @@ +import 'dart:isolate'; +import 'dart:async'; +import 'dart:typed_data'; +import 'dart:ffi'; +import 'package:flowy_infra/flowy_logger.dart'; +import 'protobuf/flowy-observable/subject.pb.dart'; + +typedef ObserverCallback = void Function(ObservableSubject observable); + +class RustStreamReceiver { + static RustStreamReceiver shared = RustStreamReceiver._internal(); + late RawReceivePort _ffiPort; + late StreamController _streamController; + late StreamController _observableController; + late StreamSubscription _ffiSubscription; + + int get port => _ffiPort.sendPort.nativePort; + StreamController get observable => _observableController; + + RustStreamReceiver._internal() { + _ffiPort = RawReceivePort(); + _streamController = StreamController(); + _observableController = StreamController.broadcast(); + + _ffiPort.handler = _streamController.add; + _ffiSubscription = _streamController.stream.listen(streamCallback); + } + + factory RustStreamReceiver() { + return shared; + } + + static listen(void Function(ObservableSubject subject) callback) { + RustStreamReceiver.shared.observable.stream.listen(callback); + } + + void streamCallback(Uint8List bytes) { + try { + final observable = ObservableSubject.fromBuffer(bytes); + _observableController.add(observable); + } catch (e, s) { + Log.error('RustStreamReceiver ObservableSubject deserialize error: ${e.runtimeType}'); + Log.error('Stack trace \n $s'); + rethrow; + } + } + + Future dispose() async { + await _ffiSubscription.cancel(); + await _streamController.close(); + await _observableController.close(); + _ffiPort.close(); + } +} diff --git a/app_flowy/packages/flowy_sdk/macos/Classes/binding.h b/app_flowy/packages/flowy_sdk/macos/Classes/binding.h index 0455d23a96..036d56aa2a 100644 --- a/app_flowy/packages/flowy_sdk/macos/Classes/binding.h +++ b/app_flowy/packages/flowy_sdk/macos/Classes/binding.h @@ -10,4 +10,6 @@ void async_command(int64_t port, const uint8_t *input, uintptr_t len); const uint8_t *sync_command(const uint8_t *input, uintptr_t len); +int32_t set_stream_port(int64_t port); + void link_me_please(void); \ No newline at end of file diff --git a/rust-lib/Cargo.toml b/rust-lib/Cargo.toml index 4085f5c52b..deef32c996 100644 --- a/rust-lib/Cargo.toml +++ b/rust-lib/Cargo.toml @@ -12,6 +12,7 @@ members = [ "flowy-database", "flowy-infra", "flowy-workspace", + "flowy-observable", ] [profile.dev] diff --git a/rust-lib/dart-ffi/Cargo.toml b/rust-lib/dart-ffi/Cargo.toml index 7373739538..fc345df327 100644 --- a/rust-lib/dart-ffi/Cargo.toml +++ b/rust-lib/dart-ffi/Cargo.toml @@ -28,6 +28,7 @@ serde_json = {version = "1.0"} flowy-dispatch = {path = "../flowy-dispatch"} flowy-sdk = {path = "../flowy-sdk"} flowy-derive = {path = "../flowy-derive"} +flowy-observable = {path = "../flowy-observable", features = ["dart"]} #[features] diff --git a/rust-lib/dart-ffi/binding.h b/rust-lib/dart-ffi/binding.h index 0455d23a96..036d56aa2a 100644 --- a/rust-lib/dart-ffi/binding.h +++ b/rust-lib/dart-ffi/binding.h @@ -10,4 +10,6 @@ void async_command(int64_t port, const uint8_t *input, uintptr_t len); const uint8_t *sync_command(const uint8_t *input, uintptr_t len); +int32_t set_stream_port(int64_t port); + void link_me_please(void); \ No newline at end of file diff --git a/rust-lib/dart-ffi/src/lib.rs b/rust-lib/dart-ffi/src/lib.rs index 5c7f0b28c0..aaaba4d12a 100644 --- a/rust-lib/dart-ffi/src/lib.rs +++ b/rust-lib/dart-ffi/src/lib.rs @@ -12,14 +12,6 @@ use flowy_sdk::*; use lazy_static::lazy_static; use std::{ffi::CStr, os::raw::c_char}; -lazy_static! { - pub static ref FFI_RUNTIME: tokio::runtime::Runtime = - tokio::runtime::Builder::new_current_thread() - .thread_name("flowy-dart-ffi") - .build() - .unwrap(); -} - #[no_mangle] pub extern "C" fn init_sdk(path: *mut c_char) -> i64 { let c_str: &CStr = unsafe { CStr::from_ptr(path) }; @@ -58,6 +50,12 @@ pub extern "C" fn sync_command(input: *const u8, len: usize) -> *const u8 { forget_rust(result) } +#[no_mangle] +pub extern "C" fn set_stream_port(port: i64) -> i32 { + flowy_observable::dart::RustStreamSender::set_port(port); + return 0; +} + #[inline(never)] #[no_mangle] pub extern "C" fn link_me_please() {} diff --git a/rust-lib/flowy-derive/src/derive_cache/derive_cache.rs b/rust-lib/flowy-derive/src/derive_cache/derive_cache.rs index c44fb15c44..1448fc51c5 100644 --- a/rust-lib/flowy-derive/src/derive_cache/derive_cache.rs +++ b/rust-lib/flowy-derive/src/derive_cache/derive_cache.rs @@ -15,7 +15,8 @@ pub fn category_from_str(type_str: &str) -> TypeCategory { "HashMap" => TypeCategory::Map, "u8" => TypeCategory::Bytes, "String" => TypeCategory::Str, - "KeyValue" + "ObservableSubject" + | "KeyValue" | "QueryAppRequest" | "CreateAppRequest" | "ColorStyle" @@ -45,6 +46,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory { "ViewTypeIdentifier" | "WorkspaceEvent" | "WorkspaceErrorCode" + | "ObservableType" | "FFIStatusCode" | "UserStatus" | "UserEvent" diff --git a/rust-lib/flowy-derive/src/proto_buf/deserialize.rs b/rust-lib/flowy-derive/src/proto_buf/deserialize.rs index 15cb2db2f6..f1ef12a705 100644 --- a/rust-lib/flowy-derive/src/proto_buf/deserialize.rs +++ b/rust-lib/flowy-derive/src/proto_buf/deserialize.rs @@ -86,6 +86,15 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option } }) }, + TypeCategory::Array => { + let take_func = format_ident!("take_{}", ident.to_string()); + let ty = bracketed_ty_info.unwrap().ty; + Some(quote! { + if pb.#has_func() { + o.#member=Some(pb.#take_func()); + } + }) + }, _ => { let take_func = format_ident!("take_{}", ident.to_string()); let ty = bracketed_ty_info.unwrap().ty; diff --git a/rust-lib/flowy-observable/Cargo.toml b/rust-lib/flowy-observable/Cargo.toml new file mode 100644 index 0000000000..0fca6d8391 --- /dev/null +++ b/rust-lib/flowy-observable/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "flowy-observable" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +lazy_static = {version = "1.4.0"} +protobuf = {version = "2.20.0"} +allo-isolate = {version = "^0.1", features = ["catch-unwind",]} +log = "0.4.14" + +flowy-derive = {path = "../flowy-derive"} + +[features] +dart = [] \ No newline at end of file diff --git a/rust-lib/flowy-observable/Flowy.toml b/rust-lib/flowy-observable/Flowy.toml new file mode 100644 index 0000000000..93f30162a8 --- /dev/null +++ b/rust-lib/flowy-observable/Flowy.toml @@ -0,0 +1,3 @@ + +proto_crates = ["src/entities"] +event_files = [""] \ No newline at end of file diff --git a/rust-lib/flowy-observable/src/dart/mod.rs b/rust-lib/flowy-observable/src/dart/mod.rs new file mode 100644 index 0000000000..b58f792ae6 --- /dev/null +++ b/rust-lib/flowy-observable/src/dart/mod.rs @@ -0,0 +1,3 @@ +mod stream_sender; + +pub use stream_sender::*; diff --git a/rust-lib/flowy-observable/src/dart/stream_sender.rs b/rust-lib/flowy-observable/src/dart/stream_sender.rs new file mode 100644 index 0000000000..8640775020 --- /dev/null +++ b/rust-lib/flowy-observable/src/dart/stream_sender.rs @@ -0,0 +1,52 @@ +use crate::entities::ObservableSubject; +use lazy_static::lazy_static; +use std::{convert::TryInto, sync::RwLock}; + +lazy_static! { + static ref R2F_STREAM_SENDER: RwLock = RwLock::new(RustStreamSender::new()); +} + +pub struct RustStreamSender { + isolate: Option, +} + +impl RustStreamSender { + fn new() -> Self { Self { isolate: None } } + + fn inner_set_port(&mut self, port: i64) { + log::debug!("Setup rust to flutter stream with port {}", port); + self.isolate = Some(allo_isolate::Isolate::new(port)); + } + + fn inner_post(&self, observable_subject: ObservableSubject) -> Result<(), String> { + match self.isolate { + Some(ref isolate) => { + let bytes: Vec = observable_subject.try_into().unwrap(); + isolate.post(bytes); + Ok(()) + }, + None => Err("Isolate is not set".to_owned()), + } + } + + pub fn set_port(port: i64) { + match R2F_STREAM_SENDER.write() { + Ok(mut stream) => stream.inner_set_port(port), + Err(e) => { + let msg = format!("Get rust to flutter stream lock fail. {:?}", e); + log::error!("{:?}", msg); + }, + } + } + + pub fn post(observable_subject: ObservableSubject) -> Result<(), String> { + #[cfg(feature = "dart")] + match R2F_STREAM_SENDER.read() { + Ok(stream) => stream.inner_post(observable_subject), + Err(e) => Err(format!("Get rust to flutter stream lock fail. {:?}", e)), + } + + #[cfg(not(feature = "dart"))] + Ok(()) + } +} diff --git a/rust-lib/flowy-observable/src/entities/mod.rs b/rust-lib/flowy-observable/src/entities/mod.rs new file mode 100644 index 0000000000..c4512b93f5 --- /dev/null +++ b/rust-lib/flowy-observable/src/entities/mod.rs @@ -0,0 +1,3 @@ +mod subject; + +pub use subject::*; diff --git a/rust-lib/flowy-observable/src/entities/subject.rs b/rust-lib/flowy-observable/src/entities/subject.rs new file mode 100644 index 0000000000..c1a2b6d67c --- /dev/null +++ b/rust-lib/flowy-observable/src/entities/subject.rs @@ -0,0 +1,24 @@ +use flowy_derive::ProtoBuf; + +#[derive(Debug, Clone, ProtoBuf)] +pub struct ObservableSubject { + #[pb(index = 1)] + pub category: String, + + #[pb(index = 2)] + pub ty: i32, + + #[pb(index = 3)] + pub subject_id: String, + + #[pb(index = 4, one_of)] + pub subject_payload: Option>, +} + +impl std::default::Default for ObservableSubject { + fn default() -> Self { + Self { + ..Default::default() + } + } +} diff --git a/rust-lib/flowy-observable/src/lib.rs b/rust-lib/flowy-observable/src/lib.rs new file mode 100644 index 0000000000..f6ea0af380 --- /dev/null +++ b/rust-lib/flowy-observable/src/lib.rs @@ -0,0 +1,11 @@ +pub mod dart; +pub mod entities; +mod protobuf; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/rust-lib/flowy-observable/src/protobuf/mod.rs b/rust-lib/flowy-observable/src/protobuf/mod.rs new file mode 100644 index 0000000000..2480f62fbe --- /dev/null +++ b/rust-lib/flowy-observable/src/protobuf/mod.rs @@ -0,0 +1,4 @@ + +mod model; +pub use model::*; + \ No newline at end of file diff --git a/rust-lib/flowy-observable/src/protobuf/model/mod.rs b/rust-lib/flowy-observable/src/protobuf/model/mod.rs new file mode 100644 index 0000000000..ce50dd797d --- /dev/null +++ b/rust-lib/flowy-observable/src/protobuf/model/mod.rs @@ -0,0 +1,4 @@ +// Auto-generated, do not edit + +mod subject; +pub use subject::*; diff --git a/rust-lib/flowy-observable/src/protobuf/model/subject.rs b/rust-lib/flowy-observable/src/protobuf/model/subject.rs new file mode 100644 index 0000000000..7497b4001b --- /dev/null +++ b/rust-lib/flowy-observable/src/protobuf/model/subject.rs @@ -0,0 +1,376 @@ +// This file is generated by rust-protobuf 2.22.1. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `subject.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1; + +#[derive(PartialEq,Clone,Default)] +pub struct ObservableSubject { + // message fields + pub category: ::std::string::String, + pub ty: i32, + pub subject_id: ::std::string::String, + // message oneof groups + pub one_of_subject_payload: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a ObservableSubject { + fn default() -> &'a ObservableSubject { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum ObservableSubject_oneof_one_of_subject_payload { + subject_payload(::std::vec::Vec), +} + +impl ObservableSubject { + pub fn new() -> ObservableSubject { + ::std::default::Default::default() + } + + // string category = 1; + + + pub fn get_category(&self) -> &str { + &self.category + } + pub fn clear_category(&mut self) { + self.category.clear(); + } + + // Param is passed by value, moved + pub fn set_category(&mut self, v: ::std::string::String) { + self.category = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_category(&mut self) -> &mut ::std::string::String { + &mut self.category + } + + // Take field + pub fn take_category(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.category, ::std::string::String::new()) + } + + // int32 ty = 2; + + + pub fn get_ty(&self) -> i32 { + self.ty + } + pub fn clear_ty(&mut self) { + self.ty = 0; + } + + // Param is passed by value, moved + pub fn set_ty(&mut self, v: i32) { + self.ty = v; + } + + // string subject_id = 3; + + + pub fn get_subject_id(&self) -> &str { + &self.subject_id + } + pub fn clear_subject_id(&mut self) { + self.subject_id.clear(); + } + + // Param is passed by value, moved + pub fn set_subject_id(&mut self, v: ::std::string::String) { + self.subject_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_subject_id(&mut self) -> &mut ::std::string::String { + &mut self.subject_id + } + + // Take field + pub fn take_subject_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.subject_id, ::std::string::String::new()) + } + + // bytes subject_payload = 4; + + + pub fn get_subject_payload(&self) -> &[u8] { + match self.one_of_subject_payload { + ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(ref v)) => v, + _ => &[], + } + } + pub fn clear_subject_payload(&mut self) { + self.one_of_subject_payload = ::std::option::Option::None; + } + + pub fn has_subject_payload(&self) -> bool { + match self.one_of_subject_payload { + ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_subject_payload(&mut self, v: ::std::vec::Vec) { + self.one_of_subject_payload = ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(v)) + } + + // Mutable pointer to the field. + pub fn mut_subject_payload(&mut self) -> &mut ::std::vec::Vec { + if let ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(_)) = self.one_of_subject_payload { + } else { + self.one_of_subject_payload = ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(::std::vec::Vec::new())); + } + match self.one_of_subject_payload { + ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_subject_payload(&mut self) -> ::std::vec::Vec { + if self.has_subject_payload() { + match self.one_of_subject_payload.take() { + ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(v)) => v, + _ => panic!(), + } + } else { + ::std::vec::Vec::new() + } + } +} + +impl ::protobuf::Message for ObservableSubject { + 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_singular_proto3_string_into(wire_type, is, &mut self.category)?; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int32()?; + self.ty = tmp; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.subject_id)?; + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_subject_payload = ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(is.read_bytes()?)); + }, + _ => { + ::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.category.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.category); + } + if self.ty != 0 { + my_size += ::protobuf::rt::value_size(2, self.ty, ::protobuf::wire_format::WireTypeVarint); + } + if !self.subject_id.is_empty() { + my_size += ::protobuf::rt::string_size(3, &self.subject_id); + } + if let ::std::option::Option::Some(ref v) = self.one_of_subject_payload { + match v { + &ObservableSubject_oneof_one_of_subject_payload::subject_payload(ref v) => { + my_size += ::protobuf::rt::bytes_size(4, &v); + }, + }; + } + 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.category.is_empty() { + os.write_string(1, &self.category)?; + } + if self.ty != 0 { + os.write_int32(2, self.ty)?; + } + if !self.subject_id.is_empty() { + os.write_string(3, &self.subject_id)?; + } + if let ::std::option::Option::Some(ref v) = self.one_of_subject_payload { + match v { + &ObservableSubject_oneof_one_of_subject_payload::subject_payload(ref v) => { + os.write_bytes(4, v)?; + }, + }; + } + 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) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> ObservableSubject { + ObservableSubject::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::ProtobufTypeString>( + "category", + |m: &ObservableSubject| { &m.category }, + |m: &mut ObservableSubject| { &mut m.category }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( + "ty", + |m: &ObservableSubject| { &m.ty }, + |m: &mut ObservableSubject| { &mut m.ty }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "subject_id", + |m: &ObservableSubject| { &m.subject_id }, + |m: &mut ObservableSubject| { &mut m.subject_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor::<_>( + "subject_payload", + ObservableSubject::has_subject_payload, + ObservableSubject::get_subject_payload, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "ObservableSubject", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static ObservableSubject { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(ObservableSubject::new) + } +} + +impl ::protobuf::Clear for ObservableSubject { + fn clear(&mut self) { + self.category.clear(); + self.ty = 0; + self.subject_id.clear(); + self.one_of_subject_payload = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for ObservableSubject { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for ObservableSubject { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\rsubject.proto\"\xa3\x01\n\x11ObservableSubject\x12\x1a\n\x08category\ + \x18\x01\x20\x01(\tR\x08category\x12\x0e\n\x02ty\x18\x02\x20\x01(\x05R\ + \x02ty\x12\x1d\n\nsubject_id\x18\x03\x20\x01(\tR\tsubjectId\x12)\n\x0fsu\ + bject_payload\x18\x04\x20\x01(\x0cH\0R\x0esubjectPayloadB\x18\n\x16one_o\ + f_subject_payloadJ\xa1\x02\n\x06\x12\x04\0\0\x07\x01\n\x08\n\x01\x0c\x12\ + \x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x07\x01\n\n\n\x03\x04\0\x01\ + \x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x18\n\x0c\n\ + \x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\ + \x03\x03\x0b\x13\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x16\x17\n\x0b\n\ + \x04\x04\0\x02\x01\x12\x03\x04\x04\x11\n\x0c\n\x05\x04\0\x02\x01\x05\x12\ + \x03\x04\x04\t\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\n\x0c\n\x0c\n\ + \x05\x04\0\x02\x01\x03\x12\x03\x04\x0f\x10\n\x0b\n\x04\x04\0\x02\x02\x12\ + \x03\x05\x04\x1a\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\n\n\x0c\n\ + \x05\x04\0\x02\x02\x01\x12\x03\x05\x0b\x15\n\x0c\n\x05\x04\0\x02\x02\x03\ + \x12\x03\x05\x18\x19\n\x0b\n\x04\x04\0\x08\0\x12\x03\x06\x04?\n\x0c\n\ + \x05\x04\0\x08\0\x01\x12\x03\x06\n\x20\n\x0b\n\x04\x04\0\x02\x03\x12\x03\ + \x06#=\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\x06#(\n\x0c\n\x05\x04\0\x02\ + \x03\x01\x12\x03\x06)8\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06; = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/rust-lib/flowy-observable/src/protobuf/proto/subject.proto b/rust-lib/flowy-observable/src/protobuf/proto/subject.proto new file mode 100644 index 0000000000..97efe0d9c2 --- /dev/null +++ b/rust-lib/flowy-observable/src/protobuf/proto/subject.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +message ObservableSubject { + string category = 1; + int32 ty = 2; + string subject_id = 3; + oneof one_of_subject_payload { bytes subject_payload = 4; }; +} diff --git a/rust-lib/flowy-workspace/Cargo.toml b/rust-lib/flowy-workspace/Cargo.toml index 80d1790964..8a96786393 100644 --- a/rust-lib/flowy-workspace/Cargo.toml +++ b/rust-lib/flowy-workspace/Cargo.toml @@ -12,6 +12,7 @@ flowy-derive = { path = "../flowy-derive" } flowy-database = { path = "../flowy-database" } flowy-sqlite = { path = "../flowy-sqlite" } flowy-infra = { path = "../flowy-infra" } +flowy-observable = { path = "../flowy-observable" } protobuf = {version = "2.18.0"} log = "0.4.14" diesel = {version = "1.4.7", features = ["sqlite"]} diff --git a/rust-lib/flowy-workspace/Flowy.toml b/rust-lib/flowy-workspace/Flowy.toml index 728e5eb776..f66326779a 100644 --- a/rust-lib/flowy-workspace/Flowy.toml +++ b/rust-lib/flowy-workspace/Flowy.toml @@ -1,3 +1,3 @@ -proto_crates = ["src/entities", "src/event.rs", "src/errors.rs"] +proto_crates = ["src/entities", "src/event.rs", "src/errors.rs", "src/observable"] event_files = ["src/event.rs"] \ No newline at end of file diff --git a/rust-lib/flowy-workspace/src/lib.rs b/rust-lib/flowy-workspace/src/lib.rs index 111c190399..c24d413009 100644 --- a/rust-lib/flowy-workspace/src/lib.rs +++ b/rust-lib/flowy-workspace/src/lib.rs @@ -7,6 +7,7 @@ mod sql_tables; #[macro_use] mod macros; +mod observable; mod protobuf; mod services; diff --git a/rust-lib/flowy-workspace/src/observable/mod.rs b/rust-lib/flowy-workspace/src/observable/mod.rs new file mode 100644 index 0000000000..66a2058d79 --- /dev/null +++ b/rust-lib/flowy-workspace/src/observable/mod.rs @@ -0,0 +1,3 @@ +mod observable; + +pub use observable::*; diff --git a/rust-lib/flowy-workspace/src/observable/observable.rs b/rust-lib/flowy-workspace/src/observable/observable.rs new file mode 100644 index 0000000000..91b299da1e --- /dev/null +++ b/rust-lib/flowy-workspace/src/observable/observable.rs @@ -0,0 +1,71 @@ +use flowy_derive::ProtoBuf_Enum; +use flowy_dispatch::prelude::ToBytes; +use flowy_observable::{dart::RustStreamSender, entities::ObservableSubject}; +const OBSERVABLE_CATEGORY: &'static str = "Workspace"; + +#[derive(ProtoBuf_Enum, Debug)] +pub(crate) enum ObservableType { + Unknown = 0, + + WorkspaceDidUpdate = 10, + AppDidUpdate = 11, +} + +impl std::default::Default for ObservableType { + fn default() -> Self { ObservableType::Unknown } +} + +pub(crate) struct ObservableSender { + ty: ObservableType, + subject_id: String, + payload: Option>, +} + +impl ObservableSender { + pub(crate) fn new(subject_id: &str, ty: ObservableType) -> Self { + Self { + subject_id: subject_id.to_owned(), + ty, + payload: None, + } + } + + pub(crate) fn payload(mut self, payload: T) -> Self + where + T: ToBytes, + { + let bytes = payload.into_bytes().unwrap(); + self.payload = Some(bytes); + self + } + + pub(crate) fn send(self) { + log::debug!( + "Workspace observable id: {}, ty: {:?}", + self.subject_id, + self.ty + ); + + let subject = ObservableSubject { + category: OBSERVABLE_CATEGORY.to_string(), + ty: self.ty as i32, + subject_id: self.subject_id, + subject_payload: self.payload, + }; + match RustStreamSender::post(subject) { + Ok(_) => {}, + Err(error) => log::error!("Send observable subject failed: {}", error), + } + } +} + +pub(crate) fn send_observable(id: &str, ty: ObservableType) { + ObservableSender::new(id, ty).send(); +} + +pub(crate) fn send_observable_with_payload(id: &str, ty: ObservableType, payload: T) +where + T: ToBytes, +{ + ObservableSender::new(id, ty).payload(payload).send(); +} diff --git a/rust-lib/flowy-workspace/src/protobuf/model/mod.rs b/rust-lib/flowy-workspace/src/protobuf/model/mod.rs index 5d7f7711fa..951d9d1a1f 100644 --- a/rust-lib/flowy-workspace/src/protobuf/model/mod.rs +++ b/rust-lib/flowy-workspace/src/protobuf/model/mod.rs @@ -3,6 +3,9 @@ mod app_query; pub use app_query::*; +mod observable; +pub use observable::*; + mod errors; pub use errors::*; diff --git a/rust-lib/flowy-workspace/src/protobuf/model/observable.rs b/rust-lib/flowy-workspace/src/protobuf/model/observable.rs new file mode 100644 index 0000000000..c98bdffa4c --- /dev/null +++ b/rust-lib/flowy-workspace/src/protobuf/model/observable.rs @@ -0,0 +1,103 @@ +// This file is generated by rust-protobuf 2.22.1. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `observable.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1; + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum ObservableType { + Unknown = 0, + WorkspaceDidUpdate = 10, + AppDidUpdate = 11, +} + +impl ::protobuf::ProtobufEnum for ObservableType { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(ObservableType::Unknown), + 10 => ::std::option::Option::Some(ObservableType::WorkspaceDidUpdate), + 11 => ::std::option::Option::Some(ObservableType::AppDidUpdate), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [ObservableType] = &[ + ObservableType::Unknown, + ObservableType::WorkspaceDidUpdate, + ObservableType::AppDidUpdate, + ]; + 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::("ObservableType", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for ObservableType { +} + +impl ::std::default::Default for ObservableType { + fn default() -> Self { + ObservableType::Unknown + } +} + +impl ::protobuf::reflect::ProtobufValue for ObservableType { + 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*G\n\x0eObservableType\x12\x0b\n\x07Unknown\x10\0\ + \x12\x16\n\x12WorkspaceDidUpdate\x10\n\x12\x10\n\x0cAppDidUpdate\x10\x0b\ + J\xa5\x01\n\x06\x12\x04\0\0\x06\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\ + \n\x02\x05\0\x12\x04\x02\0\x06\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\ + \x13\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\x1c\n\x0c\n\x05\x05\0\x02\x01\ + \x01\x12\x03\x04\x04\x16\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\x19\ + \x1b\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x16\n\x0c\n\x05\x05\0\x02\ + \x02\x01\x12\x03\x05\x04\x10\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\ + \x13\x15b\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/rust-lib/flowy-workspace/src/protobuf/proto/observable.proto b/rust-lib/flowy-workspace/src/protobuf/proto/observable.proto new file mode 100644 index 0000000000..3100feddbd --- /dev/null +++ b/rust-lib/flowy-workspace/src/protobuf/proto/observable.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +enum ObservableType { + Unknown = 0; + WorkspaceDidUpdate = 10; + AppDidUpdate = 11; +} diff --git a/rust-lib/flowy-workspace/src/services/app_controller.rs b/rust-lib/flowy-workspace/src/services/app_controller.rs index 0bb220a396..10a9352b03 100644 --- a/rust-lib/flowy-workspace/src/services/app_controller.rs +++ b/rust-lib/flowy-workspace/src/services/app_controller.rs @@ -5,6 +5,7 @@ use crate::{ }, errors::*, module::{WorkspaceDatabase, WorkspaceUser}, + observable::*, services::ViewController, sql_tables::app::{AppTable, AppTableChangeset, AppTableSql}, }; @@ -35,7 +36,7 @@ impl AppController { let app_table = AppTable::new(params); let app: App = app_table.clone().into(); let _ = self.sql.write_app_table(app_table)?; - + send_observable(&app.workspace_id, ObservableType::WorkspaceDidUpdate); Ok(app) } @@ -46,7 +47,9 @@ impl AppController { pub fn update_app(&self, params: UpdateAppParams) -> Result<(), WorkspaceError> { let changeset = AppTableChangeset::new(params); + let app_id = changeset.id.clone(); let _ = self.sql.update_app_table(changeset)?; + send_observable(&app_id, ObservableType::AppDidUpdate); Ok(()) } diff --git a/rust-lib/flowy-workspace/src/services/mod.rs b/rust-lib/flowy-workspace/src/services/mod.rs index 35c19c299e..d043703c3d 100644 --- a/rust-lib/flowy-workspace/src/services/mod.rs +++ b/rust-lib/flowy-workspace/src/services/mod.rs @@ -1,9 +1,9 @@ +pub use app_controller::*; +pub use view_controller::*; +pub use workspace_controller::*; + mod app_controller; mod database; mod helper; mod view_controller; mod workspace_controller; - -pub use app_controller::*; -pub use view_controller::*; -pub use workspace_controller::*; diff --git a/scripts/flowy-tool/src/proto/template/proto_file/struct_template.rs b/scripts/flowy-tool/src/proto/template/proto_file/struct_template.rs index 9037ff0b38..1d06a16a51 100644 --- a/scripts/flowy-tool/src/proto/template/proto_file/struct_template.rs +++ b/scripts/flowy-tool/src/proto/template/proto_file/struct_template.rs @@ -1,6 +1,7 @@ use crate::util::get_tera; use flowy_ast::*; use phf::phf_map; +use syn::__private::quote::__private::Ident; use tera::Context; // Protobuf data type : https://developers.google.com/protocol-buffers/docs/proto3 @@ -47,10 +48,24 @@ impl StructTemplate { match field.bracket_category { Some(ref category) => match category { - BracketCategory::Opt => self.fields.push(format!( - "oneof one_of_{} {{ {} {} = {}; }};", - name, mapped_ty, name, index - )), + BracketCategory::Opt => match &field.bracket_inner_ty { + None => {} + Some(inner_ty) => match inner_ty.to_string().as_str() { + //TODO: support hashmap or something else wrapped by Option + "Vec" => { + self.fields.push(format!( + "oneof one_of_{} {{ bytes {} = {}; }};", + name, name, index + )); + } + _ => { + self.fields.push(format!( + "oneof one_of_{} {{ {} {} = {}; }};", + name, mapped_ty, name, index + )); + } + }, + }, BracketCategory::Map((k, v)) => { let key: &str = k; let value: &str = v; @@ -65,6 +80,7 @@ impl StructTemplate { } BracketCategory::Vec => { let bracket_ty: &str = &field.bracket_ty.as_ref().unwrap().to_string(); + // Vec if mapped_ty == "u8" && bracket_ty == "Vec" { self.fields.push(format!("bytes {} = {};", name, index)) } else { diff --git a/scripts/makefile/desktop.toml b/scripts/makefile/desktop.toml index 173db6a9a2..5c9aea45e9 100644 --- a/scripts/makefile/desktop.toml +++ b/scripts/makefile/desktop.toml @@ -34,7 +34,7 @@ condition = { platforms = ["mac"] } dependencies = ["restore-crate-type"] script = [ """ - echo "🚀 🚀 🚀 Copy Flowy-SDK to flutter" + echo "🚀 🚀 🚀 Flowy-SDK build success" cp ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/target/x86_64-apple-darwin/${LIB_OUT_DIR}/lib${CARGO_MAKE_CRATE_FS_NAME}.dylib \ ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/packages/flowy_sdk/macos/lib${CARGO_MAKE_CRATE_FS_NAME}.dylib """,