onboarding
Christian Pauly 4 years ago
parent 49092744f0
commit 937b69fec9

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class FluffyBanner extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Image.asset(Theme.of(context).brightness == Brightness.dark
? 'assets/banner_dark.png'
: 'assets/banner.png');
}
}

@ -0,0 +1,40 @@
import 'dart:math';
import 'package:flutter/material.dart';
class OnePageCard extends StatelessWidget {
final Widget child;
const OnePageCard({Key key, this.child}) : super(key: key);
static const int alpha = 64;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor,
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
stops: [
0.1,
0.4,
0.6,
0.9,
],
colors: [
Theme.of(context).secondaryHeaderColor.withAlpha(alpha),
Theme.of(context).primaryColor.withAlpha(alpha),
Theme.of(context).accentColor.withAlpha(alpha),
Theme.of(context).backgroundColor.withAlpha(alpha),
],
),
),
padding: EdgeInsets.symmetric(
horizontal: max((MediaQuery.of(context).size.width - 600) / 2, 0),
vertical: max((MediaQuery.of(context).size.height - 800) / 2, 0),
),
child: Card(child: child),
);
}
}

@ -66,6 +66,13 @@ abstract class FluffyThemes {
padding: EdgeInsets.all(12), padding: EdgeInsets.all(12),
), ),
), ),
cardTheme: CardTheme(
elevation: 7,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
),
clipBehavior: Clip.hardEdge,
),
inputDecorationTheme: InputDecorationTheme( inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppConfig.borderRadius)), borderRadius: BorderRadius.circular(AppConfig.borderRadius)),
@ -112,6 +119,13 @@ abstract class FluffyThemes {
borderRadius: BorderRadius.circular(AppConfig.borderRadius), borderRadius: BorderRadius.circular(AppConfig.borderRadius),
), ),
), ),
cardTheme: CardTheme(
elevation: 7,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
),
clipBehavior: Clip.hardEdge,
),
floatingActionButtonTheme: FloatingActionButtonThemeData( floatingActionButtonTheme: FloatingActionButtonThemeData(
backgroundColor: AppConfig.primaryColor, backgroundColor: AppConfig.primaryColor,
foregroundColor: Colors.white, foregroundColor: Colors.white,
@ -128,6 +142,17 @@ abstract class FluffyThemes {
), ),
), ),
), ),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
primary: AppConfig.primaryColor,
onPrimary: Colors.white,
elevation: 7,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
),
padding: EdgeInsets.all(12),
),
),
appBarTheme: AppBarTheme( appBarTheme: AppBarTheme(
brightness: Brightness.dark, brightness: Brightness.dark,
color: Color(0xff1D1D1D), color: Color(0xff1D1D1D),

@ -204,6 +204,9 @@ class _ChatListState extends State<ChatList> {
return Scaffold( return Scaffold(
appBar: appBar ?? appBar: appBar ??
AppBar( AppBar(
elevation: AdaptivePageLayout.of(context).columnMode(context)
? 1
: null,
leading: selectMode == SelectMode.normal leading: selectMode == SelectMode.normal
? null ? null
: IconButton( : IconButton(

@ -1,11 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'dart:math';
import 'package:adaptive_page_layout/adaptive_page_layout.dart'; import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/default_app_bar_search_field.dart'; import 'package:fluffychat/components/default_app_bar_search_field.dart';
import 'package:fluffychat/components/fluffy_banner.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/app_config.dart'; import 'package:fluffychat/app_config.dart';
import 'package:fluffychat/components/one_page_card.dart';
import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/platform_infos.dart';
@ -120,9 +121,6 @@ class _HomeserverPickerState extends State<HomeserverPicker> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final padding = EdgeInsets.symmetric(
horizontal: max((MediaQuery.of(context).size.width - 600) / 2, 0),
);
if (kIsWeb) { if (kIsWeb) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
final token = final token =
@ -130,28 +128,28 @@ class _HomeserverPickerState extends State<HomeserverPicker> {
_loginWithToken(token); _loginWithToken(token);
}); });
} }
return Scaffold( return OnePageCard(
appBar: AppBar( child: Scaffold(
title: DefaultAppBarSearchField( appBar: AppBar(
prefixText: 'https://', titleSpacing: 8,
hintText: L10n.of(context).enterYourHomeserver, title: DefaultAppBarSearchField(
searchController: _controller, prefixText: 'https://',
suffix: Icon(Icons.edit_outlined), hintText: L10n.of(context).enterYourHomeserver,
padding: padding, searchController: _controller,
onChanged: (s) => _domain = s, suffix: Icon(Icons.edit_outlined),
readOnly: !AppConfig.allowOtherHomeservers, padding: EdgeInsets.zero,
onSubmit: (_) => _checkHomeserverAction(context), onChanged: (s) => _domain = s,
readOnly: !AppConfig.allowOtherHomeservers,
onSubmit: (_) => _checkHomeserverAction(context),
),
elevation: 0,
), ),
elevation: 0, body: SafeArea(
),
body: SafeArea(
child: Padding(
padding: padding,
child: ListView( child: ListView(
children: [ children: [
Hero( Hero(
tag: 'loginBanner', tag: 'loginBanner',
child: Image.asset('assets/banner.png'), child: FluffyBanner(),
), ),
Padding( Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
@ -167,10 +165,7 @@ class _HomeserverPickerState extends State<HomeserverPicker> {
], ],
), ),
), ),
), bottomNavigationBar: Column(
bottomNavigationBar: Padding(
padding: padding,
child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Hero( Hero(

@ -1,9 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'dart:math';
import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:adaptive_page_layout/adaptive_page_layout.dart'; import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/one_page_card.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
@ -184,96 +184,95 @@ class _LoginState extends State<Login> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return OnePageCard(
appBar: AppBar( child: Scaffold(
leading: loading ? Container() : BackButton(), appBar: AppBar(
elevation: 0, leading: loading ? Container() : BackButton(),
title: Text( elevation: 0,
L10n.of(context).logInTo(Matrix.of(context) title: Text(
.client L10n.of(context).logInTo(Matrix.of(context)
.homeserver .client
.toString() .homeserver
.replaceFirst('https://', '')), .toString()
.replaceFirst('https://', '')),
),
), ),
), body: Builder(builder: (context) {
body: Builder(builder: (context) { return ListView(
return ListView( children: <Widget>[
padding: EdgeInsets.symmetric( Padding(
horizontal: padding: const EdgeInsets.all(12.0),
max((MediaQuery.of(context).size.width - 600) / 2, 0)), child: TextField(
children: <Widget>[ readOnly: loading,
Padding( autocorrect: false,
padding: const EdgeInsets.all(12.0), autofocus: true,
child: TextField( onChanged: (t) => _checkWellKnownWithCoolDown(t, context),
readOnly: loading, controller: usernameController,
autocorrect: false, autofillHints: loading ? null : [AutofillHints.username],
autofocus: true, decoration: InputDecoration(
onChanged: (t) => _checkWellKnownWithCoolDown(t, context), prefixIcon: Icon(Icons.account_box_outlined),
controller: usernameController, hintText:
autofillHints: loading ? null : [AutofillHints.username], '@${L10n.of(context).username.toLowerCase()}:domain',
decoration: InputDecoration( errorText: usernameError,
prefixIcon: Icon(Icons.account_box_outlined), labelText: L10n.of(context).username),
hintText: ),
'@${L10n.of(context).username.toLowerCase()}:domain',
errorText: usernameError,
labelText: L10n.of(context).username),
), ),
), Padding(
Padding( padding: const EdgeInsets.all(12.0),
padding: const EdgeInsets.all(12.0), child: TextField(
child: TextField( readOnly: loading,
readOnly: loading, autocorrect: false,
autocorrect: false, autofillHints: loading ? null : [AutofillHints.password],
autofillHints: loading ? null : [AutofillHints.password], controller: passwordController,
controller: passwordController, obscureText: !showPassword,
obscureText: !showPassword, onSubmitted: (t) => login(context),
onSubmitted: (t) => login(context), decoration: InputDecoration(
decoration: InputDecoration( prefixIcon: Icon(Icons.lock_outlined),
prefixIcon: Icon(Icons.lock_outlined), hintText: '****',
hintText: '****', errorText: passwordError,
errorText: passwordError, suffixIcon: IconButton(
suffixIcon: IconButton( tooltip: L10n.of(context).showPassword,
tooltip: L10n.of(context).showPassword, icon: Icon(showPassword
icon: Icon(showPassword ? Icons.visibility_off_outlined
? Icons.visibility_off_outlined : Icons.visibility_outlined),
: Icons.visibility_outlined), onPressed: () =>
onPressed: () => setState(() => showPassword = !showPassword),
setState(() => showPassword = !showPassword), ),
), labelText: L10n.of(context).password),
labelText: L10n.of(context).password), ),
), ),
), SizedBox(height: 12),
SizedBox(height: 12), Hero(
Hero( tag: 'loginButton',
tag: 'loginButton', child: Padding(
child: Padding( padding: EdgeInsets.symmetric(horizontal: 12),
padding: EdgeInsets.symmetric(horizontal: 12), child: ElevatedButton(
child: ElevatedButton( onPressed: loading ? null : () => login(context),
onPressed: loading ? null : () => login(context), child: loading
child: loading ? LinearProgressIndicator()
? LinearProgressIndicator() : Text(
: Text( L10n.of(context).login.toUpperCase(),
L10n.of(context).login.toUpperCase(), style: TextStyle(color: Colors.white, fontSize: 16),
style: TextStyle(color: Colors.white, fontSize: 16), ),
), ),
), ),
), ),
), Center(
Center( child: TextButton(
child: TextButton( onPressed: () => _passwordForgotten(context),
onPressed: () => _passwordForgotten(context), child: Text(
child: Text( L10n.of(context).passwordForgotten,
L10n.of(context).passwordForgotten, style: TextStyle(
style: TextStyle( color: Colors.blue,
color: Colors.blue, decoration: TextDecoration.underline,
decoration: TextDecoration.underline, ),
), ),
), ),
), ),
), ],
], );
); }),
}), ),
); );
} }
} }

@ -1,10 +1,10 @@
import 'dart:math';
import 'package:adaptive_page_layout/adaptive_page_layout.dart'; import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:file_picker_cross/file_picker_cross.dart'; import 'package:file_picker_cross/file_picker_cross.dart';
import 'package:fluffychat/components/fluffy_banner.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/components/one_page_card.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -67,103 +67,101 @@ class _SignUpState extends State<SignUp> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return OnePageCard(
appBar: AppBar( child: Scaffold(
elevation: 0, appBar: AppBar(
leading: loading ? Container() : BackButton(), elevation: 0,
title: Text( leading: loading ? Container() : BackButton(),
Matrix.of(context) title: Text(
.client Matrix.of(context)
.homeserver .client
.toString() .homeserver
.replaceFirst('https://', ''), .toString()
.replaceFirst('https://', ''),
),
), ),
), body: ListView(children: <Widget>[
body: ListView( Hero(
padding: EdgeInsets.symmetric( tag: 'loginBanner',
horizontal: child: FluffyBanner(),
max((MediaQuery.of(context).size.width - 600) / 2, 0)), ),
children: <Widget>[ SizedBox(height: 16),
Hero( Padding(
tag: 'loginBanner', padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Image.asset('assets/banner.png'), child: TextField(
), readOnly: loading,
SizedBox(height: 16), autocorrect: false,
Padding( controller: usernameController,
padding: const EdgeInsets.symmetric(horizontal: 12.0), onSubmitted: (s) => signUpAction(context),
child: TextField( autofillHints: loading ? null : [AutofillHints.newUsername],
readOnly: loading, decoration: InputDecoration(
autocorrect: false, prefixIcon: Icon(Icons.account_circle_outlined),
controller: usernameController, hintText: L10n.of(context).username,
onSubmitted: (s) => signUpAction(context), errorText: usernameError,
autofillHints: loading ? null : [AutofillHints.newUsername], labelText: L10n.of(context).chooseAUsername,
decoration: InputDecoration(
prefixIcon: Icon(Icons.account_circle_outlined),
hintText: L10n.of(context).username,
errorText: usernameError,
labelText: L10n.of(context).chooseAUsername,
),
), ),
), ),
SizedBox(height: 8), ),
ListTile( SizedBox(height: 8),
leading: CircleAvatar( ListTile(
backgroundImage: leading: CircleAvatar(
avatar == null ? null : MemoryImage(avatar.bytes), backgroundImage:
backgroundColor: avatar == null avatar == null ? null : MemoryImage(avatar.bytes),
? Theme.of(context).brightness == Brightness.dark backgroundColor: avatar == null
? Color(0xff121212) ? Theme.of(context).brightness == Brightness.dark
: Colors.white ? Color(0xff121212)
: Theme.of(context).secondaryHeaderColor, : Colors.white
child: avatar == null : Theme.of(context).secondaryHeaderColor,
? Icon(Icons.camera_alt_outlined, child: avatar == null
color: Theme.of(context).primaryColor) ? Icon(Icons.camera_alt_outlined,
: null, color: Theme.of(context).primaryColor)
), : null,
trailing: avatar == null
? null
: Icon(
Icons.close,
color: Colors.red,
),
title: Text(avatar == null
? L10n.of(context).setAProfilePicture
: L10n.of(context).discardPicture),
onTap: avatar == null
? setAvatarAction
: () => setState(() => avatar = null),
), ),
SizedBox(height: 16), trailing: avatar == null
Hero( ? null
tag: 'loginButton', : Icon(
child: Padding( Icons.close,
padding: EdgeInsets.symmetric(horizontal: 12), color: Colors.red,
child: ElevatedButton( ),
onPressed: loading ? null : () => signUpAction(context), title: Text(avatar == null
child: loading ? L10n.of(context).setAProfilePicture
? LinearProgressIndicator() : L10n.of(context).discardPicture),
: Text( onTap: avatar == null
L10n.of(context).signUp.toUpperCase(), ? setAvatarAction
style: TextStyle(color: Colors.white, fontSize: 16), : () => setState(() => avatar = null),
), ),
), SizedBox(height: 16),
Hero(
tag: 'loginButton',
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 12),
child: ElevatedButton(
onPressed: loading ? null : () => signUpAction(context),
child: loading
? LinearProgressIndicator()
: Text(
L10n.of(context).signUp.toUpperCase(),
style: TextStyle(color: Colors.white, fontSize: 16),
),
), ),
), ),
Center( ),
child: TextButton( Center(
onPressed: () => child: TextButton(
AdaptivePageLayout.of(context).pushNamed('/login'), onPressed: () =>
child: Text( AdaptivePageLayout.of(context).pushNamed('/login'),
L10n.of(context).alreadyHaveAnAccount, child: Text(
style: TextStyle( L10n.of(context).alreadyHaveAnAccount,
decoration: TextDecoration.underline, style: TextStyle(
color: Colors.blue, decoration: TextDecoration.underline,
fontSize: 16, color: Colors.blue,
), fontSize: 16,
), ),
), ),
), ),
]), ),
]),
),
); );
} }
} }

@ -1,11 +1,10 @@
import 'dart:math';
import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:adaptive_page_layout/adaptive_page_layout.dart'; import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/components/matrix.dart';
import 'package:fluffychat/components/one_page_card.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -131,60 +130,60 @@ class _SignUpPasswordState extends State<SignUpPassword> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return OnePageCard(
appBar: AppBar( child: Scaffold(
elevation: 0, appBar: AppBar(
leading: loading ? Container() : BackButton(), elevation: 0,
title: Text( leading: loading ? Container() : BackButton(),
L10n.of(context).chooseAStrongPassword, title: Text(
L10n.of(context).chooseAStrongPassword,
),
), ),
), body: ListView(
body: ListView( children: <Widget>[
padding: EdgeInsets.symmetric( Padding(
horizontal: max((MediaQuery.of(context).size.width - 600) / 2, 0)), padding: const EdgeInsets.all(12.0),
children: <Widget>[ child: TextField(
Padding( controller: passwordController,
padding: const EdgeInsets.all(12.0), obscureText: !showPassword,
child: TextField( autofocus: true,
controller: passwordController, readOnly: loading,
obscureText: !showPassword, autocorrect: false,
autofocus: true, onSubmitted: (t) => _signUpAction(context),
readOnly: loading, autofillHints: loading ? null : [AutofillHints.newPassword],
autocorrect: false, decoration: InputDecoration(
onSubmitted: (t) => _signUpAction(context), prefixIcon: Icon(Icons.lock_outlined),
autofillHints: loading ? null : [AutofillHints.newPassword], hintText: '****',
decoration: InputDecoration( errorText: passwordError,
prefixIcon: Icon(Icons.lock_outlined), suffixIcon: IconButton(
hintText: '****', tooltip: L10n.of(context).showPassword,
errorText: passwordError, icon: Icon(showPassword
suffixIcon: IconButton( ? Icons.visibility_off_outlined
tooltip: L10n.of(context).showPassword, : Icons.visibility_outlined),
icon: Icon(showPassword onPressed: () =>
? Icons.visibility_off_outlined setState(() => showPassword = !showPassword),
: Icons.visibility_outlined), ),
onPressed: () => labelText: L10n.of(context).password),
setState(() => showPassword = !showPassword), ),
),
labelText: L10n.of(context).password),
), ),
), SizedBox(height: 12),
SizedBox(height: 12), Hero(
Hero( tag: 'loginButton',
tag: 'loginButton', child: Padding(
child: Padding( padding: EdgeInsets.symmetric(horizontal: 12),
padding: EdgeInsets.symmetric(horizontal: 12), child: ElevatedButton(
child: ElevatedButton( onPressed: loading ? null : () => _signUpAction(context),
onPressed: loading ? null : () => _signUpAction(context), child: loading
child: loading ? LinearProgressIndicator()
? LinearProgressIndicator() : Text(
: Text( L10n.of(context).createAccountNow.toUpperCase(),
L10n.of(context).createAccountNow.toUpperCase(), style: TextStyle(color: Colors.white, fontSize: 16),
style: TextStyle(color: Colors.white, fontSize: 16), ),
), ),
), ),
), ),
), ],
], ),
), ),
); );
} }

Loading…
Cancel
Save