merge master

This commit is contained in:
Jaylen Bian 2021-07-28 17:42:27 +08:00
commit cc17529977
154 changed files with 3249 additions and 1416 deletions

View File

@ -10,7 +10,7 @@ CARGO_MAKE_CRATE_NAME = "dart-ffi"
DEV = true
LIB_OUT_DIR = "debug"
RELEASE = false
TARGET_OS = "unknown"
#TARGET_OS = "unknown"
[tasks.setup-crate-type]
private = true

View File

@ -9,7 +9,8 @@
"request": "launch",
"program": "${workspaceRoot}/lib/main.dart",
"type": "dart",
// "preLaunchTask": "build rust sdk"
"preLaunchTask": "build_flowy_sdk",
"cwd": "${workspaceRoot}"
},
{
"name": "app_flowy (profile mode)",

View File

@ -1,8 +1,6 @@
{
"version": "2.0.0",
"tasks": [
{
// https://code.visualstudio.com/docs/editor/tasks
// https://code.visualstudio.com/docs/editor/tasks
//https://gist.github.com/deadalusai/9e13e36d61ec7fb72148
// ${workspaceRoot}: the root folder of the team
@ -11,9 +9,22 @@
// ${fileDirname}: the current opened file's dirname
// ${fileExtname}: the current opened file's extension
// ${cwd}: the current working directory of the spawned process
"tasks": [
{
"type": "shell",
"command": "sh ${workspaceFolder}/../scripts/build_sdk.sh",
"command": "sh ./scripts/build_sdk.sh",
"group": "build",
"options": {
"cwd": "${workspaceFolder}/../"
},
// "problemMatcher": [
// "$rustc"
// ],
"label": "build_flowy_sdk"
},
{
"type": "shell",
"command": "sh ./scripts/code_gen.sh",
"group": "build",
"options": {
"cwd": "${workspaceFolder}/../"
@ -21,7 +32,7 @@
"problemMatcher": [
"$rustc"
],
"label": "build rust sdk"
"label": "generate events"
}
]
}

View File

@ -15,7 +15,7 @@ analyzer:
- "**/*.g.dart"
- "**/*.freezed.dart"
- "packages/flowy_editor/**"
- "packages/flowy_infra_ui/**"
# - "packages/flowy_infra_ui/**"
linter:
# The lint rules applied to this project can be customized in the

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -15,7 +15,7 @@ Future<void> initGetIt(
getIt.registerLazySingleton<FlowySDK>(() => const FlowySDK());
getIt.registerLazySingleton<AppLauncher>(() => AppLauncher(env, getIt));
await WelcomeDepsResolver.resolve(getIt);
await UserDepsResolver.resolve(getIt);
await WelcomeDepsResolver.resolve(getIt);
await HomeDepsResolver.resolve(getIt);
}

View File

@ -40,7 +40,7 @@ class ApplicationBlocObserver extends BlocObserver {
@override
// ignore: unnecessary_overrides
void onTransition(Bloc bloc, Transition transition) {
// Log.debug(transition);
Log.debug(transition);
super.onTransition(bloc, transition);
}
@ -50,9 +50,3 @@ class ApplicationBlocObserver extends BlocObserver {
super.onError(bloc, error, stackTrace);
}
}
class EngineBlocConfig {
static void setup() {
Bloc.observer = ApplicationBlocObserver();
}
}

View File

@ -22,10 +22,10 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
);
},
emailChanged: (EmailChanged value) async* {
yield state.copyWith(email: value.email, signInFailure: none());
yield state.copyWith(email: value.email, successOrFail: none());
},
passwordChanged: (PasswordChanged value) async* {
yield state.copyWith(password: value.password, signInFailure: none());
yield state.copyWith(password: value.password, successOrFail: none());
},
);
}
@ -36,17 +36,34 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
final result = await authImpl.signIn(state.email, state.password);
yield result.fold(
(userDetail) => state.copyWith(
isSubmitting: false, signInFailure: some(left(userDetail))),
(s) => state.copyWith(isSubmitting: false, signInFailure: some(right(s))),
isSubmitting: false, successOrFail: some(left(userDetail))),
(error) => stateFromCode(error),
);
}
SignInState stateFromCode(UserError error) {
switch (error.code) {
case UserErrCode.EmailInvalid:
return state.copyWith(
isSubmitting: false,
emailError: some(error.msg),
passwordError: none());
case UserErrCode.PasswordInvalid:
return state.copyWith(
isSubmitting: false,
passwordError: some(error.msg),
emailError: none());
default:
return state.copyWith(
isSubmitting: false, successOrFail: some(right(error)));
}
}
}
@freezed
abstract class SignInEvent with _$SignInEvent {
const factory SignInEvent.signedInWithUserEmailAndPassword() =
SignedInWithUserEmailAndPassword;
const factory SignInEvent.emailChanged(String email) = EmailChanged;
const factory SignInEvent.passwordChanged(String password) = PasswordChanged;
}
@ -57,11 +74,15 @@ abstract class SignInState with _$SignInState {
String? email,
String? password,
required bool isSubmitting,
required Option<Either<UserDetail, UserError>> signInFailure,
required Option<String> passwordError,
required Option<String> emailError,
required Option<Either<UserDetail, UserError>> successOrFail,
}) = _SignInState;
factory SignInState.initial() => SignInState(
isSubmitting: false,
signInFailure: none(),
passwordError: none(),
emailError: none(),
successOrFail: none(),
);
}

View File

@ -438,12 +438,16 @@ class _$SignInStateTearOff {
{String? email,
String? password,
required bool isSubmitting,
required Option<Either<UserDetail, UserError>> signInFailure}) {
required Option<String> passwordError,
required Option<String> emailError,
required Option<Either<UserDetail, UserError>> successOrFail}) {
return _SignInState(
email: email,
password: password,
isSubmitting: isSubmitting,
signInFailure: signInFailure,
passwordError: passwordError,
emailError: emailError,
successOrFail: successOrFail,
);
}
}
@ -456,7 +460,9 @@ mixin _$SignInState {
String? get email => throw _privateConstructorUsedError;
String? get password => throw _privateConstructorUsedError;
bool get isSubmitting => throw _privateConstructorUsedError;
Option<Either<UserDetail, UserError>> get signInFailure =>
Option<String> get passwordError => throw _privateConstructorUsedError;
Option<String> get emailError => throw _privateConstructorUsedError;
Option<Either<UserDetail, UserError>> get successOrFail =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true)
@ -473,7 +479,9 @@ abstract class $SignInStateCopyWith<$Res> {
{String? email,
String? password,
bool isSubmitting,
Option<Either<UserDetail, UserError>> signInFailure});
Option<String> passwordError,
Option<String> emailError,
Option<Either<UserDetail, UserError>> successOrFail});
}
/// @nodoc
@ -489,7 +497,9 @@ class _$SignInStateCopyWithImpl<$Res> implements $SignInStateCopyWith<$Res> {
Object? email = freezed,
Object? password = freezed,
Object? isSubmitting = freezed,
Object? signInFailure = freezed,
Object? passwordError = freezed,
Object? emailError = freezed,
Object? successOrFail = freezed,
}) {
return _then(_value.copyWith(
email: email == freezed
@ -504,9 +514,17 @@ class _$SignInStateCopyWithImpl<$Res> implements $SignInStateCopyWith<$Res> {
? _value.isSubmitting
: isSubmitting // ignore: cast_nullable_to_non_nullable
as bool,
signInFailure: signInFailure == freezed
? _value.signInFailure
: signInFailure // ignore: cast_nullable_to_non_nullable
passwordError: passwordError == freezed
? _value.passwordError
: passwordError // ignore: cast_nullable_to_non_nullable
as Option<String>,
emailError: emailError == freezed
? _value.emailError
: emailError // ignore: cast_nullable_to_non_nullable
as Option<String>,
successOrFail: successOrFail == freezed
? _value.successOrFail
: successOrFail // ignore: cast_nullable_to_non_nullable
as Option<Either<UserDetail, UserError>>,
));
}
@ -523,7 +541,9 @@ abstract class _$SignInStateCopyWith<$Res>
{String? email,
String? password,
bool isSubmitting,
Option<Either<UserDetail, UserError>> signInFailure});
Option<String> passwordError,
Option<String> emailError,
Option<Either<UserDetail, UserError>> successOrFail});
}
/// @nodoc
@ -541,7 +561,9 @@ class __$SignInStateCopyWithImpl<$Res> extends _$SignInStateCopyWithImpl<$Res>
Object? email = freezed,
Object? password = freezed,
Object? isSubmitting = freezed,
Object? signInFailure = freezed,
Object? passwordError = freezed,
Object? emailError = freezed,
Object? successOrFail = freezed,
}) {
return _then(_SignInState(
email: email == freezed
@ -556,9 +578,17 @@ class __$SignInStateCopyWithImpl<$Res> extends _$SignInStateCopyWithImpl<$Res>
? _value.isSubmitting
: isSubmitting // ignore: cast_nullable_to_non_nullable
as bool,
signInFailure: signInFailure == freezed
? _value.signInFailure
: signInFailure // ignore: cast_nullable_to_non_nullable
passwordError: passwordError == freezed
? _value.passwordError
: passwordError // ignore: cast_nullable_to_non_nullable
as Option<String>,
emailError: emailError == freezed
? _value.emailError
: emailError // ignore: cast_nullable_to_non_nullable
as Option<String>,
successOrFail: successOrFail == freezed
? _value.successOrFail
: successOrFail // ignore: cast_nullable_to_non_nullable
as Option<Either<UserDetail, UserError>>,
));
}
@ -571,7 +601,9 @@ class _$_SignInState implements _SignInState {
{this.email,
this.password,
required this.isSubmitting,
required this.signInFailure});
required this.passwordError,
required this.emailError,
required this.successOrFail});
@override
final String? email;
@ -580,11 +612,15 @@ class _$_SignInState implements _SignInState {
@override
final bool isSubmitting;
@override
final Option<Either<UserDetail, UserError>> signInFailure;
final Option<String> passwordError;
@override
final Option<String> emailError;
@override
final Option<Either<UserDetail, UserError>> successOrFail;
@override
String toString() {
return 'SignInState(email: $email, password: $password, isSubmitting: $isSubmitting, signInFailure: $signInFailure)';
return 'SignInState(email: $email, password: $password, isSubmitting: $isSubmitting, passwordError: $passwordError, emailError: $emailError, successOrFail: $successOrFail)';
}
@override
@ -599,9 +635,15 @@ class _$_SignInState implements _SignInState {
(identical(other.isSubmitting, isSubmitting) ||
const DeepCollectionEquality()
.equals(other.isSubmitting, isSubmitting)) &&
(identical(other.signInFailure, signInFailure) ||
(identical(other.passwordError, passwordError) ||
const DeepCollectionEquality()
.equals(other.signInFailure, signInFailure)));
.equals(other.passwordError, passwordError)) &&
(identical(other.emailError, emailError) ||
const DeepCollectionEquality()
.equals(other.emailError, emailError)) &&
(identical(other.successOrFail, successOrFail) ||
const DeepCollectionEquality()
.equals(other.successOrFail, successOrFail)));
}
@override
@ -610,7 +652,9 @@ class _$_SignInState implements _SignInState {
const DeepCollectionEquality().hash(email) ^
const DeepCollectionEquality().hash(password) ^
const DeepCollectionEquality().hash(isSubmitting) ^
const DeepCollectionEquality().hash(signInFailure);
const DeepCollectionEquality().hash(passwordError) ^
const DeepCollectionEquality().hash(emailError) ^
const DeepCollectionEquality().hash(successOrFail);
@JsonKey(ignore: true)
@override
@ -623,7 +667,9 @@ abstract class _SignInState implements SignInState {
{String? email,
String? password,
required bool isSubmitting,
required Option<Either<UserDetail, UserError>> signInFailure}) =
required Option<String> passwordError,
required Option<String> emailError,
required Option<Either<UserDetail, UserError>> successOrFail}) =
_$_SignInState;
@override
@ -633,7 +679,11 @@ abstract class _SignInState implements SignInState {
@override
bool get isSubmitting => throw _privateConstructorUsedError;
@override
Option<Either<UserDetail, UserError>> get signInFailure =>
Option<String> get passwordError => throw _privateConstructorUsedError;
@override
Option<String> get emailError => throw _privateConstructorUsedError;
@override
Option<Either<UserDetail, UserError>> get successOrFail =>
throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)

View File

@ -1,5 +1,6 @@
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter/material.dart';
abstract class IAuth {
Future<Either<UserDetail, UserError>> signIn(String? email, String? password);
@ -8,3 +9,9 @@ abstract class IAuth {
Future<Either<Unit, UserError>> signOut();
}
abstract class IAuthRouter {
void showHomeScreen(BuildContext context, UserDetail user);
void showSignUpScreen(BuildContext context);
void showForgetPasswordScreen(BuildContext context);
}

View File

@ -6,10 +6,11 @@ import 'package:get_it/get_it.dart';
class UserDepsResolver {
static Future<void> resolve(GetIt getIt) async {
getIt.registerLazySingleton<AuthRepository>(() => AuthRepository());
getIt.registerFactory<AuthRepository>(() => AuthRepository());
//Interface implementation
getIt.registerFactory<IAuth>(() => AuthImpl(repo: getIt<AuthRepository>()));
getIt.registerFactory<IAuthRouter>(() => AuthRouterImpl());
//Bloc
getIt.registerFactory<SignInBloc>(() => SignInBloc(getIt<IAuth>()));

View File

@ -1,7 +1,10 @@
import 'package:app_flowy/workspace/presentation/home/home_screen.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_infra_ui/widget/route/animation.dart';
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart';
import 'package:app_flowy/user/domain/i_auth.dart';
import 'package:app_flowy/user/infrastructure/repos/auth_repo.dart';
import 'package:flutter/material.dart';
class AuthImpl extends IAuth {
AuthRepository repo;
@ -26,3 +29,20 @@ class AuthImpl extends IAuth {
return repo.signOut();
}
}
class AuthRouterImpl extends IAuthRouter {
@override
void showForgetPasswordScreen(BuildContext context) {
// TODO: implement showForgetPasswordScreen
}
@override
void showHomeScreen(BuildContext context, UserDetail user) {
Navigator.of(context).push(PageRoutes.fade(() => HomeScreen(user)));
}
@override
void showSignUpScreen(BuildContext context) {
// TODO: implement showSignUpScreen
}
}

View File

@ -1,19 +1,217 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/user/application/sign_in/sign_in_bloc.dart';
import 'package:app_flowy/user/presentation/sign_in/widgets/body.dart';
import 'package:app_flowy/user/domain/i_auth.dart';
import 'package:app_flowy/user/presentation/sign_in/widgets/background.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_sdk/protobuf/flowy-user/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dartz/dartz.dart';
class SignInScreen extends StatelessWidget {
const SignInScreen({Key? key}) : super(key: key);
final IAuthRouter router;
const SignInScreen({Key? key, required this.router}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => getIt<SignInBloc>(),
child: const Scaffold(
body: Body(),
child: BlocListener<SignInBloc, SignInState>(
listener: (context, state) {
state.successOrFail.fold(
() => null,
(result) => _handleSuccessOrFail(result, context),
);
},
child: Scaffold(
body: SignInForm(router: router),
),
),
);
}
void _handleSuccessOrFail(
Either<UserDetail, UserError> result, BuildContext context) {
result.fold(
(user) => router.showHomeScreen(context, user),
(error) => _showErrorMessage(context, error.msg),
);
}
void _showErrorMessage(BuildContext context, String msg) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(msg),
),
);
}
}
class SignInForm extends StatelessWidget {
final IAuthRouter router;
const SignInForm({
Key? key,
required this.router,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.center,
child: SignInFormContainer(
children: [
const SignInTitle(
title: 'Login to Appflowy',
logoSize: Size(60, 60),
),
const VSpace(30),
const EmailTextField(),
const PasswordTextField(),
ForgetPasswordButton(router: router),
const LoginButton(),
const VSpace(10),
SignUpPrompt(router: router),
if (context.read<SignInBloc>().state.isSubmitting) ...[
const SizedBox(height: 8),
const LinearProgressIndicator(value: null),
]
],
),
);
}
}
class SignUpPrompt extends StatelessWidget {
const SignUpPrompt({
Key? key,
required this.router,
}) : super(key: key);
final IAuthRouter router;
@override
Widget build(BuildContext context) {
return Row(
children: [
const Text("Dont't have an account",
style: TextStyle(color: Colors.blueGrey, fontSize: 12)),
TextButton(
style: TextButton.styleFrom(
textStyle: const TextStyle(fontSize: 12),
),
onPressed: () => router.showSignUpScreen(context),
child: const Text(
'Sign Up',
style: TextStyle(color: Colors.lightBlue),
),
),
],
mainAxisAlignment: MainAxisAlignment.center,
);
}
}
class LoginButton extends StatelessWidget {
const LoginButton({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return RoundedTextButton(
title: 'Login',
height: 45,
borderRadius: BorderRadius.circular(10),
color: Colors.lightBlue,
press: () {
context
.read<SignInBloc>()
.add(const SignInEvent.signedInWithUserEmailAndPassword());
},
);
}
}
class ForgetPasswordButton extends StatelessWidget {
const ForgetPasswordButton({
Key? key,
required this.router,
}) : super(key: key);
final IAuthRouter router;
@override
Widget build(BuildContext context) {
return TextButton(
style: TextButton.styleFrom(
textStyle: const TextStyle(fontSize: 12),
),
onPressed: () => router.showForgetPasswordScreen(context),
child: const Text(
'Forgot Password?',
style: TextStyle(color: Colors.lightBlue),
),
);
}
}
class PasswordTextField extends StatelessWidget {
const PasswordTextField({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<SignInBloc, SignInState>(
buildWhen: (previous, current) =>
previous.passwordError != current.passwordError,
builder: (context, state) {
return RoundedInputField(
obscureText: true,
hintText: 'password',
normalBorderColor: Colors.green,
highlightBorderColor: Colors.red,
errorText: context
.read<SignInBloc>()
.state
.passwordError
.fold(() => "", (error) => error),
onChanged: (value) => context
.read<SignInBloc>()
.add(SignInEvent.passwordChanged(value)),
);
},
);
}
}
class EmailTextField extends StatelessWidget {
const EmailTextField({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<SignInBloc, SignInState>(
buildWhen: (previous, current) =>
previous.emailError != current.emailError,
builder: (context, state) {
return RoundedInputField(
hintText: 'email',
normalBorderColor: Colors.green,
highlightBorderColor: Colors.red,
errorText: context
.read<SignInBloc>()
.state
.emailError
.fold(() => "", (error) => error),
onChanged: (value) =>
context.read<SignInBloc>().add(SignInEvent.emailChanged(value)),
);
},
);
}
}

View File

@ -1,29 +1,57 @@
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
class SignInBackground extends StatelessWidget {
final Widget child;
const SignInBackground({
class SignInFormContainer extends StatelessWidget {
final List<Widget> children;
const SignInFormContainer({
Key? key,
required this.child,
required this.children,
}) : super(key: key);
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
final size = MediaQuery.of(context).size;
return SizedBox(
height: size.height,
width: double.infinity,
child: Stack(
alignment: Alignment.center,
children: [
Image(
fit: BoxFit.cover,
width: size.width,
height: size.height,
image: const AssetImage(
'assets/images/appflowy_launch_splash.jpg')),
child,
],
));
width: size.width * 0.3,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: children,
),
);
}
}
class SignInTitle extends StatelessWidget {
final String title;
final Size logoSize;
const SignInTitle({
Key? key,
required this.title,
required this.logoSize,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image(
fit: BoxFit.cover,
width: logoSize.width,
height: logoSize.height,
image: const AssetImage('assets/images/app_flowy_logo.jpg')),
const VSpace(30),
Text(
title,
style: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20,
),
)
],
),
);
}
}

View File

@ -1,125 +0,0 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/user/application/sign_in/sign_in_bloc.dart';
import 'package:app_flowy/user/presentation/sign_in/widgets/background.dart';
import 'package:app_flowy/workspace/presentation/home/home_screen.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class Body extends StatelessWidget {
const Body({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => getIt<SignInBloc>(),
child: const SignInBackground(
child: SignInForm(),
),
);
}
}
class SignInForm extends StatelessWidget {
const SignInForm({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocConsumer<SignInBloc, SignInState>(
listenWhen: (p, c) => p != c,
listener: (context, state) {
state.signInFailure.fold(
() {},
(result) => _handleStateErrors(result, context),
);
},
builder: (context, state) {
return SignInFormBackground(
children: [
const SizedBox(height: 30),
RoundedInputField(
icon: Icons.person,
hintText: 'email',
onChanged: (value) => context
.read<SignInBloc>()
.add(SignInEvent.emailChanged(value)),
),
RoundedInputField(
icon: Icons.lock,
obscureText: true,
hintText: 'password',
onChanged: (value) => context
.read<SignInBloc>()
.add(SignInEvent.passwordChanged(value)),
),
RoundedButton(
title: 'LOGIN',
press: () {
context
.read<SignInBloc>()
.add(const SignInEvent.signedInWithUserEmailAndPassword());
},
),
if (state.isSubmitting) ...[
const SizedBox(height: 8),
const LinearProgressIndicator(value: null),
]
],
);
},
);
}
void _handleStateErrors(
Either<UserDetail, UserError> some, BuildContext context) {
some.fold(
(userDetail) => showHomeScreen(context, userDetail),
(result) => _showErrorMessage(context, result.msg),
);
}
void _showErrorMessage(BuildContext context, String msg) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(msg),
),
);
}
void showHomeScreen(BuildContext context, UserDetail userDetail) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) {
return HomeScreen(userDetail);
},
),
);
}
}
class SignInFormBackground extends StatelessWidget {
final List<Widget> children;
const SignInFormBackground({
Key? key,
required this.children,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Container(
width: size.width * 0.4,
alignment: Alignment.center,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center, children: children),
),
);
}
}

View File

@ -13,7 +13,7 @@ class WelcomeBloc extends Bloc<WelcomeEvent, WelcomeState> {
Stream<WelcomeState> mapEventToState(WelcomeEvent event) async* {
yield* event.map(
getUser: (val) async* {
final authState = await authImpl.currentUserState();
final authState = await authImpl.currentUserDetail();
yield state.copyWith(auth: authState);
},
);

View File

@ -4,7 +4,7 @@ import 'package:flutter/widgets.dart';
import 'auth_state.dart';
abstract class IWelcomeAuth {
Future<AuthState> currentUserState();
Future<AuthState> currentUserDetail();
}
abstract class IWelcomeRoute {

View File

@ -1,3 +1,5 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/user/domain/i_auth.dart';
import 'package:app_flowy/user/presentation/sign_in/sign_in_screen.dart';
import 'package:app_flowy/welcome/domain/auth_state.dart';
import 'package:app_flowy/welcome/domain/i_welcome.dart';
@ -11,7 +13,7 @@ export 'package:app_flowy/welcome/domain/i_welcome.dart';
class WelcomeAuthImpl implements IWelcomeAuth {
@override
Future<AuthState> currentUserState() {
Future<AuthState> currentUserDetail() {
final result = UserEventGetStatus().send();
return result.then((result) {
return result.fold(
@ -34,6 +36,6 @@ class WelcomeRoute implements IWelcomeRoute {
@override
Widget pushSignInScreen() {
return const SignInScreen();
return SignInScreen(router: getIt<IAuthRouter>());
}
}

View File

@ -14,7 +14,6 @@ class DocBloc extends Bloc<DocEvent, DocState> {
Stream<DocState> mapEventToState(DocEvent event) async* {
yield* event.map(
initial: (e) async* {},
save: (Save value) async* {},
close: (Close value) async* {},
);
}
@ -23,7 +22,6 @@ class DocBloc extends Bloc<DocEvent, DocState> {
@freezed
abstract class DocEvent with _$DocEvent {
const factory DocEvent.initial() = Initial;
const factory DocEvent.save(String jsonStr) = Save;
const factory DocEvent.close() = Close;
}

View File

@ -20,12 +20,6 @@ class _$DocEventTearOff {
return const Initial();
}
Save save(String jsonStr) {
return Save(
jsonStr,
);
}
Close close() {
return const Close();
}
@ -39,14 +33,12 @@ mixin _$DocEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String jsonStr) save,
required TResult Function() close,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String jsonStr)? save,
TResult Function()? close,
required TResult orElse(),
}) =>
@ -54,14 +46,12 @@ mixin _$DocEvent {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(Save value) save,
required TResult Function(Close value) close,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(Save value)? save,
TResult Function(Close value)? close,
required TResult orElse(),
}) =>
@ -121,7 +111,6 @@ class _$Initial implements Initial {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String jsonStr) save,
required TResult Function() close,
}) {
return initial();
@ -131,7 +120,6 @@ class _$Initial implements Initial {
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String jsonStr)? save,
TResult Function()? close,
required TResult orElse(),
}) {
@ -145,7 +133,6 @@ class _$Initial implements Initial {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(Save value) save,
required TResult Function(Close value) close,
}) {
return initial(this);
@ -155,7 +142,6 @@ class _$Initial implements Initial {
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(Save value)? save,
TResult Function(Close value)? close,
required TResult orElse(),
}) {
@ -170,122 +156,6 @@ abstract class Initial implements DocEvent {
const factory Initial() = _$Initial;
}
/// @nodoc
abstract class $SaveCopyWith<$Res> {
factory $SaveCopyWith(Save value, $Res Function(Save) then) =
_$SaveCopyWithImpl<$Res>;
$Res call({String jsonStr});
}
/// @nodoc
class _$SaveCopyWithImpl<$Res> extends _$DocEventCopyWithImpl<$Res>
implements $SaveCopyWith<$Res> {
_$SaveCopyWithImpl(Save _value, $Res Function(Save) _then)
: super(_value, (v) => _then(v as Save));
@override
Save get _value => super._value as Save;
@override
$Res call({
Object? jsonStr = freezed,
}) {
return _then(Save(
jsonStr == freezed
? _value.jsonStr
: jsonStr // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$Save implements Save {
const _$Save(this.jsonStr);
@override
final String jsonStr;
@override
String toString() {
return 'DocEvent.save(jsonStr: $jsonStr)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is Save &&
(identical(other.jsonStr, jsonStr) ||
const DeepCollectionEquality().equals(other.jsonStr, jsonStr)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(jsonStr);
@JsonKey(ignore: true)
@override
$SaveCopyWith<Save> get copyWith =>
_$SaveCopyWithImpl<Save>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String jsonStr) save,
required TResult Function() close,
}) {
return save(jsonStr);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String jsonStr)? save,
TResult Function()? close,
required TResult orElse(),
}) {
if (save != null) {
return save(jsonStr);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(Save value) save,
required TResult Function(Close value) close,
}) {
return save(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(Save value)? save,
TResult Function(Close value)? close,
required TResult orElse(),
}) {
if (save != null) {
return save(this);
}
return orElse();
}
}
abstract class Save implements DocEvent {
const factory Save(String jsonStr) = _$Save;
String get jsonStr => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$SaveCopyWith<Save> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $CloseCopyWith<$Res> {
factory $CloseCopyWith(Close value, $Res Function(Close) then) =
@ -324,7 +194,6 @@ class _$Close implements Close {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String jsonStr) save,
required TResult Function() close,
}) {
return close();
@ -334,7 +203,6 @@ class _$Close implements Close {
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String jsonStr)? save,
TResult Function()? close,
required TResult orElse(),
}) {
@ -348,7 +216,6 @@ class _$Close implements Close {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(Save value) save,
required TResult Function(Close value) close,
}) {
return close(this);
@ -358,7 +225,6 @@ class _$Close implements Close {
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(Save value)? save,
TResult Function(Close value)? close,
required TResult orElse(),
}) {

View File

@ -40,9 +40,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
}
Stream<MenuState> _performActionOnCreateApp(CreateApp event) async* {
await iWorkspaceImpl
.createApp(name: event.name, desc: event.desc)
.then((result) async* {
iWorkspaceImpl.createApp(name: event.name, desc: event.desc).then((result) {
result.fold(
(app) => {},
(error) async* {

View File

@ -0,0 +1,60 @@
import 'package:app_flowy/workspace/domain/i_user.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_create.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:dartz/dartz.dart';
part 'menu_user_bloc.freezed.dart';
class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
final IUser iUserImpl;
MenuUserBloc(this.iUserImpl) : super(MenuUserState.initial(iUserImpl.user));
@override
Stream<MenuUserState> mapEventToState(MenuUserEvent event) async* {
yield* event.map(
initial: (_) async* {
// fetch workspaces
iUserImpl.fetchWorkspaces().then((result) {
result.fold(
(workspaces) async* {
yield state.copyWith(workspaces: some(workspaces));
},
(error) async* {
yield state.copyWith(successOrFailure: right(error.msg));
},
);
});
},
fetchWorkspaces: (_FetchWorkspaces value) async* {},
);
}
@override
Future<void> close() async {
super.close();
}
}
@freezed
class MenuUserEvent with _$MenuUserEvent {
const factory MenuUserEvent.initial() = _Initial;
const factory MenuUserEvent.fetchWorkspaces() = _FetchWorkspaces;
}
@freezed
class MenuUserState with _$MenuUserState {
const factory MenuUserState({
required UserDetail user,
required Option<List<Workspace>> workspaces,
required Either<Unit, String> successOrFailure,
}) = _MenuUserState;
factory MenuUserState.initial(UserDetail user) => MenuUserState(
user: user,
workspaces: none(),
successOrFailure: left(unit),
);
}

View File

@ -0,0 +1,432 @@
// 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 'menu_user_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(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 _$MenuUserEventTearOff {
const _$MenuUserEventTearOff();
_Initial initial() {
return const _Initial();
}
_FetchWorkspaces fetchWorkspaces() {
return const _FetchWorkspaces();
}
}
/// @nodoc
const $MenuUserEvent = _$MenuUserEventTearOff();
/// @nodoc
mixin _$MenuUserEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() fetchWorkspaces,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? fetchWorkspaces,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_FetchWorkspaces value) fetchWorkspaces,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_FetchWorkspaces value)? fetchWorkspaces,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $MenuUserEventCopyWith<$Res> {
factory $MenuUserEventCopyWith(
MenuUserEvent value, $Res Function(MenuUserEvent) then) =
_$MenuUserEventCopyWithImpl<$Res>;
}
/// @nodoc
class _$MenuUserEventCopyWithImpl<$Res>
implements $MenuUserEventCopyWith<$Res> {
_$MenuUserEventCopyWithImpl(this._value, this._then);
final MenuUserEvent _value;
// ignore: unused_field
final $Res Function(MenuUserEvent) _then;
}
/// @nodoc
abstract class _$InitialCopyWith<$Res> {
factory _$InitialCopyWith(_Initial value, $Res Function(_Initial) then) =
__$InitialCopyWithImpl<$Res>;
}
/// @nodoc
class __$InitialCopyWithImpl<$Res> extends _$MenuUserEventCopyWithImpl<$Res>
implements _$InitialCopyWith<$Res> {
__$InitialCopyWithImpl(_Initial _value, $Res Function(_Initial) _then)
: super(_value, (v) => _then(v as _Initial));
@override
_Initial get _value => super._value as _Initial;
}
/// @nodoc
class _$_Initial implements _Initial {
const _$_Initial();
@override
String toString() {
return 'MenuUserEvent.initial()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is _Initial);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() fetchWorkspaces,
}) {
return initial();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? fetchWorkspaces,
required TResult orElse(),
}) {
if (initial != null) {
return initial();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_FetchWorkspaces value) fetchWorkspaces,
}) {
return initial(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_FetchWorkspaces value)? fetchWorkspaces,
required TResult orElse(),
}) {
if (initial != null) {
return initial(this);
}
return orElse();
}
}
abstract class _Initial implements MenuUserEvent {
const factory _Initial() = _$_Initial;
}
/// @nodoc
abstract class _$FetchWorkspacesCopyWith<$Res> {
factory _$FetchWorkspacesCopyWith(
_FetchWorkspaces value, $Res Function(_FetchWorkspaces) then) =
__$FetchWorkspacesCopyWithImpl<$Res>;
}
/// @nodoc
class __$FetchWorkspacesCopyWithImpl<$Res>
extends _$MenuUserEventCopyWithImpl<$Res>
implements _$FetchWorkspacesCopyWith<$Res> {
__$FetchWorkspacesCopyWithImpl(
_FetchWorkspaces _value, $Res Function(_FetchWorkspaces) _then)
: super(_value, (v) => _then(v as _FetchWorkspaces));
@override
_FetchWorkspaces get _value => super._value as _FetchWorkspaces;
}
/// @nodoc
class _$_FetchWorkspaces implements _FetchWorkspaces {
const _$_FetchWorkspaces();
@override
String toString() {
return 'MenuUserEvent.fetchWorkspaces()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is _FetchWorkspaces);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() fetchWorkspaces,
}) {
return fetchWorkspaces();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? fetchWorkspaces,
required TResult orElse(),
}) {
if (fetchWorkspaces != null) {
return fetchWorkspaces();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_FetchWorkspaces value) fetchWorkspaces,
}) {
return fetchWorkspaces(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_FetchWorkspaces value)? fetchWorkspaces,
required TResult orElse(),
}) {
if (fetchWorkspaces != null) {
return fetchWorkspaces(this);
}
return orElse();
}
}
abstract class _FetchWorkspaces implements MenuUserEvent {
const factory _FetchWorkspaces() = _$_FetchWorkspaces;
}
/// @nodoc
class _$MenuUserStateTearOff {
const _$MenuUserStateTearOff();
_MenuUserState call(
{required UserDetail user,
required Option<List<Workspace>> workspaces,
required Either<Unit, String> successOrFailure}) {
return _MenuUserState(
user: user,
workspaces: workspaces,
successOrFailure: successOrFailure,
);
}
}
/// @nodoc
const $MenuUserState = _$MenuUserStateTearOff();
/// @nodoc
mixin _$MenuUserState {
UserDetail get user => throw _privateConstructorUsedError;
Option<List<Workspace>> get workspaces => throw _privateConstructorUsedError;
Either<Unit, String> get successOrFailure =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$MenuUserStateCopyWith<MenuUserState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $MenuUserStateCopyWith<$Res> {
factory $MenuUserStateCopyWith(
MenuUserState value, $Res Function(MenuUserState) then) =
_$MenuUserStateCopyWithImpl<$Res>;
$Res call(
{UserDetail user,
Option<List<Workspace>> workspaces,
Either<Unit, String> successOrFailure});
}
/// @nodoc
class _$MenuUserStateCopyWithImpl<$Res>
implements $MenuUserStateCopyWith<$Res> {
_$MenuUserStateCopyWithImpl(this._value, this._then);
final MenuUserState _value;
// ignore: unused_field
final $Res Function(MenuUserState) _then;
@override
$Res call({
Object? user = freezed,
Object? workspaces = freezed,
Object? successOrFailure = freezed,
}) {
return _then(_value.copyWith(
user: user == freezed
? _value.user
: user // ignore: cast_nullable_to_non_nullable
as UserDetail,
workspaces: workspaces == freezed
? _value.workspaces
: workspaces // ignore: cast_nullable_to_non_nullable
as Option<List<Workspace>>,
successOrFailure: successOrFailure == freezed
? _value.successOrFailure
: successOrFailure // ignore: cast_nullable_to_non_nullable
as Either<Unit, String>,
));
}
}
/// @nodoc
abstract class _$MenuUserStateCopyWith<$Res>
implements $MenuUserStateCopyWith<$Res> {
factory _$MenuUserStateCopyWith(
_MenuUserState value, $Res Function(_MenuUserState) then) =
__$MenuUserStateCopyWithImpl<$Res>;
@override
$Res call(
{UserDetail user,
Option<List<Workspace>> workspaces,
Either<Unit, String> successOrFailure});
}
/// @nodoc
class __$MenuUserStateCopyWithImpl<$Res>
extends _$MenuUserStateCopyWithImpl<$Res>
implements _$MenuUserStateCopyWith<$Res> {
__$MenuUserStateCopyWithImpl(
_MenuUserState _value, $Res Function(_MenuUserState) _then)
: super(_value, (v) => _then(v as _MenuUserState));
@override
_MenuUserState get _value => super._value as _MenuUserState;
@override
$Res call({
Object? user = freezed,
Object? workspaces = freezed,
Object? successOrFailure = freezed,
}) {
return _then(_MenuUserState(
user: user == freezed
? _value.user
: user // ignore: cast_nullable_to_non_nullable
as UserDetail,
workspaces: workspaces == freezed
? _value.workspaces
: workspaces // ignore: cast_nullable_to_non_nullable
as Option<List<Workspace>>,
successOrFailure: successOrFailure == freezed
? _value.successOrFailure
: successOrFailure // ignore: cast_nullable_to_non_nullable
as Either<Unit, String>,
));
}
}
/// @nodoc
class _$_MenuUserState implements _MenuUserState {
const _$_MenuUserState(
{required this.user,
required this.workspaces,
required this.successOrFailure});
@override
final UserDetail user;
@override
final Option<List<Workspace>> workspaces;
@override
final Either<Unit, String> successOrFailure;
@override
String toString() {
return 'MenuUserState(user: $user, workspaces: $workspaces, successOrFailure: $successOrFailure)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is _MenuUserState &&
(identical(other.user, user) ||
const DeepCollectionEquality().equals(other.user, user)) &&
(identical(other.workspaces, workspaces) ||
const DeepCollectionEquality()
.equals(other.workspaces, workspaces)) &&
(identical(other.successOrFailure, successOrFailure) ||
const DeepCollectionEquality()
.equals(other.successOrFailure, successOrFailure)));
}
@override
int get hashCode =>
runtimeType.hashCode ^
const DeepCollectionEquality().hash(user) ^
const DeepCollectionEquality().hash(workspaces) ^
const DeepCollectionEquality().hash(successOrFailure);
@JsonKey(ignore: true)
@override
_$MenuUserStateCopyWith<_MenuUserState> get copyWith =>
__$MenuUserStateCopyWithImpl<_MenuUserState>(this, _$identity);
}
abstract class _MenuUserState implements MenuUserState {
const factory _MenuUserState(
{required UserDetail user,
required Option<List<Workspace>> workspaces,
required Either<Unit, String> successOrFailure}) = _$_MenuUserState;
@override
UserDetail get user => throw _privateConstructorUsedError;
@override
Option<List<Workspace>> get workspaces => throw _privateConstructorUsedError;
@override
Either<Unit, String> get successOrFailure =>
throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$MenuUserStateCopyWith<_MenuUserState> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,18 @@
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/protobuf/flowy-user/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_create.pb.dart';
export 'package:flowy_sdk/protobuf/flowy-workspace/workspace_create.pb.dart';
export 'package:flowy_sdk/protobuf/flowy-user/errors.pb.dart';
export 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
export 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
abstract class IUser {
UserDetail get user;
Future<Either<UserDetail, UserError>> fetchUserDetail(String userId);
Future<Either<List<Workspace>, WorkspaceError>> fetchWorkspaces();
Future<Either<Unit, WorkspaceError>> deleteWorkspace(String workspaceId);
Future<Either<Unit, UserError>> signOut();
}

View File

@ -0,0 +1,16 @@
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/material.dart';
AssetImage assetImageForViewType(ViewType type) {
final imageName = imageNameForViewType(type);
return AssetImage('assets/images/$imageName');
}
String imageNameForViewType(ViewType type) {
switch (type) {
case ViewType.Doc:
return "file_icon.jpg";
default:
return "file_icon.jpg";
}
}

View File

@ -23,7 +23,8 @@ class HomePageStack {
}
void setStackView(HomeStackView? stackView) {
_bloc.add(PageStackEvent.setStackView(stackView ?? const BlankStackView()));
_bloc.add(PageStackEvent.setStackView(
stackView ?? const AnnouncementStackView()));
}
Widget stackTopBar() {
@ -32,7 +33,7 @@ class HomePageStack {
child: BlocBuilder<PageStackBloc, PageStackState>(
builder: (context, state) {
return HomeTopBar(
title: state.stackView.title,
view: state.stackView,
);
},
),
@ -61,14 +62,17 @@ List<Widget> _buildStackWidget(HomeStackView stackView) {
if (viewType == stackView.type) {
switch (stackView.type) {
case ViewType.Blank:
return BlankPage(stackView: stackView as BlankStackView);
return AnnouncementPage(
stackView: stackView as AnnouncementStackView);
case ViewType.Doc:
return DocPage(stackView: stackView as DocPageStackView);
final docView = stackView as DocPageStackView;
return DocPage(key: ValueKey(docView.view.id), stackView: docView);
default:
return BlankPage(stackView: stackView as BlankStackView);
return AnnouncementPage(
stackView: stackView as AnnouncementStackView);
}
} else {
return const BlankPage(stackView: BlankStackView());
return const AnnouncementPage(stackView: AnnouncementStackView());
}
}).toList();
}
@ -76,11 +80,11 @@ List<Widget> _buildStackWidget(HomeStackView stackView) {
HomeStackView stackViewFromView(View view) {
switch (view.viewType) {
case ViewType.Blank:
return const BlankStackView();
return const AnnouncementStackView();
case ViewType.Doc:
return DocPageStackView(view);
default:
return const BlankStackView();
return const AnnouncementStackView();
}
}

View File

@ -30,6 +30,6 @@ abstract class PageStackState implements _$PageStackState {
}) = _PageStackState;
factory PageStackState.initial() => const PageStackState(
stackView: BlankStackView(),
stackView: AnnouncementStackView(),
);
}

View File

@ -2,6 +2,7 @@ import 'package:app_flowy/workspace/application/app/app_bloc.dart';
import 'package:app_flowy/workspace/application/app/app_watch_bloc.dart';
import 'package:app_flowy/workspace/application/doc/doc_bloc.dart';
import 'package:app_flowy/workspace/application/menu/menu_bloc.dart';
import 'package:app_flowy/workspace/application/menu/menu_user_bloc.dart';
import 'package:app_flowy/workspace/application/menu/menu_watch.dart';
import 'package:app_flowy/workspace/application/view/doc_watch_bloc.dart';
import 'package:app_flowy/workspace/application/view/view_bloc.dart';
@ -15,8 +16,11 @@ import 'package:app_flowy/workspace/infrastructure/repos/app_repo.dart';
import 'package:app_flowy/workspace/infrastructure/repos/doc_repo.dart';
import 'package:app_flowy/workspace/infrastructure/repos/view_repo.dart';
import 'package:app_flowy/workspace/infrastructure/repos/workspace_repo.dart';
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
import 'package:get_it/get_it.dart';
import 'i_user_impl.dart';
import 'i_view_impl.dart';
class HomeDepsResolver {
@ -31,10 +35,10 @@ class HomeDepsResolver {
(appId, _) => IAppWatchImpl(repo: AppWatchRepository(appId: appId)));
//workspace
getIt.registerFactoryParam<IWorkspace, String, void>((workspaceId, _) =>
IWorkspaceImpl(repo: WorkspaceRepo(workspaceId: workspaceId)));
getIt.registerFactoryParam<IWorkspaceWatch, String, void>((workspacId, _) =>
IWorkspaceWatchImpl(repo: WorkspaceWatchRepo(workspaceId: workspacId)));
getIt.registerFactoryParam<IWorkspace, UserDetail, void>(
(user, _) => IWorkspaceImpl(repo: WorkspaceRepo(user: user)));
getIt.registerFactoryParam<IWorkspaceWatch, UserDetail, void>(
(user, _) => IWorkspaceWatchImpl(repo: WorkspaceWatchRepo(user: user)));
// View
getIt.registerFactoryParam<IView, String, void>(
@ -46,12 +50,20 @@ class HomeDepsResolver {
getIt.registerFactoryParam<IDoc, String, void>(
(docId, _) => IDocImpl(repo: DocRepository(docId: docId)));
//Bloc
getIt.registerFactoryParam<MenuBloc, String, void>(
(workspaceId, _) => MenuBloc(getIt<IWorkspace>(param1: workspaceId)));
getIt.registerFactoryParam<MenuWatchBloc, String, void>((workspaceId, _) =>
MenuWatchBloc(getIt<IWorkspaceWatch>(param1: workspaceId)));
// User
getIt.registerFactoryParam<IUser, UserDetail, void>(
(user, _) => IUserImpl(repo: UserRepo(user: user)));
//Menu Bloc
getIt.registerFactoryParam<MenuBloc, UserDetail, void>(
(user, _) => MenuBloc(getIt<IWorkspace>(param1: user)));
getIt.registerFactoryParam<MenuWatchBloc, UserDetail, void>(
(user, _) => MenuWatchBloc(getIt<IWorkspaceWatch>(param1: user)));
getIt.registerFactoryParam<MenuUserBloc, UserDetail, void>(
(user, _) => MenuUserBloc(getIt<IUser>(param1: user)));
//
getIt.registerFactoryParam<AppBloc, String, void>(
(appId, _) => AppBloc(getIt<IApp>(param1: appId)));
getIt.registerFactoryParam<AppWatchBloc, String, void>(
@ -66,6 +78,9 @@ class HomeDepsResolver {
getIt.registerFactoryParam<DocBloc, String, void>(
(docId, _) => DocBloc(getIt<IDoc>(param1: docId)));
// editor
getIt.registerFactoryParam<EditorPersistence, String, void>(
(docId, _) => EditorPersistenceImpl(repo: DocRepository(docId: docId)));
// getIt.registerFactoryParam<ViewBloc, String, void>(
// (viewId, _) => ViewBloc(iViewImpl: getIt<IView>(param1: viewId)));
}

View File

@ -35,8 +35,7 @@ class IAppImpl extends IApp {
final result = await docRepo.createDoc(
name: view.name, desc: "", text: "[{\"insert\":\"\\n\"}]");
return result.fold((l) => left(view), (r) {
return right(
WorkspaceError(code: WorkspaceErrorCode.Unknown, msg: r.msg));
return right(WorkspaceError(code: WsErrCode.Unknown, msg: r.msg));
});
default:
return left(view);

View File

@ -1,10 +1,11 @@
import 'dart:convert';
import 'package:dartz/dartz.dart';
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flowy_sdk/protobuf/flowy-editor/errors.pb.dart';
import 'package:app_flowy/workspace/domain/i_doc.dart';
import 'package:app_flowy/workspace/infrastructure/repos/doc_repo.dart';
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flowy_sdk/protobuf/flowy-editor/errors.pb.dart';
import 'package:dartz/dartz.dart';
class IDocImpl extends IDoc {
DocRepository repo;
@ -49,3 +50,21 @@ class IDocImpl extends IDoc {
return document;
}
}
class EditorPersistenceImpl extends EditorPersistence {
DocRepository repo;
EditorPersistenceImpl({
required this.repo,
});
@override
Future<bool> save(List<dynamic> jsonList) async {
final json = jsonEncode(jsonList);
return repo.updateDoc(text: json).then((result) {
return result.fold(
(l) => true,
(r) => false,
);
});
}
}

View File

@ -0,0 +1,36 @@
import 'package:dartz/dartz.dart';
import 'package:app_flowy/workspace/domain/i_user.dart';
import 'package:app_flowy/workspace/infrastructure/repos/user_repo.dart';
export 'package:app_flowy/workspace/domain/i_user.dart';
export 'package:app_flowy/workspace/infrastructure/repos/user_repo.dart';
class IUserImpl extends IUser {
UserRepo repo;
IUserImpl({
required this.repo,
});
@override
Future<Either<Unit, WorkspaceError>> deleteWorkspace(String workspaceId) {
return repo.deleteWorkspace(workspaceId: workspaceId);
}
@override
Future<Either<UserDetail, UserError>> fetchUserDetail(String userId) {
return repo.fetchUserDetail(userId: userId);
}
@override
Future<Either<Unit, UserError>> signOut() {
return repo.signOut();
}
@override
UserDetail get user => repo.user;
@override
Future<Either<List<Workspace>, WorkspaceError>> fetchWorkspaces() {
return repo.fetchWorkspaces();
}
}

View File

@ -0,0 +1,36 @@
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-user/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_create.pb.dart';
class UserRepo {
final UserDetail user;
UserRepo({
required this.user,
});
Future<Either<UserDetail, UserError>> fetchUserDetail(
{required String userId}) {
return UserEventGetStatus().send();
}
Future<Either<Unit, WorkspaceError>> deleteWorkspace(
{required String workspaceId}) {
throw UnimplementedError();
}
Future<Either<Unit, UserError>> signOut() {
return UserEventSignOut().send();
}
Future<Either<List<Workspace>, WorkspaceError>> fetchWorkspaces() {
return WorkspaceEventReadAllWorkspace().send().then((result) {
return result.fold(
(workspaces) => left(workspaces.items),
(r) => right(r),
);
});
}
}

View File

@ -5,6 +5,7 @@ import 'package:dartz/dartz.dart';
import 'package:flowy_infra/flowy_logger.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-observable/subject.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/observable.pb.dart';
@ -13,9 +14,9 @@ import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_query.pb.dart';
import 'package:flowy_sdk/rust_stream.dart';
class WorkspaceRepo {
String workspaceId;
UserDetail user;
WorkspaceRepo({
required this.workspaceId,
required this.user,
});
Future<Either<App, WorkspaceError>> createApp(String appName, String desc) {
@ -38,7 +39,7 @@ class WorkspaceRepo {
Future<Either<Workspace, WorkspaceError>> getWorkspace(
{bool readApps = false}) {
final request = QueryWorkspaceRequest.create()
..workspaceId = workspaceId
..workspaceId = user.workspace
..readApps = readApps;
return WorkspaceEventGetWorkspace(request).send().then((result) {
@ -54,13 +55,13 @@ class WorkspaceWatchRepo {
StreamSubscription<ObservableSubject>? _subscription;
WorkspaceAddAppCallback? _addAppCallback;
WorkspaceUpdatedCallback? _updatedCallback;
final String workspaceId;
final UserDetail user;
late WorkspaceRepo _repo;
WorkspaceWatchRepo({
required this.workspaceId,
required this.user,
}) {
_repo = WorkspaceRepo(workspaceId: workspaceId);
_repo = WorkspaceRepo(user: user);
}
void startWatching(
@ -70,7 +71,7 @@ class WorkspaceWatchRepo {
_updatedCallback = updatedCallback;
_subscription = RustStreamReceiver.listen((observable) {
if (observable.subjectId != workspaceId) {
if (observable.subjectId != user.workspace) {
return;
}

View File

@ -1,20 +1,32 @@
import 'package:app_flowy/workspace/application/app/app_bloc.dart';
import 'package:app_flowy/workspace/application/app/app_watch_bloc.dart';
import 'package:app_flowy/workspace/presentation/app/view_list.dart';
import 'package:app_flowy/workspace/presentation/widgets/menu/menu_size.dart';
import 'package:app_flowy/workspace/presentation/widgets/menu/menu_list.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:expandable/expandable.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_infra_ui/style_widget/styled_text_button.dart';
import 'package:flowy_infra_ui/style_widget/styled_icon_button.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dartz/dartz.dart';
class AppWidget extends StatelessWidget {
class AppWidgetSize {
static double expandedIconSize = 24;
static double expandedIconRightSpace = 8;
static double scale = 1;
static double get expandedPadding =>
expandedIconSize * scale + expandedIconRightSpace;
}
class AppWidget extends MenuItem {
final App app;
const AppWidget(this.app, {Key? key}) : super(key: key);
AppWidget(this.app, {Key? key}) : super(key: ValueKey(app.id));
@override
Widget build(BuildContext context) {
@ -35,11 +47,9 @@ class AppWidget extends StatelessWidget {
builder: (context, state) {
final child = state.map(
initial: (_) => BlocBuilder<AppBloc, AppState>(
builder: (context, state) {
return ViewList(state.views);
},
builder: (context, state) => _renderViewList(state.views),
),
loadViews: (s) => ViewList(some(s.views)),
loadViews: (s) => _renderViewList(some(s.views)),
loadFail: (s) => FlowyErrorPage(s.error.toString()),
);
@ -54,31 +64,36 @@ class AppWidget extends StatelessWidget {
child: ScrollOnExpand(
scrollOnExpand: true,
scrollOnCollapse: false,
child: Card(
clipBehavior: Clip.antiAlias,
child: Column(
children: <Widget>[
ExpandablePanel(
theme: const ExpandableThemeData(
headerAlignment: ExpandablePanelHeaderAlignment.center,
tapBodyToExpand: false,
tapBodyToCollapse: false,
iconPadding: EdgeInsets.zero,
hasIcon: false,
),
header: AppHeader(app),
expanded: Padding(
padding: EdgeInsets.only(left: Sizes.iconMed),
child: child,
),
collapsed: const SizedBox(),
child: Column(
children: <Widget>[
ExpandablePanel(
theme: const ExpandableThemeData(
headerAlignment: ExpandablePanelHeaderAlignment.center,
tapBodyToExpand: false,
tapBodyToCollapse: false,
tapHeaderToExpand: false,
iconPadding: EdgeInsets.zero,
hasIcon: false,
),
],
),
header: AppHeader(app),
expanded: child,
collapsed: const SizedBox(),
),
],
),
),
);
}
Widget _renderViewList(Option<List<View>> views) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: ViewList(views),
);
}
@override
MenuItemType get type => MenuItemType.app;
}
class AppHeader extends StatelessWidget {
@ -90,46 +105,53 @@ class AppHeader extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Padding(
padding: EdgeInsets.symmetric(vertical: Insets.m),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ExpandableIcon(
theme: ExpandableThemeData(
expandIcon: Icons.arrow_right,
collapseIcon: Icons.arrow_drop_down,
iconColor: Colors.black,
iconSize: HomeMenuSize.collapseIconSize,
iconPadding: EdgeInsets.zero,
hasIcon: false,
),
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
InkWell(
onTap: () {
ExpandableController.of(context,
rebuildOnChange: false, required: true)
?.toggle();
},
child: ExpandableIcon(
theme: ExpandableThemeData(
expandIcon: Icons.arrow_drop_up,
collapseIcon: Icons.arrow_drop_down,
iconColor: Colors.black,
iconSize: AppWidgetSize.expandedIconSize,
iconPadding: EdgeInsets.zero,
hasIcon: false,
),
Expanded(
child: Text(app.name),
),
SizedBox(
height: HomeMenuSize.createViewButtonSize,
child: createViewPopupMenu(context),
),
],
),
),
),
HSpace(AppWidgetSize.expandedIconRightSpace),
Expanded(
child: StyledTextButton(
app.name,
onPressed: () {
debugPrint('show app document');
},
),
),
StyledIconButton(
icon: const Icon(Icons.add),
onPressed: () {
debugPrint('add view');
},
),
],
);
}
Widget createViewPopupMenu(BuildContext context) {
return PopupMenuButton(
iconSize: 24,
tooltip: 'create new view',
icon: const Icon(Icons.add),
padding: EdgeInsets.zero,
onSelected: (viewType) => _createView(viewType as ViewType, context),
itemBuilder: (context) => menuItemBuilder());
}
// return PopupMenuButton(
// iconSize: 20,
// tooltip: 'create new view',
// icon: const Icon(Icons.add),
// padding: EdgeInsets.zero,
// onSelected: (viewType) => _createView(viewType as ViewType, context),
// itemBuilder: (context) => menuItemBuilder());
List<PopupMenuEntry> menuItemBuilder() {
return ViewType.values

View File

@ -1,11 +1,9 @@
import 'package:app_flowy/workspace/presentation/view/view_widget.dart';
import 'package:flowy_infra/flowy_logger.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:dartz/dartz.dart';
import 'package:styled_widget/styled_widget.dart';
class ViewList extends StatelessWidget {
final Option<List<View>> views;
@ -15,24 +13,24 @@ class ViewList extends StatelessWidget {
Widget build(BuildContext context) {
Log.info('ViewList build');
return views.fold(
() => const SizedBox(
height: 10,
),
() => const SizedBox(),
(views) {
return Column(
children: buildViewWidgets(views),
).padding(vertical: Insets.sm);
children: _renderViews(views),
);
},
);
}
List<ViewWidget> buildViewWidgets(List<View> views) {
List<Widget> _renderViews(List<View> views) {
var targetViews = views.map((view) {
return ViewWidget(
icon: const Icon(Icons.file_copy),
view: view,
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: ViewWidget(
view: view,
),
);
}).toList(growable: true);
}).toList(growable: false);
return targetViews;
}

View File

@ -6,6 +6,7 @@ import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flowy_infra_ui/style_widget/styled_progress_indicator.dart';
class DocPage extends HomeStackWidget {
const DocPage({Key? key, required DocPageStackView stackView})
@ -29,13 +30,28 @@ class _DocPageState extends State<DocPage> {
BlocBuilder<DocWatchBloc, DocWatchState>(builder: (context, state) {
assert(widget.stackView is DocPageStackView);
return state.map(
loading: (_) => const CircularProgressIndicator.adaptive(),
loading: (_) => const StyledProgressIndicator(),
loadDoc: (s) => EditorWdiget(doc: s.doc),
loadFail: (s) => FlowyErrorPage(s.error.toString()),
);
}),
);
}
@override
void dispose() {
super.dispose();
}
@override
void deactivate() {
super.deactivate();
}
@override
void didUpdateWidget(covariant DocPage oldWidget) {
super.didUpdateWidget(oldWidget);
}
}
class DocPageStackView extends HomeStackView {

View File

@ -16,6 +16,7 @@ class EditorWdiget extends StatelessWidget {
controller = EditorController(
document: doc.data,
selection: const TextSelection.collapsed(offset: 0),
persistence: getIt<EditorPersistence>(param1: doc.info.id),
);
}
@ -23,12 +24,16 @@ class EditorWdiget extends StatelessWidget {
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => getIt<DocBloc>(param1: doc.info.id),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_renderEditor(controller),
_renderToolbar(controller),
],
child: BlocBuilder<DocBloc, DocState>(
builder: (ctx, state) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_renderEditor(controller),
_renderToolbar(controller),
],
);
},
),
);
}
@ -45,7 +50,9 @@ class EditorWdiget extends StatelessWidget {
scrollBottomInset: 0,
scrollController: ScrollController(),
);
return Expanded(child: editor);
return Expanded(
child: Padding(padding: const EdgeInsets.all(10), child: editor),
);
}
Widget _renderToolbar(EditorController controller) {

View File

@ -23,7 +23,7 @@ class HomeLayout {
showEditPannel = homeBlocState.editContext.isSome();
menuWidth = Sizes.sideBarSm;
menuWidth = Sizes.sideBarMed;
if (context.widthPx >= PageBreaks.desktop) {
menuWidth = Sizes.sideBarLg;
}

View File

@ -14,8 +14,8 @@ import 'home_layout.dart';
class HomeScreen extends StatelessWidget {
static GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
final UserDetail userDetail;
const HomeScreen(this.userDetail, {Key? key}) : super(key: key);
final UserDetail user;
const HomeScreen(this.user, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -31,7 +31,8 @@ class HomeScreen extends StatelessWidget {
buildWhen: (previous, current) => previous != current,
builder: (context, state) {
return StyledContainer(
Theme.of(context).colorScheme.background,
Theme.of(context).colorScheme.surface,
// Colors.white,
child: _buildBody(
state, context.read<HomeBloc>().state.forceCollapse),
);
@ -74,7 +75,7 @@ class HomeScreen extends StatelessWidget {
isCollapseChanged: (isCollapse) {
homeBloc.add(HomeEvent.forceCollapse(isCollapse));
},
workspaceId: userDetail.workspace,
user: user,
);
homeMenu = RepaintBoundary(child: homeMenu);
homeMenu = FocusTraversalGroup(child: homeMenu);

View File

@ -1,32 +1,67 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/domain/image.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:app_flowy/workspace/presentation/app/app_widget.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/material.dart';
import 'package:flowy_infra_ui/style_widget/styled_icon_button.dart';
import 'package:flowy_infra_ui/style_widget/styled_hover.dart';
class ViewWidget extends StatelessWidget {
final View view;
final Widget icon;
const ViewWidget({Key? key, required this.view, required this.icon})
: super(key: key);
const ViewWidget({Key? key, required this.view}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(onTap: _openView(context), child: buildContent());
return InkWell(
onTap: _openView(context),
child: StyledHover(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(8),
builder: (context, onHover) => _render(context, onHover),
),
);
}
Row buildContent() {
return Row(
children: [
icon,
const SizedBox(
width: 4,
Widget _render(BuildContext context, bool onHover) {
const double width = 20;
List<Widget> children = [
Image(
fit: BoxFit.cover,
width: width,
height: width,
image: assetImageForViewType(view.viewType)),
const HSpace(6),
Text(
view.name,
textAlign: TextAlign.start,
style: const TextStyle(fontSize: 15),
),
];
if (onHover) {
children.add(const Spacer());
children.add(Align(
alignment: Alignment.center,
child: StyledMore(
width: width,
onPressed: () {},
),
Text(
view.name,
textAlign: TextAlign.start,
style: const TextStyle(fontSize: 15),
)
],
));
}
final padding = EdgeInsets.only(
left: AppWidgetSize.expandedPadding,
top: 5,
bottom: 5,
right: 5,
);
return Padding(
padding: padding,
child: Row(children: children),
);
}

View File

@ -2,30 +2,30 @@ import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/material.dart';
class BlankStackView extends HomeStackView {
const BlankStackView() : super(type: ViewType.Blank, title: 'Blank');
class AnnouncementStackView extends HomeStackView {
const AnnouncementStackView() : super(type: ViewType.Blank, title: 'Blank');
@override
List<Object> get props => [];
}
class BlankPage extends HomeStackWidget {
const BlankPage({Key? key, required BlankStackView stackView})
class AnnouncementPage extends HomeStackWidget {
const AnnouncementPage({Key? key, required AnnouncementStackView stackView})
: super(key: key, stackView: stackView);
@override
State<StatefulWidget> createState() => _BlankPageState();
State<StatefulWidget> createState() => _AnnouncementPage();
}
class _BlankPageState extends State<BlankPage> {
class _AnnouncementPage extends State<AnnouncementPage> {
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).colorScheme.primary,
child: const Center(
child: Text(
'Hello AppFlowy',
style: TextStyle(fontSize: 60),
return SizedBox.expand(
child: Container(
color: Theme.of(context).colorScheme.surface,
child: Padding(
padding: const EdgeInsets.all(10),
child: Container(),
),
),
);

View File

@ -1,49 +1,91 @@
import 'package:app_flowy/workspace/domain/image.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.dart';
import 'package:flutter/material.dart';
import 'package:flowy_infra_ui/style_widget/styled_icon_button.dart';
import 'package:flowy_infra_ui/style_widget/styled_text.dart';
class HomeTopBar extends StatelessWidget {
final String title;
const HomeTopBar({Key? key, required this.title}) : super(key: key);
final HomeStackView view;
const HomeTopBar({Key? key, required this.view}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: HomeInsets.topBarTitlePadding),
return SizedBox(
height: HomeSizes.topBarHeight,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
HomeTitle(title: title),
],
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 0.5, color: Colors.grey.shade300),
),
),
child: Padding(
padding:
EdgeInsets.symmetric(horizontal: HomeInsets.topBarTitlePadding),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
HomeTitle(title: view.title, type: view.type),
const Spacer(),
_renderShareButton(),
_renderMoreButton(),
],
),
),
),
);
}
Widget _renderShareButton() {
return RoundedTextButton(
title: 'Share',
height: 30,
width: 60,
fontSize: 12,
borderRadius: BorderRadius.circular(6),
color: Colors.lightBlue,
press: () {
debugPrint('share page');
},
);
}
Widget _renderMoreButton() {
return StyledMore(
width: 24,
onPressed: () {
debugPrint('show more');
},
);
}
}
class HomeTitle extends StatelessWidget {
final String title;
final _editingController = TextEditingController(
text: '',
);
final ViewType type;
HomeTitle({
const HomeTitle({
Key? key,
required this.title,
required this.type,
}) : super(key: key);
@override
Widget build(BuildContext context) {
_editingController.text = title;
return Expanded(
child: TextField(
controller: _editingController,
textAlign: TextAlign.left,
style: const TextStyle(fontSize: 28.0),
decoration: const InputDecoration(
hintText: 'Name the view',
border: UnderlineInputBorder(borderSide: BorderSide.none),
),
return Flexible(
child: Row(
children: [
Image(
fit: BoxFit.scaleDown,
width: 15,
height: 15,
image: assetImageForViewType(type)),
const HSpace(6),
StyledText(title, fontSize: 16),
],
),
);
}

View File

@ -1,29 +0,0 @@
import 'package:app_flowy/workspace/presentation/app/app_widget.dart';
import 'package:expandable/expandable.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
import 'package:flutter/material.dart';
import 'package:dartz/dartz.dart';
class AppList extends StatelessWidget {
final Option<List<App>> apps;
const AppList({required this.apps, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return apps.fold(() {
return const Expanded(child: Text('You have no apps, create one?'));
}, (apps) {
return ExpandableTheme(
data: const ExpandableThemeData(
iconColor: Colors.blue,
useInkWell: true,
),
child: Expanded(
child: ListView(
physics: const BouncingScrollPhysics(),
children: apps.map((app) => AppWidget(app)).toList(),
),
));
});
}
}

View File

@ -0,0 +1,65 @@
import 'package:app_flowy/startup/tasks/application_task.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/text_style.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/styled_text_input.dart';
import 'package:flowy_infra_ui/widget/buttons/ok_cancel_button.dart';
import 'package:flowy_infra_ui/widget/dialog/dialog_context.dart';
import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
// ignore: implementation_imports
import 'package:provider/src/provider.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
// ignore: must_be_immutable
class CreateAppDialogContext extends DialogContext {
String appName;
final Function(String)? confirm;
CreateAppDialogContext({this.appName = "", this.confirm})
: super(identifier: 'CreateAppDialogContext');
@override
Widget buildWiget(BuildContext context) {
final theme = context.watch<AppTheme>();
return StyledDialog(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
...[
Text('Create App'.toUpperCase(),
style: TextStyles.T1.textColor(theme.bg1)),
VSpace(Insets.sm * 1.5),
// Container(color: theme.greyWeak.withOpacity(.35), height: 1),
VSpace(Insets.m * 1.5),
],
StyledFormTextInput(
hintText: "App name",
onChanged: (text) {
appName = text;
},
),
SizedBox(height: Insets.l),
OkCancelButton(
onOkPressed: () {
if (confirm != null) {
confirm!(appName);
AppGlobals.nav.pop();
}
},
onCancelPressed: () {
AppGlobals.nav.pop();
},
)
],
),
);
}
@override
List<Object> get props => [identifier];
@override
bool get barrierDismissable => false;
}

View File

@ -1,34 +1,34 @@
import 'package:app_flowy/workspace/application/menu/menu_bloc.dart';
import 'package:app_flowy/workspace/application/menu/menu_watch.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/startup/tasks/application_task.dart';
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
import 'package:app_flowy/workspace/presentation/widgets/menu/menu_new_app.dart';
import 'package:app_flowy/workspace/presentation/widgets/menu/menu_top_bar.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/text_style.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/styled_text_input.dart';
import 'package:flowy_infra_ui/widget/buttons/ok_cancel_button.dart';
import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
import 'app_list.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/menu/menu_bloc.dart';
import 'package:app_flowy/workspace/application/menu/menu_watch.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:app_flowy/workspace/presentation/app/app_widget.dart';
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
import 'package:app_flowy/workspace/presentation/widgets/menu/menu_user.dart';
import 'menu_list.dart';
class HomeMenu extends StatelessWidget {
final Function(HomeStackView?) pageContextChanged;
final Function(bool) isCollapseChanged;
final String workspaceId;
final UserDetail user;
const HomeMenu(
{Key? key,
required this.pageContextChanged,
required this.isCollapseChanged,
required this.workspaceId})
required this.user})
: super(key: key);
@override
@ -36,10 +36,10 @@ class HomeMenu extends StatelessWidget {
return MultiBlocProvider(
providers: [
BlocProvider<MenuBloc>(
create: (context) => getIt<MenuBloc>(param1: workspaceId)
..add(const MenuEvent.initial())),
create: (context) =>
getIt<MenuBloc>(param1: user)..add(const MenuEvent.initial())),
BlocProvider(
create: (context) => getIt<MenuWatchBloc>(param1: workspaceId)
create: (context) => getIt<MenuWatchBloc>(param1: user)
..add(const MenuWatchEvent.started())),
],
child: MultiBlocListener(
@ -61,161 +61,82 @@ class HomeMenu extends StatelessWidget {
}
Widget _renderBody(BuildContext context) {
// nested cloumn: https://siddharthmolleti.com/flutter-box-constraints-nested-column-s-row-s-3dfacada7361
return Container(
color: Theme.of(context).colorScheme.primaryVariant,
color: Theme.of(context).colorScheme.background,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const MenuTopBar(),
_renderAppList(context),
_renderNewButton(context),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
_renderTopBar(context),
_renderMenuList(context),
],
).padding(horizontal: Insets.l),
),
_renderNewAppButton(context),
],
).padding(horizontal: Insets.sm),
);
}
Widget _renderAppList(BuildContext context) {
return BlocBuilder<MenuWatchBloc, MenuWatchState>(
builder: (context, state) => state.map(
initial: (_) => BlocBuilder<MenuBloc, MenuState>(
builder: (context, state) {
return AppList(apps: state.apps);
},
),
loadApps: (s) => AppList(apps: some(s.apps)),
loadFail: (s) => FlowyErrorPage(s.error.toString()),
),
);
}
Widget _renderNewButton(BuildContext context) {
return NewAppButton(
createAppCallback: (appName) =>
context.read<MenuBloc>().add(MenuEvent.createApp(appName, desc: "")),
);
}
}
class MenuTopBar extends StatelessWidget {
const MenuTopBar({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<MenuBloc, MenuState>(
Widget _renderMenuList(BuildContext context) {
return BlocBuilder<MenuWatchBloc, MenuWatchState>(
builder: (context, state) {
return SizedBox(
height: HomeSizes.menuTopBarHeight,
child: Row(
children: [
const Text(
'AppFlowy',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
).constrained(minWidth: 100),
const Spacer(),
IconButton(
icon: const Icon(Icons.arrow_left),
onPressed: () =>
context.read<MenuBloc>().add(const MenuEvent.collapse()),
),
],
return state.map(
initial: (_) => MenuList(
menuItems: menuItemsWithApps(context.read<MenuBloc>().state.apps),
),
loadApps: (s) => MenuList(
menuItems: menuItemsWithApps(some(s.apps)),
),
loadFail: (s) => FlowyErrorPage(s.error.toString()),
);
},
);
}
}
class NewAppButton extends StatelessWidget {
final Function(String)? createAppCallback;
Widget _renderNewAppButton(BuildContext context) {
return NewAppButton(
press: (appName) =>
context.read<MenuBloc>().add(MenuEvent.createApp(appName, desc: "")),
);
}
const NewAppButton({this.createAppCallback, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
Widget _renderTopBar(BuildContext context) {
return SizedBox(
height: HomeSizes.menuAddButtonHeight,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Icon(Icons.add),
const SizedBox(
width: 10,
),
TextButton(
onPressed: () async => await _showCreateAppDialog(context),
child: _buttonTitle(),
)
],
),
height: HomeSizes.menuTopBarHeight,
child: const MenuTopBar(),
);
}
Widget _buttonTitle() {
return const Text('New App',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20,
));
}
Future<void> _showCreateAppDialog(BuildContext context) async {
await Dialogs.showWithContext(CreateAppDialogContext(
confirm: (appName) {
if (appName.isNotEmpty && createAppCallback != null) {
createAppCallback!(appName);
}
},
), context);
List<MenuItem> menuItemsWithApps(Option<List<App>> someApps) {
return MenuItemBuilder().withUser(user).withApps(someApps).build();
}
}
//ignore: must_be_immutable
class CreateAppDialogContext extends DialogContext {
String appName;
final Function(String)? confirm;
class MenuItemBuilder {
List<MenuItem> items = [];
CreateAppDialogContext({this.appName = "", this.confirm})
: super(identifier: 'CreateAppDialogContext');
MenuItemBuilder();
@override
Widget buildWiget(BuildContext context) {
final theme = context.watch<AppTheme>();
return StyledDialog(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
...[
Text('Create App'.toUpperCase(),
style: TextStyles.T1.textColor(theme.accent1Darker)),
VSpace(Insets.sm * 1.5),
// Container(color: theme.greyWeak.withOpacity(.35), height: 1),
VSpace(Insets.m * 1.5),
],
StyledFormTextInput(
hintText: "App name",
onChanged: (text) {
appName = text;
},
),
SizedBox(height: Insets.l),
OkCancelButton(
onOkPressed: () {
if (confirm != null) {
confirm!(appName);
AppGlobals.nav.pop();
}
},
onCancelPressed: () {
AppGlobals.nav.pop();
},
)
],
),
MenuItemBuilder withUser(UserDetail user) {
items.add(MenuUser(user));
return this;
}
MenuItemBuilder withApps(Option<List<App>> someApps) {
List<MenuItem> appWidgets = someApps.foldRight(
[],
(apps, _) => apps.map((app) => AppWidget(app)).toList(),
);
items.addAll(appWidgets);
return this;
}
@override
List<Object> get props => [identifier];
@override
bool get barrierDismissable => false;
List<MenuItem> build() {
return items;
}
}

View File

@ -0,0 +1,40 @@
import 'package:expandable/expandable.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_infra/time/duration.dart';
import 'package:flutter/material.dart';
enum MenuItemType {
userProfile,
dashboard,
favorites,
app,
}
abstract class MenuItem extends StatelessWidget {
const MenuItem({Key? key}) : super(key: key);
MenuItemType get type;
}
class MenuList extends StatelessWidget {
final List<MenuItem> menuItems;
const MenuList({required this.menuItems, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ExpandableTheme(
data: ExpandableThemeData(
useInkWell: true, animationDuration: Durations.medium),
child: Expanded(
child: ListView.separated(
itemCount: menuItems.length,
separatorBuilder: (context, index) => const VSpace(10),
physics: const BouncingScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return menuItems[index];
},
),
),
);
}
}

View File

@ -0,0 +1,50 @@
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
import 'package:app_flowy/workspace/presentation/widgets/menu/create_app_dialog.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
import 'package:flutter/material.dart';
import 'package:styled_widget/styled_widget.dart';
class NewAppButton extends StatelessWidget {
final Function(String)? press;
const NewAppButton({this.press, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(width: 1, color: Colors.grey.shade300),
),
),
height: HomeSizes.menuAddButtonHeight,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Icon(Icons.add_circle_rounded, size: 30),
TextButton(
onPressed: () async => await _showCreateAppDialog(context),
child: const Text(
'New App',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
)
],
).padding(horizontal: Insets.l),
);
}
Future<void> _showCreateAppDialog(BuildContext context) async {
await Dialogs.showWithContext(CreateAppDialogContext(
confirm: (appName) {
if (appName.isNotEmpty && press != null) {
press!(appName);
}
},
), context);
}
}

View File

@ -1,4 +0,0 @@
class HomeMenuSize {
static double get createViewButtonSize => 30;
static double get collapseIconSize => 24;
}

View File

@ -0,0 +1,37 @@
import 'package:app_flowy/workspace/application/menu/menu_bloc.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class MenuTopBar extends StatelessWidget {
const MenuTopBar({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<MenuBloc, MenuState>(
builder: (context, state) {
return Row(
children: [
const Image(
fit: BoxFit.cover,
width: 25,
height: 25,
image: AssetImage('assets/images/app_flowy_logo.jpg')),
const HSpace(8),
const Text(
'AppFlowy',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
const Spacer(),
IconButton(
icon: const Icon(Icons.arrow_left),
alignment: Alignment.centerRight,
padding: EdgeInsets.zero,
onPressed: () =>
context.read<MenuBloc>().add(const MenuEvent.collapse()),
),
],
);
},
);
}
}

View File

@ -0,0 +1,66 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/menu/menu_user_bloc.dart';
import 'package:app_flowy/workspace/presentation/widgets/menu/menu_list.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_detail.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flowy_infra_ui/style_widget/styled_text.dart';
import 'package:flowy_infra_ui/style_widget/styled_icon_button.dart';
class MenuUser extends MenuItem {
final UserDetail user;
MenuUser(this.user, {Key? key}) : super(key: ValueKey(user.id));
@override
Widget build(BuildContext context) {
return BlocProvider<MenuUserBloc>(
create: (context) =>
getIt<MenuUserBloc>(param1: user)..add(const MenuUserEvent.initial()),
child: BlocBuilder<MenuUserBloc, MenuUserState>(
builder: (context, state) => Row(children: [
_renderAvatar(context),
const HSpace(10),
_renderUserName(context),
const HSpace(10),
_renderDropButton(context),
]),
),
);
}
Widget _renderAvatar(BuildContext context) {
return SizedBox(
width: 30,
height: 30,
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: const Image(image: AssetImage('assets/images/avatar.jpg')),
),
);
}
Widget _renderUserName(BuildContext context) {
String name = context.read<MenuUserBloc>().state.user.name;
if (name.isEmpty) {
name = context.read<MenuUserBloc>().state.user.email;
}
return Flexible(
child: StyledText(name, fontSize: 18),
);
}
Widget _renderDropButton(BuildContext context) {
return StyledIconButton(
width: 30,
iconRatio: 0.8,
icon: const Icon(Icons.arrow_drop_down),
onPressed: () {
debugPrint('show user profile');
},
);
}
@override
MenuItemType get type => MenuItemType.userProfile;
}

View File

@ -1,2 +1 @@
export 'menu.dart';
export 'menu_size.dart';

View File

@ -49,4 +49,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
COCOAPODS: 1.9.3
COCOAPODS: 1.10.1

View File

@ -10,10 +10,16 @@ import '../model/document/document.dart';
import '../model/document/style.dart';
import '../model/document/node/embed.dart';
abstract class EditorPersistence {
Future<bool> save(List<dynamic> jsonList);
}
class EditorController extends ChangeNotifier {
final EditorPersistence? persistence;
EditorController({
required this.document,
required this.selection,
this.persistence,
});
factory EditorController.basic() {
@ -38,7 +44,8 @@ class EditorController extends ChangeNotifier {
);
Style getSelectionStyle() =>
document.collectStyle(selection.start, selection.end - selection.start)..mergeAll(toggledStyle);
document.collectStyle(selection.start, selection.end - selection.start)
..mergeAll(toggledStyle);
bool get hasUndo => document.hasUndo;
@ -58,10 +65,10 @@ class EditorController extends ChangeNotifier {
}
}
Future<bool> save() async {
document.toDelta().toJson();
// TODO: vedon - Save document to database
return true;
void save() {
if (persistence != null) {
persistence!.save(document.toDelta().toJson());
}
}
@override
@ -80,7 +87,9 @@ class EditorController extends ChangeNotifier {
}
void formatText(int index, int length, Attribute? attribute) {
if (length == 0 && attribute!.isInline && attribute.key != Attribute.link.key) {
if (length == 0 &&
attribute!.isInline &&
attribute.key != Attribute.link.key) {
toggledStyle = toggledStyle.put(attribute);
}
@ -95,16 +104,25 @@ class EditorController extends ChangeNotifier {
notifyListeners();
}
void replaceText(int index, int length, Object? data, TextSelection? textSelection) {
void replaceText(
int index, int length, Object? data, TextSelection? textSelection) {
assert(data is String || data is Embeddable);
Delta? delta;
if (length > 0 || data is! String || data.isNotEmpty) {
delta = document.replace(index, length, data);
var shouldRetainDelta = toggledStyle.isNotEmpty && delta.isNotEmpty && delta.length <= 2 && delta.last.isInsert;
if (shouldRetainDelta && toggledStyle.isNotEmpty && delta.length == 2 && delta.last.data == '\n') {
print(delta);
var shouldRetainDelta = toggledStyle.isNotEmpty &&
delta.isNotEmpty &&
delta.length <= 2 &&
delta.last.isInsert;
if (shouldRetainDelta &&
toggledStyle.isNotEmpty &&
delta.length == 2 &&
delta.last.data == '\n') {
// if all attributes are inline, shouldRetainDelta should be false
final anyAttributeNotInline = toggledStyle.values.any((attr) => !attr.isInline);
final anyAttributeNotInline =
toggledStyle.values.any((attr) => !attr.isInline);
shouldRetainDelta &= anyAttributeNotInline;
}
if (shouldRetainDelta) {
@ -146,7 +164,8 @@ class EditorController extends ChangeNotifier {
textSelection = selection.copyWith(
baseOffset: delta.transformPosition(selection.baseOffset, force: false),
extentOffset: delta.transformPosition(selection.extentOffset, force: false),
extentOffset:
delta.transformPosition(selection.extentOffset, force: false),
);
if (selection != textSelection) {
_updateSelection(textSelection, source);

View File

@ -60,7 +60,8 @@ class RawEditor extends StatefulWidget {
this.embedBuilder,
) : assert(maxHeight == null || maxHeight > 0, 'maxHeight cannot be null'),
assert(minHeight == null || minHeight >= 0, 'minHeight cannot be null'),
assert(maxHeight == null || minHeight == null || maxHeight >= minHeight),
assert(
maxHeight == null || minHeight == null || maxHeight >= minHeight),
showCursor = showCursor ?? true,
super(key: key);
@ -111,7 +112,10 @@ abstract class EditorState extends State<RawEditor> {
}
class _RawEditorState extends EditorState
with AutomaticKeepAliveClientMixin<RawEditor>, WidgetsBindingObserver, TickerProviderStateMixin<RawEditor>
with
AutomaticKeepAliveClientMixin<RawEditor>,
WidgetsBindingObserver,
TickerProviderStateMixin<RawEditor>
implements TextSelectionDelegate, TextInputClient {
final GlobalKey _editorKey = GlobalKey();
final List<TextEditingValue> _sentRemoteValues = [];
@ -129,7 +133,8 @@ class _RawEditorState extends EditorState
bool _didAutoFocus = false;
bool _keyboardVisible = false;
DefaultStyles? _styles;
final ClipboardStatusNotifier? _clipboardStatus = kIsWeb ? null : ClipboardStatusNotifier();
final ClipboardStatusNotifier? _clipboardStatus =
kIsWeb ? null : ClipboardStatusNotifier();
final LayerLink _toolbarLayerLink = LayerLink();
final LayerLink _startHandleLayerLink = LayerLink();
final LayerLink _endHandleLayerLink = LayerLink();
@ -177,57 +182,78 @@ class _RawEditorState extends EditorState
downKey = key == LogicalKeyboardKey.arrowDown;
if ((rightKey || leftKey) && !(rightKey && leftKey)) {
newSelection =
_jumpToBeginOrEndOfWord(newSelection, wordModifier, leftKey, rightKey, plainText, lineModifier, shift);
newSelection = _jumpToBeginOrEndOfWord(newSelection, wordModifier,
leftKey, rightKey, plainText, lineModifier, shift);
}
if (downKey || upKey) {
newSelection = _handleMovingCursorVertically(upKey, downKey, shift, selection, newSelection, plainText);
newSelection = _handleMovingCursorVertically(
upKey, downKey, shift, selection, newSelection, plainText);
}
if (!shift) {
newSelection = _placeCollapsedSelection(selection, newSelection, leftKey, rightKey);
newSelection =
_placeCollapsedSelection(selection, newSelection, leftKey, rightKey);
}
widget.controller.updateSelection(newSelection, ChangeSource.LOCAL);
}
TextSelection _placeCollapsedSelection(
TextSelection selection, TextSelection newSelection, bool leftKey, bool rightKey) {
TextSelection _placeCollapsedSelection(TextSelection selection,
TextSelection newSelection, bool leftKey, bool rightKey) {
var newOffset = newSelection.extentOffset;
if (!selection.isCollapsed) {
if (leftKey) {
newOffset =
newSelection.baseOffset < newSelection.extentOffset ? newSelection.baseOffset : newSelection.extentOffset;
newOffset = newSelection.baseOffset < newSelection.extentOffset
? newSelection.baseOffset
: newSelection.extentOffset;
} else if (rightKey) {
newOffset =
newSelection.baseOffset > newSelection.extentOffset ? newSelection.baseOffset : newSelection.extentOffset;
newOffset = newSelection.baseOffset > newSelection.extentOffset
? newSelection.baseOffset
: newSelection.extentOffset;
}
}
return TextSelection.fromPosition(TextPosition(offset: newOffset));
}
TextSelection _handleMovingCursorVertically(
bool upKey, bool downKey, bool shift, TextSelection selection, TextSelection newSelection, String plainText) {
final originPosition = TextPosition(offset: upKey ? selection.baseOffset : selection.extentOffset);
bool upKey,
bool downKey,
bool shift,
TextSelection selection,
TextSelection newSelection,
String plainText) {
final originPosition = TextPosition(
offset: upKey ? selection.baseOffset : selection.extentOffset);
final child = getRenderEditor()!.childAtPosition(originPosition);
final localPosition = TextPosition(offset: originPosition.offset - child.container.documentOffset);
final localPosition = TextPosition(
offset: originPosition.offset - child.container.documentOffset);
var position = upKey ? child.getPositionAbove(localPosition) : child.getPositionBelow(localPosition);
var position = upKey
? child.getPositionAbove(localPosition)
: child.getPositionBelow(localPosition);
if (position == null) {
final sibling = upKey ? getRenderEditor()!.childBefore(child) : getRenderEditor()!.childAfter(child);
final sibling = upKey
? getRenderEditor()!.childBefore(child)
: getRenderEditor()!.childAfter(child);
if (sibling == null) {
position = TextPosition(offset: upKey ? 0 : plainText.length - 1);
} else {
final finalOffset = Offset(child.getOffsetForCaret(localPosition).dx,
sibling.getOffsetForCaret(TextPosition(offset: upKey ? sibling.container.length - 1 : 0)).dy);
final finalOffset = Offset(
child.getOffsetForCaret(localPosition).dx,
sibling
.getOffsetForCaret(TextPosition(
offset: upKey ? sibling.container.length - 1 : 0))
.dy);
final siblingPosition = sibling.getPositionForOffset(finalOffset);
position = TextPosition(offset: sibling.container.documentOffset + siblingPosition.offset);
position = TextPosition(
offset: sibling.container.documentOffset + siblingPosition.offset);
}
} else {
position = TextPosition(offset: child.container.documentOffset + position.offset);
position = TextPosition(
offset: child.container.documentOffset + position.offset);
}
if (position.offset == newSelection.extentOffset) {
@ -250,33 +276,47 @@ class _RawEditorState extends EditorState
return newSelection;
}
TextSelection _jumpToBeginOrEndOfWord(TextSelection newSelection, bool wordModifier, bool leftKey, bool rightKey,
String plainText, bool lineModifier, bool shift) {
TextSelection _jumpToBeginOrEndOfWord(
TextSelection newSelection,
bool wordModifier,
bool leftKey,
bool rightKey,
String plainText,
bool lineModifier,
bool shift) {
if (wordModifier) {
if (leftKey) {
final textSelection = getRenderEditor()!.selectWordAtPosition(
TextPosition(offset: _previousCharacter(newSelection.extentOffset, plainText, false)));
TextPosition(
offset: _previousCharacter(
newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.baseOffset);
}
final textSelection = getRenderEditor()!
.selectWordAtPosition(TextPosition(offset: _nextCharacter(newSelection.extentOffset, plainText, false)));
final textSelection = getRenderEditor()!.selectWordAtPosition(
TextPosition(
offset:
_nextCharacter(newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.extentOffset);
} else if (lineModifier) {
if (leftKey) {
final textSelection = getRenderEditor()!.selectLineAtPosition(
TextPosition(offset: _previousCharacter(newSelection.extentOffset, plainText, false)));
TextPosition(
offset: _previousCharacter(
newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.baseOffset);
}
final startPoint = newSelection.extentOffset;
if (startPoint < plainText.length) {
final textSelection = getRenderEditor()!.selectLineAtPosition(TextPosition(offset: startPoint));
final textSelection = getRenderEditor()!
.selectLineAtPosition(TextPosition(offset: startPoint));
return newSelection.copyWith(extentOffset: textSelection.extentOffset);
}
return newSelection;
}
if (rightKey && newSelection.extentOffset < plainText.length) {
final nextExtent = _nextCharacter(newSelection.extentOffset, plainText, true);
final nextExtent =
_nextCharacter(newSelection.extentOffset, plainText, true);
final distance = nextExtent - newSelection.extentOffset;
newSelection = newSelection.copyWith(extentOffset: nextExtent);
if (shift) {
@ -286,7 +326,8 @@ class _RawEditorState extends EditorState
}
if (leftKey && newSelection.extentOffset > 0) {
final previousExtent = _previousCharacter(newSelection.extentOffset, plainText, true);
final previousExtent =
_previousCharacter(newSelection.extentOffset, plainText, true);
final distance = newSelection.extentOffset - previousExtent;
newSelection = newSelection.copyWith(extentOffset: previousExtent);
if (shift) {
@ -326,7 +367,9 @@ class _RawEditorState extends EditorState
var count = 0;
int? lastNonWhitespace;
for (final currentString in string.characters) {
if (!includeWhitespace && !WHITE_SPACE.contains(currentString.characters.first.toString().codeUnitAt(0))) {
if (!includeWhitespace &&
!WHITE_SPACE.contains(
currentString.characters.first.toString().codeUnitAt(0))) {
lastNonWhitespace = count;
}
if (count + currentString.length >= index) {
@ -337,7 +380,8 @@ class _RawEditorState extends EditorState
return 0;
}
bool get hasConnection => _textInputConnection != null && _textInputConnection!.attached;
bool get hasConnection =>
_textInputConnection != null && _textInputConnection!.attached;
void openConnectionIfNeeded() {
if (!shouldCreateInputConnection) {
@ -388,7 +432,8 @@ class _RawEditorState extends EditorState
return;
}
final shouldRemember = textEditingValue.text != _lastKnownRemoteTextEditingValue!.text;
final shouldRemember =
textEditingValue.text != _lastKnownRemoteTextEditingValue!.text;
_lastKnownRemoteTextEditingValue = actualValue;
_textInputConnection!.setEditingState(actualValue);
if (shouldRemember) {
@ -397,7 +442,8 @@ class _RawEditorState extends EditorState
}
@override
TextEditingValue? get currentTextEditingValue => _lastKnownRemoteTextEditingValue;
TextEditingValue? get currentTextEditingValue =>
_lastKnownRemoteTextEditingValue;
@override
AutofillScope? get currentAutofillScope => null;
@ -429,7 +475,8 @@ class _RawEditorState extends EditorState
final text = value.text;
final cursorPosition = value.selection.extentOffset;
final diff = getDiff(oldText, text, cursorPosition);
widget.controller.replaceText(diff.start, diff.deleted.length, diff.inserted, value.selection);
widget.controller.replaceText(
diff.start, diff.deleted.length, diff.inserted, value.selection);
}
@override
@ -479,8 +526,11 @@ class _RawEditorState extends EditorState
super.build(context);
var _doc = widget.controller.document;
if (_doc.isEmpty() && !widget.focusNode.hasFocus && widget.placeholder != null) {
_doc = Document.fromJson(jsonDecode('[{"attributes":{"placeholder":true},"insert":"${widget.placeholder}\\n"}]'));
if (_doc.isEmpty() &&
!widget.focusNode.hasFocus &&
widget.placeholder != null) {
_doc = Document.fromJson(jsonDecode(
'[{"attributes":{"placeholder":true},"insert":"${widget.placeholder}\\n"}]'));
}
Widget child = CompositedTransformTarget(
@ -503,7 +553,8 @@ class _RawEditorState extends EditorState
);
if (widget.scrollable) {
final baselinePadding = EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1);
final baselinePadding =
EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1);
child = BaselineProxy(
textStyle: _styles!.paragraph!.style,
padding: baselinePadding,
@ -534,7 +585,8 @@ class _RawEditorState extends EditorState
);
}
void _handleSelectionChanged(TextSelection selection, SelectionChangedCause cause) {
void _handleSelectionChanged(
TextSelection selection, SelectionChangedCause cause) {
widget.controller.updateSelection(selection, ChangeSource.LOCAL);
_selectionOverlay?.handlesVisible = _shouldShowSelectionHandles();
@ -563,7 +615,9 @@ class _RawEditorState extends EditorState
_styles,
widget.enableInteractiveSelection,
_hasFocus,
attrs.containsKey(Attribute.codeBlock.key) ? const EdgeInsets.all(16) : null,
attrs.containsKey(Attribute.codeBlock.key)
? const EdgeInsets.all(16)
: null,
widget.embedBuilder,
_cursorController,
indentLevelCounts);
@ -575,7 +629,8 @@ class _RawEditorState extends EditorState
return result;
}
EditableTextLine _getEditableTextLineFromNode(Line node, BuildContext context) {
EditableTextLine _getEditableTextLineFromNode(
Line node, BuildContext context) {
final textLine = TextLine(
line: node,
textDirection: _textDirection,
@ -598,7 +653,8 @@ class _RawEditorState extends EditorState
return editableTextLine;
}
Tuple2<double, double> _getVerticalSpacingForLine(Line line, DefaultStyles? defaultStyles) {
Tuple2<double, double> _getVerticalSpacingForLine(
Line line, DefaultStyles? defaultStyles) {
final attrs = line.style.attributes;
if (attrs.containsKey(Attribute.header.key)) {
final int? level = attrs[Attribute.header.key]!.value;
@ -623,7 +679,8 @@ class _RawEditorState extends EditorState
return defaultStyles!.paragraph!.verticalSpacing;
}
Tuple2<double, double> _getVerticalSpacingForBlock(Block node, DefaultStyles? defaultStyles) {
Tuple2<double, double> _getVerticalSpacingForBlock(
Block node, DefaultStyles? defaultStyles) {
final attrs = node.style.attributes;
if (attrs.containsKey(Attribute.quoteBlock.key)) {
return defaultStyles!.quote!.verticalSpacing;
@ -666,7 +723,8 @@ class _RawEditorState extends EditorState
} else {
_keyboardVisibilityController = KeyboardVisibilityController();
_keyboardVisible = _keyboardVisibilityController!.isVisible;
_keyboardVisibilitySubscription = _keyboardVisibilityController?.onChange.listen((visible) {
_keyboardVisibilitySubscription =
_keyboardVisibilityController?.onChange.listen((visible) {
_keyboardVisible = visible;
if (visible) {
_onChangeTextEditingValue();
@ -689,7 +747,9 @@ class _RawEditorState extends EditorState
super.didChangeDependencies();
final parentStyles = EditorStyles.getStyles(context, true);
final defaultStyles = DefaultStyles.getInstance(context);
_styles = (parentStyles != null) ? defaultStyles.merge(parentStyles) : defaultStyles;
_styles = (parentStyles != null)
? defaultStyles.merge(parentStyles)
: defaultStyles;
if (widget.customStyles != null) {
_styles = _styles!.merge(widget.customStyles!);
@ -749,7 +809,8 @@ class _RawEditorState extends EditorState
}
bool _shouldShowSelectionHandles() {
return widget.showSelectionHandles && !widget.controller.selection.isCollapsed;
return widget.showSelectionHandles &&
!widget.controller.selection.isCollapsed;
}
void handleDelete(bool forward) {
@ -760,7 +821,8 @@ class _RawEditorState extends EditorState
var textAfter = selection.textAfter(plainText);
if (selection.isCollapsed) {
if (!forward && textBefore.isNotEmpty) {
final characterBoundary = _previousCharacter(textBefore.length, textBefore, true);
final characterBoundary =
_previousCharacter(textBefore.length, textBefore, true);
textBefore = textBefore.substring(0, characterBoundary);
cursorPosition = characterBoundary;
}
@ -784,15 +846,13 @@ class _RawEditorState extends EditorState
final selection = widget.controller.selection;
final plainText = textEditingValue.text;
if (shortcut == InputShortcut.SAVE) {
bool saved = await widget.controller.save();
if (!saved) {
log('Unabled to save document.');
}
widget.controller.save();
return;
}
if (shortcut == InputShortcut.COPY) {
if (!selection.isCollapsed) {
await Clipboard.setData(ClipboardData(text: selection.textInside(plainText)));
await Clipboard.setData(
ClipboardData(text: selection.textInside(plainText)));
}
return;
}
@ -809,7 +869,8 @@ class _RawEditorState extends EditorState
);
textEditingValue = TextEditingValue(
text: selection.textBefore(plainText) + selection.textAfter(plainText),
text:
selection.textBefore(plainText) + selection.textAfter(plainText),
selection: TextSelection.collapsed(offset: selection.start),
);
}
@ -827,7 +888,8 @@ class _RawEditorState extends EditorState
}
return;
}
if (shortcut == InputShortcut.SELECT_ALL && widget.enableInteractiveSelection) {
if (shortcut == InputShortcut.SELECT_ALL &&
widget.enableInteractiveSelection) {
widget.controller.updateSelection(
selection.copyWith(
baseOffset: 0,
@ -881,14 +943,16 @@ class _RawEditorState extends EditorState
void _onChangeTextEditingValue() {
_showCaretOnScreen();
updateRemoteValueIfNeeded();
_cursorController.startOrStopCursorTimerIfNeeded(_hasFocus, widget.controller.selection);
_cursorController.startOrStopCursorTimerIfNeeded(
_hasFocus, widget.controller.selection);
if (hasConnection) {
_cursorController
..stopCursorTimer(resetCharTicks: false)
..startCursorTimer();
}
SchedulerBinding.instance!.addPostFrameCallback((_) => _updateOrDisposeSelectionOverlayIfNeeded());
SchedulerBinding.instance!.addPostFrameCallback(
(_) => _updateOrDisposeSelectionOverlayIfNeeded());
if (mounted) {
setState(() {
// Use widget.controller.value in build()
@ -931,7 +995,8 @@ class _RawEditorState extends EditorState
void _handleFocusChanged() {
openOrCloseConnection();
_cursorController.startOrStopCursorTimerIfNeeded(_hasFocus, widget.controller.selection);
_cursorController.startOrStopCursorTimerIfNeeded(
_hasFocus, widget.controller.selection);
_updateOrDisposeSelectionOverlayIfNeeded();
if (_hasFocus) {
WidgetsBinding.instance!.addObserver(this);
@ -962,7 +1027,8 @@ class _RawEditorState extends EditorState
_showCaretOnScreenScheduled = false;
final viewport = RenderAbstractViewport.of(getRenderEditor())!;
final editorOffset = getRenderEditor()!.localToGlobal(const Offset(0, 0), ancestor: viewport);
final editorOffset = getRenderEditor()!
.localToGlobal(const Offset(0, 0), ancestor: viewport);
final offsetInViewport = _scrollController!.offset + editorOffset.dy;
final offset = getRenderEditor()!.getOffsetToRevealCursor(
@ -1045,7 +1111,8 @@ class _RawEditorState extends EditorState
final value = textEditingValue;
final data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null) {
final length = textEditingValue.selection.end - textEditingValue.selection.start;
final length =
textEditingValue.selection.end - textEditingValue.selection.start;
widget.controller.replaceText(
value.selection.start,
length,
@ -1054,7 +1121,9 @@ class _RawEditorState extends EditorState
);
// move cursor to the end of pasted text selection
widget.controller.updateSelection(
TextSelection.collapsed(offset: value.selection.start + data.text!.length), ChangeSource.LOCAL);
TextSelection.collapsed(
offset: value.selection.start + data.text!.length),
ChangeSource.LOCAL);
}
}
}
@ -1064,7 +1133,8 @@ class _RawEditorState extends EditorState
if (data == null) {
return false;
}
return textEditingValue.text.length - value.text.length == data.text!.length;
return textEditingValue.text.length - value.text.length ==
data.text!.length;
}
@override
@ -1097,7 +1167,8 @@ class _RawEditorState extends EditorState
}
@override
void userUpdateTextEditingValue(TextEditingValue value, SelectionChangedCause cause) {
void userUpdateTextEditingValue(
TextEditingValue value, SelectionChangedCause cause) {
// TODO: implement userUpdateTextEditingValue
}
}
@ -1147,7 +1218,8 @@ class _Editor extends MultiChildRenderObjectWidget {
}
@override
void updateRenderObject(BuildContext context, covariant RenderEditor renderObject) {
void updateRenderObject(
BuildContext context, covariant RenderEditor renderObject) {
renderObject
..document = document
..container = document.root

View File

@ -54,7 +54,7 @@ class Sizes {
static double get sideBarSm => 200 * hitScale;
static double get sideBarMed => 220 * hitScale;
static double get sideBarMed => 240 * hitScale;
static double get sideBarLg => 290 * hitScale;
}

View File

@ -39,7 +39,7 @@ class AppTheme {
switch (t) {
case ThemeType.light:
return AppTheme(isDark: false)
..bg1 = const Color(0xfff1f7f0)
..bg1 = const Color.fromARGB(255, 247, 248, 252)
..bg2 = const Color(0xffc1dcbc)
..surface = Colors.white
..accent1 = const Color(0xff00a086)

View File

@ -13,4 +13,5 @@ class Durations {
class RouteDurations {
static Duration get slow => .7.seconds;
static Duration get medium => .35.seconds;
}

View File

@ -156,6 +156,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
loading_indicator:
dependency: transitive
description:
name: loading_indicator
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
logger:
dependency: transitive
description:
@ -296,4 +303,4 @@ packages:
version: "2.1.0"
sdks:
dart: ">=2.12.0 <3.0.0"
flutter: ">=1.20.0"
flutter: ">=2.0.0"

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
// ignore: unused_import
import 'package:flowy_infra/time/duration.dart';
typedef HoverBuilder = Widget Function(BuildContext context, bool onHover);
class StyledHover extends StatefulWidget {
final Color color;
final Color borderColor;
final double borderWidth;
final BorderRadius borderRadius;
final HoverBuilder builder;
const StyledHover({
Key? key,
required this.color,
this.borderColor = Colors.transparent,
this.borderWidth = 0,
this.borderRadius = BorderRadius.zero,
required this.builder,
}) : super(key: key);
@override
State<StyledHover> createState() => _StyledHoverState();
}
class _StyledHoverState extends State<StyledHover> {
bool _onHover = false;
@override
Widget build(BuildContext context) {
final hoverColor =
_onHover ? widget.color : Theme.of(context).colorScheme.background;
final hoverBorder = Border.all(
color: widget.borderColor,
width: widget.borderWidth,
);
return MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (p) => setOnHover(true),
onExit: (p) => setOnHover(false),
child: Container(
decoration: BoxDecoration(
border: hoverBorder,
color: hoverColor,
borderRadius: widget.borderRadius,
),
// duration: .1.seconds,
child: widget.builder(context, _onHover),
),
);
}
void setOnHover(bool value) => setState(() => _onHover = value);
}

View File

@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
class StyledIconButton extends StatelessWidget {
final double width;
final double? height;
final double iconRatio;
final Icon icon;
final VoidCallback? onPressed;
const StyledIconButton({
Key? key,
this.height,
this.onPressed,
this.width = 30,
required this.icon,
this.iconRatio = 0.5,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
width: width,
height: height ?? width,
child: IconButton(
icon: icon,
padding: EdgeInsets.zero,
iconSize: width * iconRatio,
alignment: Alignment.center,
onPressed: onPressed,
),
);
}
}
class StyledMore extends StatelessWidget {
final double width;
final double? height;
final VoidCallback? onPressed;
const StyledMore({
Key? key,
this.height,
this.onPressed,
required this.width,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return StyledIconButton(
width: width,
height: height,
icon: const Icon(Icons.more_vert),
);
}
}

View File

@ -0,0 +1,107 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
typedef NaviAction = void Function(String);
abstract class NaviItem {
String get identifier;
NaviAction get action;
}
class StyledNavigationController extends ChangeNotifier {
List<NaviItem> naviItems;
StyledNavigationController({this.naviItems = const []});
}
class StyledNavigationList extends StatelessWidget {
const StyledNavigationList({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => StyledNavigationController()),
],
child: Consumer(builder: (ctx, StyledNavigationController ctrl, child) {
return Row(
children: _buildNaviItemWidget(ctrl.naviItems),
);
}),
);
}
List<Widget> _buildNaviItemWidget(List<NaviItem> items) {
if (items.isEmpty) {
return [];
}
List<NaviItem> newItems = _selectNaviItem(items);
Widget last = NaviItemWidget(newItems.removeLast());
List<Widget> widgets = newItems
.map(
(item) => NaviItemDivider(
child: NaviItemWidget(item),
),
)
.toList();
widgets.add(last);
return widgets;
}
List<NaviItem> _selectNaviItem(List<NaviItem> items) {
final length = items.length;
if (length > 4) {
final ellipsisItems = items.getRange(1, length - 2).toList();
return [
items[0],
EllipsisNaviItem(items: ellipsisItems),
items[length - 2],
items[length - 1]
];
} else {
return items;
}
}
}
class NaviItemWidget extends StatelessWidget {
final NaviItem item;
const NaviItemWidget(this.item, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: null,
);
}
}
class NaviItemDivider extends StatelessWidget {
final Widget child;
const NaviItemDivider({Key? key, required this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: [child, const Text('/')],
);
}
}
class EllipsisNaviItem extends NaviItem {
final List<NaviItem> items;
EllipsisNaviItem({
required this.items,
});
@override
// TODO: implement action
NaviAction get action => throw UnimplementedError();
@override
// TODO: implement identifier
String get identifier => throw UnimplementedError();
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:loading_indicator/loading_indicator.dart';
List<Color> _kDefaultRainbowColors = const [
Colors.red,
Colors.orange,
Colors.yellow,
Colors.green,
Colors.blue,
Colors.indigo,
Colors.purple,
];
// CircularProgressIndicator()
class StyledProgressIndicator extends StatelessWidget {
const StyledProgressIndicator({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox.expand(
child: Center(
child: SizedBox(
width: 60,
child: LoadingIndicator(
indicatorType: Indicator.pacman,
colors: _kDefaultRainbowColors,
strokeWidth: 4.0,
),
),
),
);
}
}

View File

@ -0,0 +1,23 @@
import 'package:flutter/widgets.dart';
class StyledText extends StatelessWidget {
final String title;
final TextOverflow overflow;
final double fontSize;
const StyledText(
this.title, {
Key? key,
this.overflow = TextOverflow.ellipsis,
this.fontSize = 16,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(
title,
overflow: overflow,
softWrap: false,
style: TextStyle(fontSize: fontSize),
);
}
}

View File

@ -0,0 +1,54 @@
import 'package:flowy_infra_ui/style_widget/styled_hover.dart';
import 'package:flowy_infra_ui/style_widget/styled_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class StyledTextButton extends StatelessWidget {
final String text;
final double fontSize;
final VoidCallback? onPressed;
final EdgeInsets padding;
const StyledTextButton(this.text,
{Key? key,
this.onPressed,
this.fontSize = 16,
this.padding = const EdgeInsets.symmetric(horizontal: 8, vertical: 6)})
: super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onPressed,
child: StyledHover(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(8),
builder: (context, onHover) => _render(),
),
);
}
Widget _render() {
return Padding(
padding: padding,
child: Align(
alignment: Alignment.centerLeft,
child: StyledText(text, fontSize: fontSize),
),
);
}
}
// return TextButton(
// style: ButtonStyle(
// textStyle: MaterialStateProperty.all(TextStyle(fontSize: fontSize)),
// alignment: Alignment.centerLeft,
// foregroundColor: MaterialStateProperty.all(Colors.black),
// padding: MaterialStateProperty.all<EdgeInsets>(
// const EdgeInsets.symmetric(horizontal: 2)),
// ),
// onPressed: onPressed,
// child: Text(
// text,
// overflow: TextOverflow.ellipsis,
// softWrap: false,
// ),
// );

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
typedef HoverBuilder = Widget Function(BuildContext context, bool isHovering);
typedef HoverBuilder = Widget Function(BuildContext context, bool onHover);
class MouseHoverBuilder extends StatefulWidget {
final bool isClickable;
@ -15,17 +15,17 @@ class MouseHoverBuilder extends StatefulWidget {
}
class _MouseHoverBuilderState extends State<MouseHoverBuilder> {
bool isOver = false;
bool _onHover = false;
@override
Widget build(BuildContext context) {
return MouseRegion(
cursor: widget.isClickable ? SystemMouseCursors.click : SystemMouseCursors.basic,
onEnter: (p) => setOver(true),
onExit: (p) => setOver(false),
child: widget.builder(context, isOver),
onEnter: (p) => setOnHover(true),
onExit: (p) => setOnHover(false),
child: widget.builder(context, _onHover),
);
}
void setOver(bool value) => setState(() => isOver = value);
void setOnHover(bool value) => setState(() => _onHover = value);
}

View File

@ -1,33 +1,90 @@
import 'package:flutter/material.dart';
class RoundedButton extends StatelessWidget {
class RoundedTextButton extends StatelessWidget {
final VoidCallback? press;
final String? title;
final Size? size;
final double? width;
final double? height;
final BorderRadius borderRadius;
final Color borderColor;
final Color color;
final Color textColor;
final double fontSize;
const RoundedButton({
const RoundedTextButton({
Key? key,
this.press,
this.title,
this.size,
this.width,
this.height,
this.borderRadius = BorderRadius.zero,
this.borderColor = Colors.transparent,
this.color = Colors.transparent,
this.textColor = Colors.white,
this.fontSize = 16,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: 100,
maxWidth: size?.width ?? double.infinity,
minHeight: 50,
maxHeight: size?.height ?? double.infinity,
minWidth: 10,
maxWidth: width ?? double.infinity,
minHeight: 10,
maxHeight: height ?? 60,
),
child: Container(
margin: const EdgeInsets.symmetric(vertical: 10),
child: TextButton(
child: Text(title ?? ''),
onPressed: press,
decoration: BoxDecoration(
border: Border.all(color: borderColor),
borderRadius: borderRadius,
color: color,
),
child: SizedBox.expand(
child: TextButton(
child: Text(
title ?? '',
style: TextStyle(color: textColor, fontSize: fontSize),
),
onPressed: press,
),
),
),
);
}
}
class RoundedImageButton extends StatelessWidget {
final VoidCallback? press;
final double size;
final BorderRadius borderRadius;
final Color borderColor;
final Color color;
final Widget child;
const RoundedImageButton({
Key? key,
this.press,
required this.size,
this.borderRadius = BorderRadius.zero,
this.borderColor = Colors.transparent,
this.color = Colors.transparent,
required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
width: size,
height: size,
child: TextButton(
onPressed: press,
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: borderRadius,
))),
child: child,
),
);
}
}

View File

@ -1,35 +1,96 @@
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flowy_infra_ui/widget/text_field_container.dart';
import 'package:flutter/material.dart';
import 'package:flowy_infra/time/duration.dart';
class RoundedInputField extends StatelessWidget {
// ignore: must_be_immutable
class RoundedInputField extends StatefulWidget {
final String? hintText;
final IconData? icon;
final bool obscureText;
final Color normalBorderColor;
final Color highlightBorderColor;
final String errorText;
final ValueChanged<String>? onChanged;
late bool enableObscure;
const RoundedInputField({
RoundedInputField({
Key? key,
this.hintText,
this.icon = Icons.person,
this.icon,
this.obscureText = false,
this.onChanged,
}) : super(key: key);
this.normalBorderColor = Colors.transparent,
this.highlightBorderColor = Colors.transparent,
this.errorText = "",
}) : super(key: key) {
enableObscure = obscureText;
}
@override
State<RoundedInputField> createState() => _RoundedInputFieldState();
}
class _RoundedInputFieldState extends State<RoundedInputField> {
@override
Widget build(BuildContext context) {
return TextFieldContainer(
final Icon? newIcon = widget.icon == null
? null
: Icon(
widget.icon!,
color: const Color(0xFF6F35A5),
);
var borderColor = widget.normalBorderColor;
if (widget.errorText.isNotEmpty) {
borderColor = widget.highlightBorderColor;
}
List<Widget> children = [
TextFieldContainer(
borderRadius: BorderRadius.circular(10),
borderColor: borderColor,
child: TextFormField(
onChanged: onChanged,
cursorColor: const Color(0xFF6F35A5),
obscureText: obscureText,
decoration: InputDecoration(
icon: Icon(
icon,
color: const Color(0xFF6F35A5),
onChanged: widget.onChanged,
cursorColor: const Color(0xFF6F35A5),
obscureText: widget.enableObscure,
decoration: InputDecoration(
icon: newIcon,
hintText: widget.hintText,
border: InputBorder.none,
suffixIcon: suffixIcon(),
),
),
hintText: hintText,
border: InputBorder.none,
),
));
];
if (widget.errorText.isNotEmpty) {
children.add(Text(
widget.errorText,
style: TextStyle(color: widget.highlightBorderColor),
));
}
return AnimatedSize(
duration: .4.seconds,
curve: Curves.easeInOut,
child: Column(
children: children,
),
);
}
Widget? suffixIcon() {
if (widget.obscureText == false) {
return null;
}
return RoundedImageButton(
size: 20,
press: () {
widget.enableObscure = !widget.enableObscure;
setState(() {});
},
child: const Icon(Icons.password, size: 15),
);
}
}

View File

@ -3,21 +3,32 @@ import 'package:flutter/material.dart';
class TextFieldContainer extends StatelessWidget {
final Widget child;
final BorderRadius borderRadius;
final Color borderColor;
final double? height;
final double? width;
const TextFieldContainer({
Key? key,
required this.child,
this.borderRadius = BorderRadius.zero,
this.borderColor = Colors.white,
this.height,
this.width,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10),
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.symmetric(horizontal: 15),
height: height,
width: width,
decoration: BoxDecoration(
border: Border.all(color: borderColor),
color: Colors.white,
borderRadius: BorderRadius.circular(30),
borderRadius: borderRadius,
),
child: child,
child: Align(alignment: Alignment.center, child: child),
);
}

View File

@ -14,7 +14,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.7.0"
version: "2.6.1"
boolean_selector:
dependency: transitive
description:
@ -35,7 +35,7 @@ packages:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
version: "1.2.0"
clock:
dependency: transitive
description:
@ -142,6 +142,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
loading_indicator:
dependency: "direct main"
description:
name: loading_indicator
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
logger:
dependency: transitive
description:
@ -162,7 +169,7 @@ packages:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
version: "1.3.0"
nested:
dependency: transitive
description:
@ -244,7 +251,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.1"
version: "0.3.0"
textstyle_extensions:
dependency: "direct main"
description:
@ -282,4 +289,4 @@ packages:
version: "2.1.0"
sdks:
dart: ">=2.12.0 <3.0.0"
flutter: ">=1.20.0"
flutter: ">=2.0.0"

View File

@ -19,6 +19,7 @@ dependencies:
styled_widget: '>=0.3.1'
equatable: '>=2.0.2'
animations: ^2.0.0
loading_indicator: ^3.0.1
# Federated Platform Interface
flowy_infra_ui_platform_interface:

View File

@ -118,6 +118,20 @@ class WorkspaceEventGetWorkspace {
}
}
class WorkspaceEventReadAllWorkspace {
WorkspaceEventReadAllWorkspace();
Future<Either<Workspaces, WorkspaceError>> send() {
final request = FFIRequest.create()
..event = WorkspaceEvent.ReadAllWorkspace.toString();
return Dispatch.asyncRequest(request).then((bytesResult) => bytesResult.fold(
(okBytes) => left(Workspaces.fromBuffer(okBytes)),
(errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
));
}
}
class WorkspaceEventCreateApp {
CreateAppRequest request;
WorkspaceEventCreateApp(this.request);

View File

@ -15,14 +15,14 @@ export 'errors.pbenum.dart';
class UserError extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UserError', createEmptyInstance: create)
..e<UserErrorCode>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'code', $pb.PbFieldType.OE, defaultOrMaker: UserErrorCode.Unknown, valueOf: UserErrorCode.valueOf, enumValues: UserErrorCode.values)
..e<UserErrCode>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'code', $pb.PbFieldType.OE, defaultOrMaker: UserErrCode.Unknown, valueOf: UserErrCode.valueOf, enumValues: UserErrCode.values)
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'msg')
..hasRequiredFields = false
;
UserError._() : super();
factory UserError({
UserErrorCode? code,
UserErrCode? code,
$core.String? msg,
}) {
final _result = create();
@ -56,9 +56,9 @@ class UserError extends $pb.GeneratedMessage {
static UserError? _defaultInstance;
@$pb.TagNumber(1)
UserErrorCode get code => $_getN(0);
UserErrCode get code => $_getN(0);
@$pb.TagNumber(1)
set code(UserErrorCode v) { setField(1, v); }
set code(UserErrCode v) { setField(1, v); }
@$pb.TagNumber(1)
$core.bool hasCode() => $_has(0);
@$pb.TagNumber(1)

View File

@ -9,26 +9,26 @@
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class UserErrorCode extends $pb.ProtobufEnum {
static const UserErrorCode Unknown = UserErrorCode._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
static const UserErrorCode UserDatabaseInitFailed = UserErrorCode._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseInitFailed');
static const UserErrorCode UserDatabaseWriteLocked = UserErrorCode._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseWriteLocked');
static const UserErrorCode UserDatabaseReadLocked = UserErrorCode._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseReadLocked');
static const UserErrorCode UserDatabaseDidNotMatch = UserErrorCode._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseDidNotMatch');
static const UserErrorCode UserDatabaseInternalError = UserErrorCode._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseInternalError');
static const UserErrorCode SqlInternalError = UserErrorCode._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SqlInternalError');
static const UserErrorCode UserNotLoginYet = UserErrorCode._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNotLoginYet');
static const UserErrorCode ReadCurrentIdFailed = UserErrorCode._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadCurrentIdFailed');
static const UserErrorCode WriteCurrentIdFailed = UserErrorCode._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WriteCurrentIdFailed');
static const UserErrorCode EmailInvalid = UserErrorCode._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EmailInvalid');
static const UserErrorCode PasswordInvalid = UserErrorCode._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PasswordInvalid');
static const UserErrorCode UserNameInvalid = UserErrorCode._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNameInvalid');
static const UserErrorCode UserWorkspaceInvalid = UserErrorCode._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserWorkspaceInvalid');
static const UserErrorCode UserIdInvalid = UserErrorCode._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserIdInvalid');
static const UserErrorCode CreateDefaultWorkspaceFailed = UserErrorCode._(25, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateDefaultWorkspaceFailed');
static const UserErrorCode DefaultWorkspaceAlreadyExist = UserErrorCode._(26, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DefaultWorkspaceAlreadyExist');
class UserErrCode extends $pb.ProtobufEnum {
static const UserErrCode Unknown = UserErrCode._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
static const UserErrCode UserDatabaseInitFailed = UserErrCode._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseInitFailed');
static const UserErrCode UserDatabaseWriteLocked = UserErrCode._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseWriteLocked');
static const UserErrCode UserDatabaseReadLocked = UserErrCode._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseReadLocked');
static const UserErrCode UserDatabaseDidNotMatch = UserErrCode._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseDidNotMatch');
static const UserErrCode UserDatabaseInternalError = UserErrCode._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseInternalError');
static const UserErrCode SqlInternalError = UserErrCode._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SqlInternalError');
static const UserErrCode UserNotLoginYet = UserErrCode._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNotLoginYet');
static const UserErrCode ReadCurrentIdFailed = UserErrCode._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadCurrentIdFailed');
static const UserErrCode WriteCurrentIdFailed = UserErrCode._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WriteCurrentIdFailed');
static const UserErrCode EmailInvalid = UserErrCode._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EmailInvalid');
static const UserErrCode PasswordInvalid = UserErrCode._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PasswordInvalid');
static const UserErrCode UserNameInvalid = UserErrCode._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNameInvalid');
static const UserErrCode UserWorkspaceInvalid = UserErrCode._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserWorkspaceInvalid');
static const UserErrCode UserIdInvalid = UserErrCode._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserIdInvalid');
static const UserErrCode CreateDefaultWorkspaceFailed = UserErrCode._(25, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateDefaultWorkspaceFailed');
static const UserErrCode DefaultWorkspaceAlreadyExist = UserErrCode._(26, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DefaultWorkspaceAlreadyExist');
static const $core.List<UserErrorCode> values = <UserErrorCode> [
static const $core.List<UserErrCode> values = <UserErrCode> [
Unknown,
UserDatabaseInitFailed,
UserDatabaseWriteLocked,
@ -48,9 +48,9 @@ class UserErrorCode extends $pb.ProtobufEnum {
DefaultWorkspaceAlreadyExist,
];
static final $core.Map<$core.int, UserErrorCode> _byValue = $pb.ProtobufEnum.initByValue(values);
static UserErrorCode? valueOf($core.int value) => _byValue[value];
static final $core.Map<$core.int, UserErrCode> _byValue = $pb.ProtobufEnum.initByValue(values);
static UserErrCode? valueOf($core.int value) => _byValue[value];
const UserErrorCode._($core.int v, $core.String n) : super(v, n);
const UserErrCode._($core.int v, $core.String n) : super(v, n);
}

View File

@ -8,9 +8,9 @@
import 'dart:core' as $core;
import 'dart:convert' as $convert;
import 'dart:typed_data' as $typed_data;
@$core.Deprecated('Use userErrorCodeDescriptor instead')
const UserErrorCode$json = const {
'1': 'UserErrorCode',
@$core.Deprecated('Use userErrCodeDescriptor instead')
const UserErrCode$json = const {
'1': 'UserErrCode',
'2': const [
const {'1': 'Unknown', '2': 0},
const {'1': 'UserDatabaseInitFailed', '2': 1},
@ -32,16 +32,16 @@ const UserErrorCode$json = const {
],
};
/// Descriptor for `UserErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List userErrorCodeDescriptor = $convert.base64Decode('Cg1Vc2VyRXJyb3JDb2RlEgsKB1Vua25vd24QABIaChZVc2VyRGF0YWJhc2VJbml0RmFpbGVkEAESGwoXVXNlckRhdGFiYXNlV3JpdGVMb2NrZWQQAhIaChZVc2VyRGF0YWJhc2VSZWFkTG9ja2VkEAMSGwoXVXNlckRhdGFiYXNlRGlkTm90TWF0Y2gQBBIdChlVc2VyRGF0YWJhc2VJbnRlcm5hbEVycm9yEAUSFAoQU3FsSW50ZXJuYWxFcnJvchAGEhMKD1VzZXJOb3RMb2dpbllldBAKEhcKE1JlYWRDdXJyZW50SWRGYWlsZWQQCxIYChRXcml0ZUN1cnJlbnRJZEZhaWxlZBAMEhAKDEVtYWlsSW52YWxpZBAUEhMKD1Bhc3N3b3JkSW52YWxpZBAVEhMKD1VzZXJOYW1lSW52YWxpZBAWEhgKFFVzZXJXb3Jrc3BhY2VJbnZhbGlkEBcSEQoNVXNlcklkSW52YWxpZBAYEiAKHENyZWF0ZURlZmF1bHRXb3Jrc3BhY2VGYWlsZWQQGRIgChxEZWZhdWx0V29ya3NwYWNlQWxyZWFkeUV4aXN0EBo=');
/// Descriptor for `UserErrCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List userErrCodeDescriptor = $convert.base64Decode('CgtVc2VyRXJyQ29kZRILCgdVbmtub3duEAASGgoWVXNlckRhdGFiYXNlSW5pdEZhaWxlZBABEhsKF1VzZXJEYXRhYmFzZVdyaXRlTG9ja2VkEAISGgoWVXNlckRhdGFiYXNlUmVhZExvY2tlZBADEhsKF1VzZXJEYXRhYmFzZURpZE5vdE1hdGNoEAQSHQoZVXNlckRhdGFiYXNlSW50ZXJuYWxFcnJvchAFEhQKEFNxbEludGVybmFsRXJyb3IQBhITCg9Vc2VyTm90TG9naW5ZZXQQChIXChNSZWFkQ3VycmVudElkRmFpbGVkEAsSGAoUV3JpdGVDdXJyZW50SWRGYWlsZWQQDBIQCgxFbWFpbEludmFsaWQQFBITCg9QYXNzd29yZEludmFsaWQQFRITCg9Vc2VyTmFtZUludmFsaWQQFhIYChRVc2VyV29ya3NwYWNlSW52YWxpZBAXEhEKDVVzZXJJZEludmFsaWQQGBIgChxDcmVhdGVEZWZhdWx0V29ya3NwYWNlRmFpbGVkEBkSIAocRGVmYXVsdFdvcmtzcGFjZUFscmVhZHlFeGlzdBAa');
@$core.Deprecated('Use userErrorDescriptor instead')
const UserError$json = const {
'1': 'UserError',
'2': const [
const {'1': 'code', '3': 1, '4': 1, '5': 14, '6': '.UserErrorCode', '10': 'code'},
const {'1': 'code', '3': 1, '4': 1, '5': 14, '6': '.UserErrCode', '10': 'code'},
const {'1': 'msg', '3': 2, '4': 1, '5': 9, '10': 'msg'},
],
};
/// Descriptor for `UserError`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List userErrorDescriptor = $convert.base64Decode('CglVc2VyRXJyb3ISIgoEY29kZRgBIAEoDjIOLlVzZXJFcnJvckNvZGVSBGNvZGUSEAoDbXNnGAIgASgJUgNtc2c=');
final $typed_data.Uint8List userErrorDescriptor = $convert.base64Decode('CglVc2VyRXJyb3ISIAoEY29kZRgBIAEoDjIMLlVzZXJFcnJDb2RlUgRjb2RlEhAKA21zZxgCIAEoCVIDbXNn');

View File

@ -15,14 +15,14 @@ export 'errors.pbenum.dart';
class WorkspaceError extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'WorkspaceError', createEmptyInstance: create)
..e<WorkspaceErrorCode>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'code', $pb.PbFieldType.OE, defaultOrMaker: WorkspaceErrorCode.Unknown, valueOf: WorkspaceErrorCode.valueOf, enumValues: WorkspaceErrorCode.values)
..e<WsErrCode>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'code', $pb.PbFieldType.OE, defaultOrMaker: WsErrCode.Unknown, valueOf: WsErrCode.valueOf, enumValues: WsErrCode.values)
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'msg')
..hasRequiredFields = false
;
WorkspaceError._() : super();
factory WorkspaceError({
WorkspaceErrorCode? code,
WsErrCode? code,
$core.String? msg,
}) {
final _result = create();
@ -56,9 +56,9 @@ class WorkspaceError extends $pb.GeneratedMessage {
static WorkspaceError? _defaultInstance;
@$pb.TagNumber(1)
WorkspaceErrorCode get code => $_getN(0);
WsErrCode get code => $_getN(0);
@$pb.TagNumber(1)
set code(WorkspaceErrorCode v) { setField(1, v); }
set code(WsErrCode v) { setField(1, v); }
@$pb.TagNumber(1)
$core.bool hasCode() => $_has(0);
@$pb.TagNumber(1)

View File

@ -9,23 +9,23 @@
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class WorkspaceErrorCode extends $pb.ProtobufEnum {
static const WorkspaceErrorCode Unknown = WorkspaceErrorCode._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
static const WorkspaceErrorCode WorkspaceNameInvalid = WorkspaceErrorCode._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceNameInvalid');
static const WorkspaceErrorCode WorkspaceIdInvalid = WorkspaceErrorCode._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceIdInvalid');
static const WorkspaceErrorCode AppColorStyleInvalid = WorkspaceErrorCode._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppColorStyleInvalid');
static const WorkspaceErrorCode AppIdInvalid = WorkspaceErrorCode._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppIdInvalid');
static const WorkspaceErrorCode AppNameInvalid = WorkspaceErrorCode._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppNameInvalid');
static const WorkspaceErrorCode ViewNameInvalid = WorkspaceErrorCode._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewNameInvalid');
static const WorkspaceErrorCode ViewThumbnailInvalid = WorkspaceErrorCode._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewThumbnailInvalid');
static const WorkspaceErrorCode ViewIdInvalid = WorkspaceErrorCode._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewIdInvalid');
static const WorkspaceErrorCode ViewDescInvalid = WorkspaceErrorCode._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewDescInvalid');
static const WorkspaceErrorCode DatabaseConnectionFail = WorkspaceErrorCode._(100, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DatabaseConnectionFail');
static const WorkspaceErrorCode WorkspaceDatabaseError = WorkspaceErrorCode._(101, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceDatabaseError');
static const WorkspaceErrorCode UserInternalError = WorkspaceErrorCode._(102, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserInternalError');
static const WorkspaceErrorCode UserNotLoginYet = WorkspaceErrorCode._(103, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNotLoginYet');
class WsErrCode extends $pb.ProtobufEnum {
static const WsErrCode Unknown = WsErrCode._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
static const WsErrCode WorkspaceNameInvalid = WsErrCode._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceNameInvalid');
static const WsErrCode WorkspaceIdInvalid = WsErrCode._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceIdInvalid');
static const WsErrCode AppColorStyleInvalid = WsErrCode._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppColorStyleInvalid');
static const WsErrCode AppIdInvalid = WsErrCode._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppIdInvalid');
static const WsErrCode AppNameInvalid = WsErrCode._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppNameInvalid');
static const WsErrCode ViewNameInvalid = WsErrCode._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewNameInvalid');
static const WsErrCode ViewThumbnailInvalid = WsErrCode._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewThumbnailInvalid');
static const WsErrCode ViewIdInvalid = WsErrCode._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewIdInvalid');
static const WsErrCode ViewDescInvalid = WsErrCode._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewDescInvalid');
static const WsErrCode DatabaseConnectionFail = WsErrCode._(100, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DatabaseConnectionFail');
static const WsErrCode WorkspaceDatabaseError = WsErrCode._(101, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceDatabaseError');
static const WsErrCode UserInternalError = WsErrCode._(102, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserInternalError');
static const WsErrCode UserNotLoginYet = WsErrCode._(103, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNotLoginYet');
static const $core.List<WorkspaceErrorCode> values = <WorkspaceErrorCode> [
static const $core.List<WsErrCode> values = <WsErrCode> [
Unknown,
WorkspaceNameInvalid,
WorkspaceIdInvalid,
@ -42,9 +42,9 @@ class WorkspaceErrorCode extends $pb.ProtobufEnum {
UserNotLoginYet,
];
static final $core.Map<$core.int, WorkspaceErrorCode> _byValue = $pb.ProtobufEnum.initByValue(values);
static WorkspaceErrorCode? valueOf($core.int value) => _byValue[value];
static final $core.Map<$core.int, WsErrCode> _byValue = $pb.ProtobufEnum.initByValue(values);
static WsErrCode? valueOf($core.int value) => _byValue[value];
const WorkspaceErrorCode._($core.int v, $core.String n) : super(v, n);
const WsErrCode._($core.int v, $core.String n) : super(v, n);
}

View File

@ -8,9 +8,9 @@
import 'dart:core' as $core;
import 'dart:convert' as $convert;
import 'dart:typed_data' as $typed_data;
@$core.Deprecated('Use workspaceErrorCodeDescriptor instead')
const WorkspaceErrorCode$json = const {
'1': 'WorkspaceErrorCode',
@$core.Deprecated('Use wsErrCodeDescriptor instead')
const WsErrCode$json = const {
'1': 'WsErrCode',
'2': const [
const {'1': 'Unknown', '2': 0},
const {'1': 'WorkspaceNameInvalid', '2': 1},
@ -29,16 +29,16 @@ const WorkspaceErrorCode$json = const {
],
};
/// Descriptor for `WorkspaceErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List workspaceErrorCodeDescriptor = $convert.base64Decode('ChJXb3Jrc3BhY2VFcnJvckNvZGUSCwoHVW5rbm93bhAAEhgKFFdvcmtzcGFjZU5hbWVJbnZhbGlkEAESFgoSV29ya3NwYWNlSWRJbnZhbGlkEAISGAoUQXBwQ29sb3JTdHlsZUludmFsaWQQAxIQCgxBcHBJZEludmFsaWQQChISCg5BcHBOYW1lSW52YWxpZBALEhMKD1ZpZXdOYW1lSW52YWxpZBAUEhgKFFZpZXdUaHVtYm5haWxJbnZhbGlkEBUSEQoNVmlld0lkSW52YWxpZBAWEhMKD1ZpZXdEZXNjSW52YWxpZBAXEhoKFkRhdGFiYXNlQ29ubmVjdGlvbkZhaWwQZBIaChZXb3Jrc3BhY2VEYXRhYmFzZUVycm9yEGUSFQoRVXNlckludGVybmFsRXJyb3IQZhITCg9Vc2VyTm90TG9naW5ZZXQQZw==');
/// Descriptor for `WsErrCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List wsErrCodeDescriptor = $convert.base64Decode('CglXc0VyckNvZGUSCwoHVW5rbm93bhAAEhgKFFdvcmtzcGFjZU5hbWVJbnZhbGlkEAESFgoSV29ya3NwYWNlSWRJbnZhbGlkEAISGAoUQXBwQ29sb3JTdHlsZUludmFsaWQQAxIQCgxBcHBJZEludmFsaWQQChISCg5BcHBOYW1lSW52YWxpZBALEhMKD1ZpZXdOYW1lSW52YWxpZBAUEhgKFFZpZXdUaHVtYm5haWxJbnZhbGlkEBUSEQoNVmlld0lkSW52YWxpZBAWEhMKD1ZpZXdEZXNjSW52YWxpZBAXEhoKFkRhdGFiYXNlQ29ubmVjdGlvbkZhaWwQZBIaChZXb3Jrc3BhY2VEYXRhYmFzZUVycm9yEGUSFQoRVXNlckludGVybmFsRXJyb3IQZhITCg9Vc2VyTm90TG9naW5ZZXQQZw==');
@$core.Deprecated('Use workspaceErrorDescriptor instead')
const WorkspaceError$json = const {
'1': 'WorkspaceError',
'2': const [
const {'1': 'code', '3': 1, '4': 1, '5': 14, '6': '.WorkspaceErrorCode', '10': 'code'},
const {'1': 'code', '3': 1, '4': 1, '5': 14, '6': '.WsErrCode', '10': 'code'},
const {'1': 'msg', '3': 2, '4': 1, '5': 9, '10': 'msg'},
],
};
/// Descriptor for `WorkspaceError`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List workspaceErrorDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFcnJvchInCgRjb2RlGAEgASgOMhMuV29ya3NwYWNlRXJyb3JDb2RlUgRjb2RlEhAKA21zZxgCIAEoCVIDbXNn');
final $typed_data.Uint8List workspaceErrorDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFcnJvchIeCgRjb2RlGAEgASgOMgouV3NFcnJDb2RlUgRjb2RlEhAKA21zZxgCIAEoCVIDbXNn');

View File

@ -13,6 +13,7 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
static const WorkspaceEvent CreateWorkspace = WorkspaceEvent._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateWorkspace');
static const WorkspaceEvent GetCurWorkspace = WorkspaceEvent._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetCurWorkspace');
static const WorkspaceEvent GetWorkspace = WorkspaceEvent._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetWorkspace');
static const WorkspaceEvent ReadAllWorkspace = WorkspaceEvent._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadAllWorkspace');
static const WorkspaceEvent CreateApp = WorkspaceEvent._(101, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateApp');
static const WorkspaceEvent GetApp = WorkspaceEvent._(102, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetApp');
static const WorkspaceEvent CreateView = WorkspaceEvent._(201, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateView');
@ -23,6 +24,7 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
CreateWorkspace,
GetCurWorkspace,
GetWorkspace,
ReadAllWorkspace,
CreateApp,
GetApp,
CreateView,

View File

@ -15,6 +15,7 @@ const WorkspaceEvent$json = const {
const {'1': 'CreateWorkspace', '2': 0},
const {'1': 'GetCurWorkspace', '2': 1},
const {'1': 'GetWorkspace', '2': 2},
const {'1': 'ReadAllWorkspace', '2': 3},
const {'1': 'CreateApp', '2': 101},
const {'1': 'GetApp', '2': 102},
const {'1': 'CreateView', '2': 201},
@ -24,4 +25,4 @@ const WorkspaceEvent$json = const {
};
/// Descriptor for `WorkspaceEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List workspaceEventDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABITCg9HZXRDdXJXb3Jrc3BhY2UQARIQCgxHZXRXb3Jrc3BhY2UQAhINCglDcmVhdGVBcHAQZRIKCgZHZXRBcHAQZhIPCgpDcmVhdGVWaWV3EMkBEg0KCFJlYWRWaWV3EMoBEg8KClVwZGF0ZVZpZXcQywE=');
final $typed_data.Uint8List workspaceEventDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABITCg9HZXRDdXJXb3Jrc3BhY2UQARIQCgxHZXRXb3Jrc3BhY2UQAhIUChBSZWFkQWxsV29ya3NwYWNlEAMSDQoJQ3JlYXRlQXBwEGUSCgoGR2V0QXBwEGYSDwoKQ3JlYXRlVmlldxDJARINCghSZWFkVmlldxDKARIPCgpVcGRhdGVWaWV3EMsB');

View File

@ -10,17 +10,25 @@ import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class ViewType extends $pb.ProtobufEnum {
static const ViewType Blank = ViewType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Blank');
static const ViewType Doc = ViewType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Doc');
static const ViewType Blank = ViewType._(
0,
const $core.bool.fromEnvironment('protobuf.omit_enum_names')
? ''
: 'Blank');
static const ViewType Doc = ViewType._(
1,
const $core.bool.fromEnvironment('protobuf.omit_enum_names')
? ''
: 'Doc');
static const $core.List<ViewType> values = <ViewType> [
static const $core.List<ViewType> values = <ViewType>[
Blank,
Doc,
];
static final $core.Map<$core.int, ViewType> _byValue = $pb.ProtobufEnum.initByValue(values);
static final $core.Map<$core.int, ViewType> _byValue =
$pb.ProtobufEnum.initByValue(values);
static ViewType? valueOf($core.int value) => _byValue[value];
const ViewType._($core.int v, $core.String n) : super(v, n);
}

View File

@ -163,3 +163,44 @@ class Workspace extends $pb.GeneratedMessage {
$0.RepeatedApp ensureApps() => $_ensure(3);
}
class Workspaces extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Workspaces', createEmptyInstance: create)
..pc<Workspace>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: Workspace.create)
..hasRequiredFields = false
;
Workspaces._() : super();
factory Workspaces({
$core.Iterable<Workspace>? items,
}) {
final _result = create();
if (items != null) {
_result.items.addAll(items);
}
return _result;
}
factory Workspaces.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory Workspaces.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')
Workspaces clone() => Workspaces()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
Workspaces copyWith(void Function(Workspaces) updates) => super.copyWith((message) => updates(message as Workspaces)) as Workspaces; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static Workspaces create() => Workspaces._();
Workspaces createEmptyInstance() => create();
static $pb.PbList<Workspaces> createRepeated() => $pb.PbList<Workspaces>();
@$core.pragma('dart2js:noInline')
static Workspaces getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Workspaces>(create);
static Workspaces? _defaultInstance;
@$pb.TagNumber(1)
$core.List<Workspace> get items => $_getList(0);
}

View File

@ -32,3 +32,13 @@ const Workspace$json = const {
/// Descriptor for `Workspace`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List workspaceDescriptor = $convert.base64Decode('CglXb3Jrc3BhY2USDgoCaWQYASABKAlSAmlkEhIKBG5hbWUYAiABKAlSBG5hbWUSEgoEZGVzYxgDIAEoCVIEZGVzYxIgCgRhcHBzGAQgASgLMgwuUmVwZWF0ZWRBcHBSBGFwcHM=');
@$core.Deprecated('Use workspacesDescriptor instead')
const Workspaces$json = const {
'1': 'Workspaces',
'2': const [
const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.Workspace', '10': 'items'},
],
};
/// Descriptor for `Workspaces`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List workspacesDescriptor = $convert.base64Decode('CgpXb3Jrc3BhY2VzEiAKBWl0ZW1zGAEgAygLMgouV29ya3NwYWNlUgVpdGVtcw==');

View File

@ -5,231 +5,231 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "22.0.0"
version: "23.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.7.1"
version: "2.0.0"
animations:
dependency: transitive
description:
name: animations
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.1"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.1"
version: "2.2.0"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.6.1"
version: "2.7.0"
bloc:
dependency: transitive
description:
name: bloc
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0"
build:
dependency: transitive
description:
name: build
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.3"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
build_daemon:
dependency: transitive
description:
name: build_daemon
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.0"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.4"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.6"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.1"
built_collection:
dependency: transitive
description:
name: built_collection
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.1.0"
built_value:
dependency: transitive
description:
name: built_value
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "8.1.1"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0"
version: "1.3.1"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.1"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.3.3"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
code_builder:
dependency: transitive
description:
name: code_builder
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.0"
version: "4.1.0"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.15.0"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.3"
dart_style:
dependency: transitive
description:
name: dart_style
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.2"
version: "2.0.3"
dartz:
dependency: transitive
description:
name: dartz
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.10.0-nullsafety.2"
equatable:
dependency: "direct main"
description:
name: equatable
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.3"
expandable:
dependency: "direct main"
description:
name: expandable
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.1"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.2"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.1.2"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
flowy_editor:
@ -283,42 +283,42 @@ packages:
dependency: "direct main"
description:
name: flutter_bloc
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.1"
flutter_colorpicker:
dependency: transitive
description:
name: flutter_colorpicker
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.5.0"
flutter_keyboard_visibility:
dependency: transitive
description:
name: flutter_keyboard_visibility
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.2"
version: "5.0.3"
flutter_keyboard_visibility_platform_interface:
dependency: transitive
description:
name: flutter_keyboard_visibility_platform_interface
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
flutter_keyboard_visibility_web:
dependency: transitive
description:
name: flutter_keyboard_visibility_web
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.4"
flutter_test:
@ -335,196 +335,203 @@ packages:
dependency: "direct dev"
description:
name: freezed
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.14.2"
version: "0.14.3"
freezed_annotation:
dependency: "direct main"
description:
name: freezed_annotation
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.14.2"
version: "0.14.3"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0"
get_it:
dependency: "direct main"
description:
name: get_it
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.2.0"
glob:
dependency: transitive
description:
name: glob
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.1"
graphs:
dependency: transitive
description:
name: graphs
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.0"
io:
dependency: transitive
description:
name: io
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.3"
isolates:
dependency: transitive
description:
name: isolates
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.3+8"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.6.3"
json_annotation:
dependency: transitive
description:
name: json_annotation
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.1"
version: "4.1.0"
lint:
dependency: transitive
description:
name: lint
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.5.3"
lints:
dependency: transitive
description:
name: lints
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
loading_indicator:
dependency: transitive
description:
name: loading_indicator
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
logger:
dependency: transitive
description:
name: logger
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.12.10"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.0"
version: "1.7.0"
mime:
dependency: transitive
description:
name: mime
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
nested:
dependency: transitive
description:
name: nested
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.8.0"
path_provider:
dependency: "direct main"
description:
name: path_provider
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.2"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.1"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.1"
pedantic:
dependency: transitive
description:
name: pedantic
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.11.1"
photo_view:
@ -540,91 +547,91 @@ packages:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.1"
pool:
dependency: transitive
description:
name: pool
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.5.0"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.2.1"
version: "4.2.3"
protobuf:
dependency: transitive
description:
name: protobuf
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
provider:
dependency: transitive
description:
name: provider
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.0"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
quiver_hashcode:
dependency: transitive
description:
name: quiver_hashcode
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
sized_context:
dependency: "direct main"
description:
name: sized_context
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0+1"
sky_engine:
@ -636,189 +643,189 @@ packages:
dependency: transitive
description:
name: source_gen
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.3"
version: "1.0.5"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.8.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.10.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
string_validator:
dependency: transitive
description:
name: string_validator
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.3.0"
styled_widget:
dependency: "direct main"
description:
name: styled_widget
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.3.1+2"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.3.0"
version: "0.4.1"
textstyle_extensions:
dependency: transitive
description:
name: textstyle_extensions
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0-nullsafety"
time:
dependency: "direct main"
description:
name: time
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
timing:
dependency: transitive
description:
name: timing
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
tuple:
dependency: transitive
description:
name: tuple
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.0"
universal_platform:
dependency: transitive
description:
name: universal_platform
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0+1"
url_launcher:
dependency: transitive
description:
name: url_launcher
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.0.9"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.4"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.1"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
uuid:
dependency: transitive
description:
name: uuid
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.4"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0"
watcher:
dependency: transitive
description:
name: watcher
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.5"
window_size:
@ -834,14 +841,14 @@ packages:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.0"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.0"
sdks:

View File

@ -9,7 +9,7 @@ use crate::{
};
use flowy_dispatch::prelude::*;
use flowy_sdk::*;
use lazy_static::lazy_static;
use std::{ffi::CStr, os::raw::c_char};
#[no_mangle]

View File

@ -1,5 +1,5 @@
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_dispatch::prelude::{DispatchError, EventResponse, Payload, StatusCode};
use flowy_dispatch::prelude::{EventResponse, Payload, StatusCode};
#[derive(ProtoBuf_Enum, Clone, Copy)]
pub enum FFIStatusCode {

View File

@ -33,6 +33,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
| "UpdateWorkspaceRequest"
| "CreateWorkspaceRequest"
| "Workspace"
| "Workspaces"
| "QueryWorkspaceRequest"
| "CurrentWorkspace"
| "UpdateViewRequest"
@ -56,12 +57,12 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
| "EditorErrorCode"
| "ViewType"
| "WorkspaceEvent"
| "WorkspaceErrorCode"
| "WsErrCode"
| "WorkspaceObservable"
| "FFIStatusCode"
| "UserStatus"
| "UserEvent"
| "UserErrorCode"
| "UserErrCode"
=> TypeCategory::Enum,
"Option" => TypeCategory::Opt,

View File

@ -1,7 +1,7 @@
use crate::{
byte_trait::FromBytes,
request::EventRequest,
response::{EventResponse, ResponseBuilder, StatusCode},
response::{EventResponse, ResponseBuilder},
};
use dyn_clone::DynClone;
use serde::{Serialize, Serializer};

View File

@ -1,5 +1,4 @@
use crate::{
errors::DispatchError,
request::Payload,
response::{EventResponse, StatusCode},
};

View File

@ -4,7 +4,7 @@ use crate::{
services::{doc_controller::DocController, file_manager::FileManager},
};
use flowy_dispatch::prelude::*;
use std::{convert::TryInto, path::Path, sync::Arc};
use std::{convert::TryInto, path::Path};
use tokio::sync::RwLock;
#[tracing::instrument(name = "create_doc", skip(data, controller, manager))]
@ -67,7 +67,8 @@ pub async fn update_doc(
manager
.write()
.await
.save(Path::new(&doc_desc.path), &s, params.id.clone());
.save(Path::new(&doc_desc.path), &s, params.id.clone())
.unwrap();
}
if params.name.is_some() || params.desc.is_some() {

View File

@ -2,10 +2,7 @@ use crate::{
errors::EditorError,
event::EditorEvent,
handlers::*,
services::{
doc_controller::DocController,
file_manager::{create_dir_if_not_exist, FileManager},
},
services::{doc_controller::DocController, file_manager::FileManager},
};
use flowy_database::DBConnection;
use flowy_dispatch::prelude::*;

View File

@ -1,5 +1,5 @@
use crate::{
entities::doc::{CreateDocParams, DocData, DocInfo, QueryDocParams, UpdateDocParams},
entities::doc::{CreateDocParams, DocInfo, UpdateDocParams},
errors::EditorError,
module::EditorDatabase,
sql_tables::doc::{DocTable, DocTableChangeset, DocTableSql},

View File

@ -6,7 +6,6 @@ use std::{
io::{Read, Write},
path::{Path, PathBuf},
str,
sync::atomic::{AtomicUsize, Ordering},
time::SystemTime,
};
@ -117,6 +116,7 @@ pub(crate) fn try_decode(
}
}
#[allow(dead_code)]
pub(crate) fn create_dir_if_not_exist(dir: &str) -> Result<(), io::Error> {
let _ = fs::create_dir_all(dir)?;
Ok(())

View File

@ -1,9 +1,8 @@
use crate::{module::EditorUser, services::file_manager::*};
use std::{
collections::HashMap,
io,
path::{Path, PathBuf},
sync::{Arc, PoisonError, RwLock, RwLockReadGuard},
sync::Arc,
};
pub struct FileManager {
@ -49,6 +48,7 @@ impl FileManager {
}
}
#[allow(dead_code)]
pub(crate) fn close<T>(&mut self, id: T)
where
T: Into<FileId>,
@ -71,12 +71,15 @@ impl FileManager {
Ok(path)
}
#[allow(dead_code)]
pub(crate) fn get_info(&self, id: &FileId) -> Option<&FileInfo> { self.file_info.get(id) }
#[allow(dead_code)]
pub(crate) fn get_file_id(&self, path: &Path) -> Option<FileId> {
self.open_files.get(path).cloned()
}
#[allow(dead_code)]
pub fn check_file(&mut self, path: &Path, id: &FileId) -> bool {
if let Some(info) = self.file_info.get_mut(&id) {
let modified_time = get_modified_time(path);

View File

@ -36,5 +36,5 @@ impl DocTableSql {
Ok(doc_table)
}
pub(crate) fn delete_doc(&self, view_id: &str) -> Result<(), EditorError> { unimplemented!() }
pub(crate) fn delete_doc(&self, _view_id: &str) -> Result<(), EditorError> { unimplemented!() }
}

View File

@ -1,7 +1,6 @@
use crate::entities::doc::{CreateDocParams, DocInfo, UpdateDocParams};
use flowy_database::schema::doc_table;
use flowy_infra::{timestamp, uuid};
use std::convert::TryInto;
use flowy_infra::timestamp;
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
#[table_name = "doc_table"]

View File

@ -1,5 +1,5 @@
mod doc_sql;
mod doc_table;
pub use doc_sql::*;
pub use doc_table::*;
pub(crate) use doc_sql::*;
pub(crate) use doc_table::*;

Some files were not shown because too many files have changed in this diff Show More