diff --git a/app_flowy/.vscode/tasks.json b/app_flowy/.vscode/tasks.json index 539b284ce9..98ce703ff7 100644 --- a/app_flowy/.vscode/tasks.json +++ b/app_flowy/.vscode/tasks.json @@ -18,9 +18,9 @@ "options": { "cwd": "${workspaceFolder}/../" }, - "problemMatcher": [ - "$rustc" - ], + // "problemMatcher": [ + // "$rustc" + // ], "label": "BuildRust" } ] diff --git a/app_flowy/analysis_options.yaml b/app_flowy/analysis_options.yaml index eb5b057c3c..c4268a9269 100644 --- a/app_flowy/analysis_options.yaml +++ b/app_flowy/analysis_options.yaml @@ -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 diff --git a/app_flowy/assets/images/app_flowy_logo.jpg b/app_flowy/assets/images/app_flowy_logo.jpg new file mode 100644 index 0000000000..bb27e0ddb1 Binary files /dev/null and b/app_flowy/assets/images/app_flowy_logo.jpg differ diff --git a/app_flowy/lib/user/presentation/sign_in/sign_in_screen.dart b/app_flowy/lib/user/presentation/sign_in/sign_in_screen.dart index 286463167c..9602a73ffd 100644 --- a/app_flowy/lib/user/presentation/sign_in/sign_in_screen.dart +++ b/app_flowy/lib/user/presentation/sign_in/sign_in_screen.dart @@ -1,8 +1,15 @@ 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/presentation/sign_in/widgets/background.dart'; +import 'package:app_flowy/workspace/presentation/home/home_screen.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); @@ -11,9 +18,129 @@ class SignInScreen extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => getIt(), - child: const Scaffold( - body: Body(), + child: Scaffold( + body: BlocProvider( + create: (context) => getIt(), + child: BlocConsumer( + listenWhen: (p, c) => p != c, + listener: (context, state) { + state.signInFailure.fold( + () {}, + (result) => _handleStateErrors(result, context), + ); + }, + builder: (context, state) => const SignInForm(), + ), + ), + ), + ); + } + + void _handleStateErrors( + Either 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 SignInForm extends StatelessWidget { + const SignInForm({ + Key? key, + }) : 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), + RoundedInputField( + hintText: 'email', + onChanged: (value) => + context.read().add(SignInEvent.emailChanged(value)), + ), + RoundedInputField( + obscureText: true, + hintText: 'password', + onChanged: (value) => context + .read() + .add(SignInEvent.passwordChanged(value)), + ), + TextButton( + style: TextButton.styleFrom( + textStyle: const TextStyle(fontSize: 12), + ), + onPressed: () => _showForgetPasswordScreen(context), + child: const Text( + 'Forgot Password?', + style: TextStyle(color: Colors.lightBlue), + ), + ), + RoundedButton( + title: 'Login', + height: 60, + borderRadius: BorderRadius.circular(10), + color: Colors.lightBlue, + press: () { + context + .read() + .add(const SignInEvent.signedInWithUserEmailAndPassword()); + }, + ), + const VSpace(10), + 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: () {}, + child: const Text( + 'Sign Up', + style: TextStyle(color: Colors.lightBlue), + ), + ), + ], + mainAxisAlignment: MainAxisAlignment.center, + ), + if (context.read().state.isSubmitting) ...[ + const SizedBox(height: 8), + const LinearProgressIndicator(value: null), + ] + ], + ), + ); + } + + void _showForgetPasswordScreen(BuildContext context) { + throw UnimplementedError(); + } +} diff --git a/app_flowy/lib/user/presentation/sign_in/widgets/background.dart b/app_flowy/lib/user/presentation/sign_in/widgets/background.dart index a33ae64e27..4bab31741f 100644 --- a/app_flowy/lib/user/presentation/sign_in/widgets/background.dart +++ b/app_flowy/lib/user/presentation/sign_in/widgets/background.dart @@ -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 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, + ), + ) + ], + ), + ); } } diff --git a/app_flowy/lib/user/presentation/sign_in/widgets/body.dart b/app_flowy/lib/user/presentation/sign_in/widgets/body.dart deleted file mode 100644 index be49b3f7b9..0000000000 --- a/app_flowy/lib/user/presentation/sign_in/widgets/body.dart +++ /dev/null @@ -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(), - child: const SignInBackground( - child: SignInForm(), - ), - ); - } -} - -class SignInForm extends StatelessWidget { - const SignInForm({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return BlocConsumer( - 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() - .add(SignInEvent.emailChanged(value)), - ), - RoundedInputField( - icon: Icons.lock, - obscureText: true, - hintText: 'password', - onChanged: (value) => context - .read() - .add(SignInEvent.passwordChanged(value)), - ), - RoundedButton( - title: 'LOGIN', - press: () { - context - .read() - .add(const SignInEvent.signedInWithUserEmailAndPassword()); - }, - ), - if (state.isSubmitting) ...[ - const SizedBox(height: 8), - const LinearProgressIndicator(value: null), - ] - ], - ); - }, - ); - } - - void _handleStateErrors( - Either 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 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), - ), - ); - } -} diff --git a/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_button.dart b/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_button.dart index 72ead5951e..eced9d0ab6 100644 --- a/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_button.dart +++ b/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_button.dart @@ -3,13 +3,23 @@ import 'package:flutter/material.dart'; class RoundedButton 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; const RoundedButton({ 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, }) : super(key: key); @override @@ -17,15 +27,22 @@ class RoundedButton extends StatelessWidget { return ConstrainedBox( constraints: BoxConstraints( minWidth: 100, - maxWidth: size?.width ?? double.infinity, + maxWidth: width ?? double.infinity, minHeight: 50, - maxHeight: size?.height ?? double.infinity, + 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)), + onPressed: press, + ), ), ), ); diff --git a/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart b/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart index e570e4e2b6..e3339b2118 100644 --- a/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart +++ b/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart @@ -10,26 +10,33 @@ class RoundedInputField extends StatelessWidget { const RoundedInputField({ Key? key, this.hintText, - this.icon = Icons.person, + this.icon, this.obscureText = false, this.onChanged, }) : super(key: key); @override Widget build(BuildContext context) { + final Icon? newIcon = icon == null + ? null + : Icon( + icon!, + color: const Color(0xFF6F35A5), + ); + return TextFieldContainer( - child: TextFormField( - onChanged: onChanged, - cursorColor: const Color(0xFF6F35A5), - obscureText: obscureText, - decoration: InputDecoration( - icon: Icon( - icon, - color: const Color(0xFF6F35A5), + borderRadius: BorderRadius.circular(10), + borderColor: Colors.blueGrey, + child: TextFormField( + onChanged: onChanged, + cursorColor: const Color(0xFF6F35A5), + obscureText: obscureText, + decoration: InputDecoration( + icon: newIcon, + hintText: hintText, + border: InputBorder.none, ), - hintText: hintText, - border: InputBorder.none, ), - )); + ); } } diff --git a/app_flowy/packages/flowy_infra_ui/lib/widget/text_field_container.dart b/app_flowy/packages/flowy_infra_ui/lib/widget/text_field_container.dart index 5808ae7b8a..d6116b4c7c 100644 --- a/app_flowy/packages/flowy_infra_ui/lib/widget/text_field_container.dart +++ b/app_flowy/packages/flowy_infra_ui/lib/widget/text_field_container.dart @@ -3,21 +3,30 @@ import 'package:flutter/material.dart'; class TextFieldContainer extends StatelessWidget { final Widget child; + final BorderRadius borderRadius; + final Color borderColor; + final Size? size; const TextFieldContainer({ Key? key, required this.child, + this.borderRadius = BorderRadius.zero, + this.borderColor = Colors.white, + this.size, }) : super(key: key); @override Widget build(BuildContext context) { + double height = size == null ? 50 : size!.height; return Container( margin: const EdgeInsets.symmetric(vertical: 10), - padding: const EdgeInsets.symmetric(horizontal: 20), + padding: const EdgeInsets.symmetric(horizontal: 15), + height: height, 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), ); }