This commit is contained in:
Christian Pauly 2021-04-09 14:56:23 +02:00
parent 9f8fa5fc1e
commit 829b3b2660
9 changed files with 323 additions and 254 deletions

BIN
assets/banner_dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -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');
}
}

View File

@ -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),
);
}
}

View File

@ -66,6 +66,13 @@ abstract class FluffyThemes {
padding: EdgeInsets.all(12),
),
),
cardTheme: CardTheme(
elevation: 7,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
),
clipBehavior: Clip.hardEdge,
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppConfig.borderRadius)),
@ -112,6 +119,13 @@ abstract class FluffyThemes {
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
),
),
cardTheme: CardTheme(
elevation: 7,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
),
clipBehavior: Clip.hardEdge,
),
floatingActionButtonTheme: FloatingActionButtonThemeData(
backgroundColor: AppConfig.primaryColor,
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(
brightness: Brightness.dark,
color: Color(0xff1D1D1D),

View File

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

View File

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

View File

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

View File

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

View File

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