Redesign login pages

This commit is contained in:
Christian Pauly 2020-01-27 10:59:03 +01:00
parent cc61d8e91a
commit e4ed3cc7ef
11 changed files with 40 additions and 334 deletions

View File

@ -1,94 +0,0 @@
import 'package:fluffychat/i18n/i18n.dart';
import 'package:fluffychat/views/chat.dart';
import 'package:fluffychat/views/invitation_selection.dart';
import 'package:flutter/material.dart';
import 'package:pedantic/pedantic.dart';
import '../matrix.dart';
class NewGroupDialog extends StatefulWidget {
@override
_NewGroupDialogState createState() => _NewGroupDialogState();
}
class _NewGroupDialogState extends State<NewGroupDialog> {
TextEditingController controller = TextEditingController();
bool publicGroup = false;
void submitAction(BuildContext context) async {
final MatrixState matrix = Matrix.of(context);
Map<String, dynamic> params = {};
if (publicGroup) {
params["preset"] = "public_chat";
params["visibility"] = "public";
if (controller.text.isNotEmpty) {
params["room_alias_name"] = controller.text;
}
} else {
params["preset"] = "private_chat";
}
if (controller.text.isNotEmpty) params["name"] = controller.text;
final String roomID = await matrix.tryRequestWithLoadingDialog(
matrix.client.createRoom(params: params),
);
Navigator.of(context).pop();
if (roomID != null) {
unawaited(
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return ChatView(roomID);
}),
),
);
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InvitationSelection(
matrix.client.getRoomById(roomID),
),
),
);
}
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(I18n.of(context).createNewGroup),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
controller: controller,
autocorrect: false,
textInputAction: TextInputAction.go,
onSubmitted: (s) => submitAction(context),
decoration: InputDecoration(
labelText: I18n.of(context).optionalGroupName,
icon: Icon(Icons.people),
hintText: I18n.of(context).enterAGroupName),
),
SwitchListTile(
title: Text(I18n.of(context).groupIsPublic),
value: publicGroup,
onChanged: (bool b) => setState(() => publicGroup = b),
),
],
),
actions: <Widget>[
FlatButton(
child: Text(I18n.of(context).close.toUpperCase(),
style: TextStyle(color: Colors.blueGrey)),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text(I18n.of(context).create.toUpperCase()),
onPressed: () => submitAction(context),
),
],
);
}
}

View File

@ -1,210 +0,0 @@
import 'dart:async';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/components/avatar.dart';
import 'package:fluffychat/i18n/i18n.dart';
import 'package:fluffychat/views/chat.dart';
import 'package:flutter/material.dart';
import 'package:share/share.dart';
import '../matrix.dart';
class NewPrivateChatDialog extends StatefulWidget {
@override
_NewPrivateChatDialogState createState() => _NewPrivateChatDialogState();
}
class _NewPrivateChatDialogState extends State<NewPrivateChatDialog> {
TextEditingController controller = TextEditingController();
final _formKey = GlobalKey<FormState>();
bool loading = false;
String currentSearchTerm;
Map<String, dynamic> foundProfile;
Timer coolDown;
bool get correctMxId =>
foundProfile != null && foundProfile["user_id"] == "@$currentSearchTerm";
void submitAction(BuildContext context) async {
if (controller.text.isEmpty) return;
if (!_formKey.currentState.validate()) return;
final MatrixState matrix = Matrix.of(context);
if ("@" + controller.text.trim() == matrix.client.userID) return;
final User user = User(
"@" + controller.text.trim(),
room: Room(id: "", client: matrix.client),
);
final String roomID =
await matrix.tryRequestWithLoadingDialog(user.startDirectChat());
Navigator.of(context).pop();
if (roomID != null) {
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => ChatView(roomID)),
);
}
}
void searchUserWithCoolDown(BuildContext context, String text) async {
coolDown?.cancel();
coolDown = Timer(
Duration(seconds: 1),
() => searchUser(context, text),
);
}
void searchUser(BuildContext context, String text) async {
if (text.isEmpty) {
setState(() {
foundProfile = null;
});
}
currentSearchTerm = text;
if (currentSearchTerm.isEmpty) return;
if (loading) return;
setState(() => loading = true);
final MatrixState matrix = Matrix.of(context);
final response = await matrix.tryRequestWithErrorToast(
matrix.client.jsonRequest(
type: HTTPType.POST,
action: "/client/r0/user_directory/search",
data: {
"search_term": text,
"limit": 1,
}),
);
setState(() => loading = false);
if (response == false ||
!(response is Map) ||
(response["results"]?.isEmpty ?? true)) return;
setState(() {
foundProfile = response["results"].first;
});
}
@override
Widget build(BuildContext context) {
final String defaultDomain = Matrix.of(context).client.userID.split(":")[1];
return AlertDialog(
title: Text(I18n.of(context).newPrivateChat),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Form(
key: _formKey,
child: TextFormField(
controller: controller,
autofocus: true,
autocorrect: false,
onChanged: (String text) => searchUserWithCoolDown(context, text),
textInputAction: TextInputAction.go,
onFieldSubmitted: (s) => submitAction(context),
validator: (value) {
if (value.isEmpty) {
return I18n.of(context).pleaseEnterAMatrixIdentifier;
}
final MatrixState matrix = Matrix.of(context);
String mxid = "@" + controller.text.trim();
if (mxid == matrix.client.userID) {
return I18n.of(context).youCannotInviteYourself;
}
if (!mxid.contains("@")) {
return I18n.of(context).makeSureTheIdentifierIsValid;
}
if (!mxid.contains(":")) {
return I18n.of(context).makeSureTheIdentifierIsValid;
}
return null;
},
decoration: InputDecoration(
labelText: I18n.of(context).enterAUsername,
icon: loading
? Container(
width: 24,
height: 24,
child: CircularProgressIndicator(strokeWidth: 1),
)
: correctMxId
? Avatar(
MxContent(foundProfile["avatar_url"] ?? ""),
foundProfile["display_name"] ??
foundProfile["user_id"],
size: 24,
)
: Icon(Icons.account_circle),
prefixText: "@",
hintText:
"${I18n.of(context).username.toLowerCase()}:$defaultDomain",
),
),
),
if (foundProfile != null && !correctMxId)
ListTile(
onTap: () {
setState(() {
controller.text =
currentSearchTerm = foundProfile["user_id"].substring(1);
});
},
leading: Avatar(
MxContent(foundProfile["avatar_url"] ?? ""),
foundProfile["display_name"] ?? foundProfile["user_id"],
//size: 24,
),
contentPadding: EdgeInsets.all(0),
title: Text(
foundProfile["display_name"] ??
foundProfile["user_id"].split(":").first.substring(1),
style: TextStyle(),
maxLines: 1,
),
subtitle: Text(
foundProfile["user_id"],
maxLines: 1,
style: TextStyle(
fontSize: 12,
),
),
),
if (foundProfile == null || correctMxId)
ListTile(
trailing: Icon(
Icons.share,
size: 16,
),
contentPadding: EdgeInsets.all(0),
onTap: () => Share.share(
"https://matrix.to/#/${Matrix.of(context).client.userID}"),
title: Text(
"${I18n.of(context).yourOwnUsername}:",
style: TextStyle(
color: Colors.blueGrey,
fontSize: 12,
),
),
subtitle: Text(
Matrix.of(context).client.userID,
),
),
Divider(height: 1),
],
),
actions: <Widget>[
FlatButton(
child: Text(I18n.of(context).close.toUpperCase(),
style: TextStyle(color: Colors.blueGrey)),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text(I18n.of(context).confirm.toUpperCase()),
onPressed: () => submitAction(context),
),
],
);
}
}

View File

@ -67,9 +67,9 @@ class Message extends StatelessWidget {
].contains(event.messageType) &&
event.body.isNotEmpty) {
popupMenuList.add(
const PopupMenuItem<String>(
PopupMenuItem<String>(
value: "copy",
child: Text('Copy'),
child: Text(I18n.of(context).copy),
),
);
}

View File

@ -200,6 +200,8 @@ class I18n {
String get copiedToClipboard => Intl.message("Copied to clipboard");
String get copy => Intl.message("Copy");
String get couldNotDecryptMessage =>
Intl.message("Could not decrypt message");

View File

@ -886,7 +886,7 @@
"targetName": {}
}
},
"Unmute chat": "Nicht mehr stummschalten",
"Unmute chat": "Stumm aus",
"@Unmute chat": {
"type": "text",
"placeholders": {}

View File

@ -215,7 +215,7 @@ class _ChatDetailsState extends State<ChatDetails> {
child: Icon(Icons.edit),
)
: null,
title: Text("Group description:",
title: Text("${I18n.of(context).groupDescription}:",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold)),

View File

@ -105,8 +105,7 @@ class _LoginState extends State<Login> {
),
body: ListView(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: max((MediaQuery.of(context).size.width - 600) / 2, 16)),
horizontal: max((MediaQuery.of(context).size.width - 600) / 2, 0)),
children: <Widget>[
Container(
height: 150,
@ -114,15 +113,15 @@ class _LoginState extends State<Login> {
child: Center(
child: Icon(
Icons.vpn_key,
color: Theme.of(context).primaryColor,
size: 40,
size: 60,
),
),
),
ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue,
child: Icon(Icons.account_box),
backgroundColor: Colors.white,
child: Icon(Icons.account_box,
color: Theme.of(context).primaryColor),
),
title: TextField(
autocorrect: false,
@ -136,8 +135,8 @@ class _LoginState extends State<Login> {
),
ListTile(
leading: CircleAvatar(
backgroundColor: Colors.yellow,
child: Icon(Icons.lock),
backgroundColor: Colors.white,
child: Icon(Icons.lock, color: Theme.of(context).primaryColor),
),
title: TextField(
autocorrect: false,
@ -159,16 +158,17 @@ class _LoginState extends State<Login> {
SizedBox(height: 20),
Container(
height: 50,
padding: EdgeInsets.symmetric(horizontal: 12),
child: RaisedButton(
elevation: 7,
color: Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
borderRadius: BorderRadius.circular(6),
),
child: loading
? CircularProgressIndicator()
: Text(
I18n.of(context).login,
I18n.of(context).login.toUpperCase(),
style: TextStyle(color: Colors.white, fontSize: 16),
),
onPressed: () => loading ? null : login(context),

View File

@ -107,18 +107,20 @@ class _SignUpState extends State<SignUp> {
),
body: ListView(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal:
max((MediaQuery.of(context).size.width - 600) / 2, 16)),
max((MediaQuery.of(context).size.width - 600) / 2, 0)),
children: <Widget>[
Image.asset("assets/fluffychat-banner.png"),
ListTile(
leading: CircleAvatar(
backgroundImage: avatar == null ? null : FileImage(avatar),
backgroundColor: avatar == null
? Colors.green
? Colors.white
: Theme.of(context).secondaryHeaderColor,
child: avatar == null ? Icon(Icons.camera_alt) : null,
child: avatar == null
? Icon(Icons.camera_alt,
color: Theme.of(context).primaryColor)
: null,
),
trailing: avatar == null
? null
@ -135,8 +137,11 @@ class _SignUpState extends State<SignUp> {
),
ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue,
child: Icon(Icons.account_box),
backgroundColor: Colors.white,
child: Icon(
Icons.account_circle,
color: Theme.of(context).primaryColor,
),
),
title: TextField(
autocorrect: false,
@ -151,16 +156,17 @@ class _SignUpState extends State<SignUp> {
SizedBox(height: 20),
Container(
height: 50,
padding: EdgeInsets.symmetric(horizontal: 12),
child: RaisedButton(
elevation: 7,
color: Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
borderRadius: BorderRadius.circular(6),
),
child: loading
? CircularProgressIndicator()
: Text(
I18n.of(context).signUp,
I18n.of(context).signUp.toUpperCase(),
style: TextStyle(color: Colors.white, fontSize: 16),
),
onPressed: () => signUpAction(context),
@ -173,6 +179,7 @@ class _SignUpState extends State<SignUp> {
style: TextStyle(
decoration: TextDecoration.underline,
color: Colors.blue,
fontSize: 16,
),
),
onPressed: () => Navigator.of(context).push(

View File

@ -125,8 +125,7 @@ class _SignUpPasswordState extends State<SignUpPassword> {
),
body: ListView(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: max((MediaQuery.of(context).size.width - 600) / 2, 16)),
horizontal: max((MediaQuery.of(context).size.width - 600) / 2, 0)),
children: <Widget>[
Container(
height: 150,
@ -141,8 +140,8 @@ class _SignUpPasswordState extends State<SignUpPassword> {
),
ListTile(
leading: CircleAvatar(
backgroundColor: Colors.yellow,
child: Icon(Icons.lock),
backgroundColor: Colors.white,
child: Icon(Icons.lock, color: Theme.of(context).primaryColor),
),
title: TextField(
controller: passwordController,
@ -165,16 +164,17 @@ class _SignUpPasswordState extends State<SignUpPassword> {
SizedBox(height: 20),
Container(
height: 50,
padding: EdgeInsets.symmetric(horizontal: 12),
child: RaisedButton(
elevation: 7,
color: Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
borderRadius: BorderRadius.circular(6),
),
child: loading
? CircularProgressIndicator()
: Text(
I18n.of(context).createAccountNow,
I18n.of(context).createAccountNow.toUpperCase(),
style: TextStyle(color: Colors.white, fontSize: 16),
),
onPressed: () => loading ? null : _signUpAction(context),

View File

@ -199,12 +199,12 @@ packages:
source: hosted
version: "0.14.0+3"
http:
dependency: transitive
dependency: "direct main"
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.0+3"
version: "0.12.0+4"
http_parser:
dependency: transitive
description:

View File

@ -47,6 +47,7 @@ dependencies:
share: ^0.6.3+5
receive_sharing_intent: ^1.3.2
flutter_secure_storage: ^3.3.1+1
http: ^0.12.0+4
intl: ^0.16.0
intl_translation: ^0.17.9