mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-12-24 14:32:37 +01:00
refactor: MVC sign up view
This commit is contained in:
parent
76199418b2
commit
db19b37f72
@ -1,6 +1,7 @@
|
|||||||
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/controllers/homeserver_picker_controller.dart';
|
import 'package:fluffychat/controllers/homeserver_picker_controller.dart';
|
||||||
|
import 'package:fluffychat/controllers/sign_up_controller.dart';
|
||||||
import 'package:fluffychat/views/widgets/matrix.dart';
|
import 'package:fluffychat/views/widgets/matrix.dart';
|
||||||
import 'package:fluffychat/views/archive.dart';
|
import 'package:fluffychat/views/archive.dart';
|
||||||
import 'package:fluffychat/views/chat.dart';
|
import 'package:fluffychat/views/chat.dart';
|
||||||
@ -24,7 +25,6 @@ import 'package:fluffychat/views/settings_ignore_list.dart';
|
|||||||
import 'package:fluffychat/views/settings_multiple_emotes.dart';
|
import 'package:fluffychat/views/settings_multiple_emotes.dart';
|
||||||
import 'package:fluffychat/views/settings_notifications.dart';
|
import 'package:fluffychat/views/settings_notifications.dart';
|
||||||
import 'package:fluffychat/views/settings_style.dart';
|
import 'package:fluffychat/views/settings_style.dart';
|
||||||
import 'package:fluffychat/views/sign_up.dart';
|
|
||||||
import 'package:fluffychat/views/sign_up_password.dart';
|
import 'package:fluffychat/views/sign_up_password.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
71
lib/controllers/sign_up_controller.dart
Normal file
71
lib/controllers/sign_up_controller.dart
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
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/views/sign_up_view.dart';
|
||||||
|
|
||||||
|
import 'package:fluffychat/views/widgets/matrix.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
|
|
||||||
|
class SignUp extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
SignUpController createState() => SignUpController();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SignUpController extends State<SignUp> {
|
||||||
|
final TextEditingController usernameController = TextEditingController();
|
||||||
|
String usernameError;
|
||||||
|
bool loading = false;
|
||||||
|
MatrixFile avatar;
|
||||||
|
|
||||||
|
void setAvatarAction() async {
|
||||||
|
var file =
|
||||||
|
await FilePickerCross.importFromStorage(type: FileTypeCross.image);
|
||||||
|
if (file != null) {
|
||||||
|
setState(
|
||||||
|
() => avatar = MatrixFile(
|
||||||
|
bytes: file.toUint8List(),
|
||||||
|
name: file.fileName,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetAvatarAction() => setState(() => avatar = null);
|
||||||
|
|
||||||
|
void signUpAction([_]) async {
|
||||||
|
var matrix = Matrix.of(context);
|
||||||
|
if (usernameController.text.isEmpty) {
|
||||||
|
setState(() => usernameError = L10n.of(context).pleaseChooseAUsername);
|
||||||
|
} else {
|
||||||
|
setState(() => usernameError = null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usernameController.text.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setState(() => loading = true);
|
||||||
|
|
||||||
|
final preferredUsername =
|
||||||
|
usernameController.text.toLowerCase().trim().replaceAll(' ', '-');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await matrix.client.usernameAvailable(preferredUsername);
|
||||||
|
} on MatrixException catch (exception) {
|
||||||
|
setState(() => usernameError = exception.errorMessage);
|
||||||
|
return setState(() => loading = false);
|
||||||
|
} catch (exception) {
|
||||||
|
setState(() => usernameError = exception.toString());
|
||||||
|
return setState(() => loading = false);
|
||||||
|
}
|
||||||
|
setState(() => loading = false);
|
||||||
|
await AdaptivePageLayout.of(context).pushNamed(
|
||||||
|
'/signup/password/${Uri.encodeComponent(preferredUsername)}/${Uri.encodeComponent(usernameController.text)}',
|
||||||
|
arguments: avatar,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SignUpView(this);
|
||||||
|
}
|
@ -51,11 +51,13 @@ void main() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FluffyChatApp extends StatelessWidget {
|
class FluffyChatApp extends StatelessWidget {
|
||||||
final Widget test;
|
final Widget testWidget;
|
||||||
|
final Client testClient;
|
||||||
static final GlobalKey<AdaptivePageLayoutState> _apl =
|
static final GlobalKey<AdaptivePageLayoutState> _apl =
|
||||||
GlobalKey<AdaptivePageLayoutState>();
|
GlobalKey<AdaptivePageLayoutState>();
|
||||||
|
|
||||||
const FluffyChatApp({Key key, this.test}) : super(key: key);
|
const FluffyChatApp({Key key, this.testWidget, this.testClient})
|
||||||
|
: super(key: key);
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AdaptiveTheme(
|
return AdaptiveTheme(
|
||||||
@ -75,13 +77,14 @@ class FluffyChatApp extends StatelessWidget {
|
|||||||
builder: (context) => Matrix(
|
builder: (context) => Matrix(
|
||||||
context: context,
|
context: context,
|
||||||
apl: _apl,
|
apl: _apl,
|
||||||
|
testClient: testClient,
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) => AdaptivePageLayout(
|
builder: (context) => AdaptivePageLayout(
|
||||||
key: _apl,
|
key: _apl,
|
||||||
safeAreaOnColumnView: false,
|
safeAreaOnColumnView: false,
|
||||||
onGenerateRoute: test == null
|
onGenerateRoute: testWidget == null
|
||||||
? FluffyRoutes(context).onGenerateRoute
|
? FluffyRoutes(context).onGenerateRoute
|
||||||
: (_) => ViewData(mainView: (_) => test),
|
: (_) => ViewData(mainView: (_) => testWidget),
|
||||||
dividerColor: Theme.of(context).dividerColor,
|
dividerColor: Theme.of(context).dividerColor,
|
||||||
columnWidth: FluffyThemes.columnWidth,
|
columnWidth: FluffyThemes.columnWidth,
|
||||||
dividerWidth: 1.0,
|
dividerWidth: 1.0,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
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:fluffychat/controllers/sign_up_controller.dart';
|
||||||
import 'package:file_picker_cross/file_picker_cross.dart';
|
|
||||||
import 'package:fluffychat/views/widgets/fluffy_banner.dart';
|
import 'package:fluffychat/views/widgets/fluffy_banner.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/views/widgets/matrix.dart';
|
import 'package:fluffychat/views/widgets/matrix.dart';
|
||||||
@ -9,61 +8,13 @@ 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';
|
||||||
|
|
||||||
class SignUp extends StatefulWidget {
|
class SignUpView extends StatelessWidget {
|
||||||
@override
|
final SignUpController controller;
|
||||||
_SignUpState createState() => _SignUpState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SignUpState extends State<SignUp> {
|
const SignUpView(
|
||||||
final TextEditingController usernameController = TextEditingController();
|
this.controller, {
|
||||||
String usernameError;
|
Key key,
|
||||||
bool loading = false;
|
}) : super(key: key);
|
||||||
MatrixFile avatar;
|
|
||||||
|
|
||||||
void setAvatarAction() async {
|
|
||||||
var file =
|
|
||||||
await FilePickerCross.importFromStorage(type: FileTypeCross.image);
|
|
||||||
if (file != null) {
|
|
||||||
setState(
|
|
||||||
() => avatar = MatrixFile(
|
|
||||||
bytes: file.toUint8List(),
|
|
||||||
name: file.fileName,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void signUpAction(BuildContext context) async {
|
|
||||||
var matrix = Matrix.of(context);
|
|
||||||
if (usernameController.text.isEmpty) {
|
|
||||||
setState(() => usernameError = L10n.of(context).pleaseChooseAUsername);
|
|
||||||
} else {
|
|
||||||
setState(() => usernameError = null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usernameController.text.isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setState(() => loading = true);
|
|
||||||
|
|
||||||
final preferredUsername =
|
|
||||||
usernameController.text.toLowerCase().trim().replaceAll(' ', '-');
|
|
||||||
|
|
||||||
try {
|
|
||||||
await matrix.client.usernameAvailable(preferredUsername);
|
|
||||||
} on MatrixException catch (exception) {
|
|
||||||
setState(() => usernameError = exception.errorMessage);
|
|
||||||
return setState(() => loading = false);
|
|
||||||
} catch (exception) {
|
|
||||||
setState(() => usernameError = exception.toString());
|
|
||||||
return setState(() => loading = false);
|
|
||||||
}
|
|
||||||
setState(() => loading = false);
|
|
||||||
await AdaptivePageLayout.of(context).pushNamed(
|
|
||||||
'/signup/password/${Uri.encodeComponent(preferredUsername)}/${Uri.encodeComponent(usernameController.text)}',
|
|
||||||
arguments: avatar,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -71,7 +22,7 @@ class _SignUpState extends State<SignUp> {
|
|||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
leading: loading ? Container() : BackButton(),
|
leading: controller.loading ? Container() : BackButton(),
|
||||||
title: Text(
|
title: Text(
|
||||||
Matrix.of(context)
|
Matrix.of(context)
|
||||||
.client
|
.client
|
||||||
@ -89,15 +40,16 @@ class _SignUpState extends State<SignUp> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
readOnly: loading,
|
readOnly: controller.loading,
|
||||||
autocorrect: false,
|
autocorrect: false,
|
||||||
controller: usernameController,
|
controller: controller.usernameController,
|
||||||
onSubmitted: (s) => signUpAction(context),
|
onSubmitted: controller.signUpAction,
|
||||||
autofillHints: loading ? null : [AutofillHints.newUsername],
|
autofillHints:
|
||||||
|
controller.loading ? null : [AutofillHints.newUsername],
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: Icon(Icons.account_circle_outlined),
|
prefixIcon: Icon(Icons.account_circle_outlined),
|
||||||
hintText: L10n.of(context).username,
|
hintText: L10n.of(context).username,
|
||||||
errorText: usernameError,
|
errorText: controller.usernameError,
|
||||||
labelText: L10n.of(context).chooseAUsername,
|
labelText: L10n.of(context).chooseAUsername,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -105,30 +57,31 @@ class _SignUpState extends State<SignUp> {
|
|||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: CircleAvatar(
|
leading: CircleAvatar(
|
||||||
backgroundImage:
|
backgroundImage: controller.avatar == null
|
||||||
avatar == null ? null : MemoryImage(avatar.bytes),
|
? null
|
||||||
backgroundColor: avatar == null
|
: MemoryImage(controller.avatar.bytes),
|
||||||
|
backgroundColor: controller.avatar == null
|
||||||
? Theme.of(context).brightness == Brightness.dark
|
? Theme.of(context).brightness == Brightness.dark
|
||||||
? Color(0xff121212)
|
? Color(0xff121212)
|
||||||
: Colors.white
|
: Colors.white
|
||||||
: Theme.of(context).secondaryHeaderColor,
|
: Theme.of(context).secondaryHeaderColor,
|
||||||
child: avatar == null
|
child: controller.avatar == null
|
||||||
? Icon(Icons.camera_alt_outlined,
|
? Icon(Icons.camera_alt_outlined,
|
||||||
color: Theme.of(context).primaryColor)
|
color: Theme.of(context).primaryColor)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
trailing: avatar == null
|
trailing: controller.avatar == null
|
||||||
? null
|
? null
|
||||||
: Icon(
|
: Icon(
|
||||||
Icons.close,
|
Icons.close,
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
),
|
),
|
||||||
title: Text(avatar == null
|
title: Text(controller.avatar == null
|
||||||
? L10n.of(context).setAProfilePicture
|
? L10n.of(context).setAProfilePicture
|
||||||
: L10n.of(context).discardPicture),
|
: L10n.of(context).discardPicture),
|
||||||
onTap: avatar == null
|
onTap: controller.avatar == null
|
||||||
? setAvatarAction
|
? controller.setAvatarAction
|
||||||
: () => setState(() => avatar = null),
|
: controller.resetAvatarAction,
|
||||||
),
|
),
|
||||||
SizedBox(height: 16),
|
SizedBox(height: 16),
|
||||||
Hero(
|
Hero(
|
||||||
@ -136,8 +89,8 @@ class _SignUpState extends State<SignUp> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: loading ? null : () => signUpAction(context),
|
onPressed: controller.loading ? null : controller.signUpAction,
|
||||||
child: loading
|
child: controller.loading
|
||||||
? LinearProgressIndicator()
|
? LinearProgressIndicator()
|
||||||
: Text(
|
: Text(
|
||||||
L10n.of(context).signUp.toUpperCase(),
|
L10n.of(context).signUp.toUpperCase(),
|
@ -43,10 +43,13 @@ class Matrix extends StatefulWidget {
|
|||||||
|
|
||||||
final BuildContext context;
|
final BuildContext context;
|
||||||
|
|
||||||
|
final Client testClient;
|
||||||
|
|
||||||
Matrix({
|
Matrix({
|
||||||
this.child,
|
this.child,
|
||||||
@required this.apl,
|
@required this.apl,
|
||||||
@required this.context,
|
@required this.context,
|
||||||
|
this.testClient,
|
||||||
Key key,
|
Key key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@ -66,6 +69,8 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||||||
|
|
||||||
BackgroundPush _backgroundPush;
|
BackgroundPush _backgroundPush;
|
||||||
|
|
||||||
|
bool get testMode => widget.testClient != null;
|
||||||
|
|
||||||
Map<String, dynamic> get shareContent => _shareContent;
|
Map<String, dynamic> get shareContent => _shareContent;
|
||||||
set shareContent(Map<String, dynamic> content) {
|
set shareContent(Map<String, dynamic> content) {
|
||||||
_shareContent = content;
|
_shareContent = content;
|
||||||
@ -256,7 +261,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
client = FluffyClient();
|
client = widget.testClient ?? FluffyClient();
|
||||||
LoadingDialog.defaultTitle = L10n.of(context).loadingPleaseWait;
|
LoadingDialog.defaultTitle = L10n.of(context).loadingPleaseWait;
|
||||||
LoadingDialog.defaultBackLabel = L10n.of(context).close;
|
LoadingDialog.defaultBackLabel = L10n.of(context).close;
|
||||||
LoadingDialog.defaultOnError = (Object e) => e.toLocalizedString(context);
|
LoadingDialog.defaultOnError = (Object e) => e.toLocalizedString(context);
|
||||||
|
@ -5,7 +5,7 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('Test if the widget can be created', (WidgetTester tester) async {
|
testWidgets('Test if the widget can be created', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(FluffyChatApp(test: HomeserverPicker()));
|
await tester.pumpWidget(FluffyChatApp(testWidget: HomeserverPicker()));
|
||||||
|
|
||||||
await tester.tap(find.byType(TextField));
|
await tester.tap(find.byType(TextField));
|
||||||
await tester.tap(find.byType(ElevatedButton));
|
await tester.tap(find.byType(ElevatedButton));
|
||||||
|
9
test/sign_up_test.dart
Normal file
9
test/sign_up_test.dart
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import 'package:fluffychat/controllers/sign_up_controller.dart';
|
||||||
|
import 'package:fluffychat/main.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('Test if the widget can be created', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(FluffyChatApp(testWidget: SignUp()));
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user