mirror of
				https://gitlab.com/famedly/fluffychat.git
				synced 2025-11-04 06:17:26 +01:00 
			
		
		
		
	feat: Nicer registration form
This commit is contained in:
		
							parent
							
								
									bc78647fb6
								
							
						
					
					
						commit
						b48cf2ecdc
					
				@ -220,7 +220,10 @@ class HomeserverPickerController extends State<HomeserverPicker> {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void signUpAction() => VRouter.of(context).to('signup');
 | 
			
		||||
  void signUpAction() => VRouter.of(context).to(
 | 
			
		||||
        'signup',
 | 
			
		||||
        queryParameters: {'domain': domain},
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
 | 
			
		||||
import 'package:vrouter/vrouter.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:fluffychat/pages/views/signup_view.dart';
 | 
			
		||||
import 'package:fluffychat/utils/platform_infos.dart';
 | 
			
		||||
@ -17,29 +18,78 @@ class SignupPage extends StatefulWidget {
 | 
			
		||||
class SignupPageController extends State<SignupPage> {
 | 
			
		||||
  final TextEditingController usernameController = TextEditingController();
 | 
			
		||||
  final TextEditingController passwordController = TextEditingController();
 | 
			
		||||
  String usernameError;
 | 
			
		||||
  String passwordError;
 | 
			
		||||
  final TextEditingController passwordController2 = TextEditingController();
 | 
			
		||||
  final TextEditingController emailController = TextEditingController();
 | 
			
		||||
  String error;
 | 
			
		||||
  bool loading = false;
 | 
			
		||||
  bool showPassword = true;
 | 
			
		||||
  bool showPassword = false;
 | 
			
		||||
 | 
			
		||||
  void toggleShowPassword() => setState(() => showPassword = !showPassword);
 | 
			
		||||
 | 
			
		||||
  String get domain => VRouter.of(context).queryParameters['domain'];
 | 
			
		||||
 | 
			
		||||
  final GlobalKey<FormState> formKey = GlobalKey<FormState>();
 | 
			
		||||
 | 
			
		||||
  String usernameTextFieldValidator(String value) {
 | 
			
		||||
    usernameController.text =
 | 
			
		||||
        usernameController.text.trim().toLowerCase().replaceAll(' ', '_');
 | 
			
		||||
    if (value.isEmpty) {
 | 
			
		||||
      return L10n.of(context).pleaseChooseAUsername;
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String password1TextFieldValidator(String value) {
 | 
			
		||||
    const minLength = 8;
 | 
			
		||||
    if (value.isEmpty) {
 | 
			
		||||
      return L10n.of(context).chooseAStrongPassword;
 | 
			
		||||
    }
 | 
			
		||||
    if (value.length < minLength) {
 | 
			
		||||
      return 'Please choose at least $minLength characters.';
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String password2TextFieldValidator(String value) {
 | 
			
		||||
    if (value.isEmpty) {
 | 
			
		||||
      return L10n.of(context).chooseAStrongPassword;
 | 
			
		||||
    }
 | 
			
		||||
    if (value != passwordController.text) {
 | 
			
		||||
      return 'Passwords do not match!';
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String emailTextFieldValidator(String value) {
 | 
			
		||||
    if (value.isNotEmpty && !value.contains('@')) {
 | 
			
		||||
      return 'Please enter a valid email address.';
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void signup([_]) async {
 | 
			
		||||
    usernameError = passwordError = null;
 | 
			
		||||
    setState(() {
 | 
			
		||||
      error = null;
 | 
			
		||||
    });
 | 
			
		||||
    if (!formKey.currentState.validate()) return;
 | 
			
		||||
 | 
			
		||||
    if (usernameController.text.isEmpty) {
 | 
			
		||||
      return setState(
 | 
			
		||||
          () => usernameError = L10n.of(context).pleaseChooseAUsername);
 | 
			
		||||
    }
 | 
			
		||||
    if (passwordController.text.isEmpty) {
 | 
			
		||||
      return setState(
 | 
			
		||||
          () => passwordError = L10n.of(context).chooseAStrongPassword);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setState(() => loading = true);
 | 
			
		||||
    setState(() {
 | 
			
		||||
      loading = true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      final client = Matrix.of(context).getLoginClient();
 | 
			
		||||
      final email = emailController.text;
 | 
			
		||||
      if (email.isNotEmpty) {
 | 
			
		||||
        Matrix.of(context).currentClientSecret =
 | 
			
		||||
            DateTime.now().millisecondsSinceEpoch.toString();
 | 
			
		||||
        Matrix.of(context).currentThreepidCreds =
 | 
			
		||||
            await client.requestTokenToRegisterEmail(
 | 
			
		||||
          Matrix.of(context).currentClientSecret,
 | 
			
		||||
          email,
 | 
			
		||||
          0,
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
      await client.uiaRequestBackground(
 | 
			
		||||
        (auth) => client.register(
 | 
			
		||||
          username: usernameController.text,
 | 
			
		||||
@ -49,7 +99,7 @@ class SignupPageController extends State<SignupPage> {
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      passwordError = (e as Object).toLocalizedString(context);
 | 
			
		||||
      error = (e as Object).toLocalizedString(context);
 | 
			
		||||
    } finally {
 | 
			
		||||
      setState(() => loading = false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:fluffychat/widgets/layouts/one_page_card.dart';
 | 
			
		||||
import 'package:fluffychat/widgets/matrix.dart';
 | 
			
		||||
import '../signup.dart';
 | 
			
		||||
 | 
			
		||||
class SignupPageView extends StatelessWidget {
 | 
			
		||||
@ -17,76 +16,116 @@ class SignupPageView extends StatelessWidget {
 | 
			
		||||
        appBar: AppBar(
 | 
			
		||||
          title: Text(L10n.of(context).signUp),
 | 
			
		||||
        ),
 | 
			
		||||
        body: ListView(
 | 
			
		||||
          children: [
 | 
			
		||||
            ListTile(
 | 
			
		||||
              title: Text(L10n.of(context).pleaseChooseAUsername),
 | 
			
		||||
              subtitle: Text(L10n.of(context).newUsernameDescription),
 | 
			
		||||
            ),
 | 
			
		||||
            Padding(
 | 
			
		||||
              padding: const EdgeInsets.all(12.0),
 | 
			
		||||
              child: TextField(
 | 
			
		||||
                readOnly: controller.loading,
 | 
			
		||||
                autocorrect: false,
 | 
			
		||||
                autofocus: true,
 | 
			
		||||
                controller: controller.usernameController,
 | 
			
		||||
                autofillHints:
 | 
			
		||||
                    controller.loading ? null : [AutofillHints.username],
 | 
			
		||||
                decoration: InputDecoration(
 | 
			
		||||
                    prefixIcon: const Icon(Icons.account_box_outlined),
 | 
			
		||||
                    hintText: L10n.of(context).username,
 | 
			
		||||
                    errorText: controller.usernameError,
 | 
			
		||||
                    labelText: L10n.of(context).username,
 | 
			
		||||
                    prefixText: '@',
 | 
			
		||||
                    suffixText:
 | 
			
		||||
                        ':${Matrix.of(context).getLoginClient().homeserver.host}'),
 | 
			
		||||
        body: Form(
 | 
			
		||||
          key: controller.formKey,
 | 
			
		||||
          child: ListView(
 | 
			
		||||
            children: [
 | 
			
		||||
              Padding(
 | 
			
		||||
                padding: const EdgeInsets.all(12.0),
 | 
			
		||||
                child: TextFormField(
 | 
			
		||||
                  readOnly: controller.loading,
 | 
			
		||||
                  autocorrect: false,
 | 
			
		||||
                  controller: controller.usernameController,
 | 
			
		||||
                  autofillHints:
 | 
			
		||||
                      controller.loading ? null : [AutofillHints.username],
 | 
			
		||||
                  validator: controller.usernameTextFieldValidator,
 | 
			
		||||
                  decoration: InputDecoration(
 | 
			
		||||
                      prefixIcon: const Icon(Icons.account_circle_outlined),
 | 
			
		||||
                      hintText: L10n.of(context).username,
 | 
			
		||||
                      labelText: L10n.of(context).username,
 | 
			
		||||
                      prefixText: '@',
 | 
			
		||||
                      prefixStyle: const TextStyle(fontWeight: FontWeight.bold),
 | 
			
		||||
                      suffixStyle: const TextStyle(fontWeight: FontWeight.w200),
 | 
			
		||||
                      suffixText: ':${controller.domain}'),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
            const Divider(),
 | 
			
		||||
            ListTile(
 | 
			
		||||
              title: Text(L10n.of(context).chooseAStrongPassword),
 | 
			
		||||
              subtitle: Text(L10n.of(context).newPasswordDescription),
 | 
			
		||||
            ),
 | 
			
		||||
            Padding(
 | 
			
		||||
              padding: const EdgeInsets.all(12.0),
 | 
			
		||||
              child: TextField(
 | 
			
		||||
                readOnly: controller.loading,
 | 
			
		||||
                autocorrect: false,
 | 
			
		||||
                autofillHints:
 | 
			
		||||
                    controller.loading ? null : [AutofillHints.password],
 | 
			
		||||
                controller: controller.passwordController,
 | 
			
		||||
                obscureText: !controller.showPassword,
 | 
			
		||||
                onSubmitted: controller.signup,
 | 
			
		||||
                decoration: InputDecoration(
 | 
			
		||||
                  prefixIcon: const Icon(Icons.lock_outlined),
 | 
			
		||||
                  hintText: '****',
 | 
			
		||||
                  errorText: controller.passwordError,
 | 
			
		||||
                  suffixIcon: IconButton(
 | 
			
		||||
                    tooltip: L10n.of(context).showPassword,
 | 
			
		||||
                    icon: Icon(controller.showPassword
 | 
			
		||||
                        ? Icons.visibility_off_outlined
 | 
			
		||||
                        : Icons.visibility_outlined),
 | 
			
		||||
                    onPressed: controller.toggleShowPassword,
 | 
			
		||||
              Padding(
 | 
			
		||||
                padding: const EdgeInsets.all(12.0),
 | 
			
		||||
                child: TextFormField(
 | 
			
		||||
                  readOnly: controller.loading,
 | 
			
		||||
                  autocorrect: false,
 | 
			
		||||
                  autofillHints:
 | 
			
		||||
                      controller.loading ? null : [AutofillHints.password],
 | 
			
		||||
                  controller: controller.passwordController,
 | 
			
		||||
                  obscureText: !controller.showPassword,
 | 
			
		||||
                  validator: controller.password1TextFieldValidator,
 | 
			
		||||
                  decoration: InputDecoration(
 | 
			
		||||
                    prefixIcon: const Icon(Icons.vpn_key_outlined),
 | 
			
		||||
                    hintText: '****',
 | 
			
		||||
                    suffixIcon: IconButton(
 | 
			
		||||
                      tooltip: L10n.of(context).showPassword,
 | 
			
		||||
                      icon: Icon(controller.showPassword
 | 
			
		||||
                          ? Icons.visibility_off_outlined
 | 
			
		||||
                          : Icons.visibility_outlined),
 | 
			
		||||
                      onPressed: controller.toggleShowPassword,
 | 
			
		||||
                    ),
 | 
			
		||||
                    labelText: L10n.of(context).password,
 | 
			
		||||
                  ),
 | 
			
		||||
                  labelText: L10n.of(context).password,
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
            const Divider(),
 | 
			
		||||
            const SizedBox(height: 12),
 | 
			
		||||
            Hero(
 | 
			
		||||
              tag: 'loginButton',
 | 
			
		||||
              child: Padding(
 | 
			
		||||
                padding: const EdgeInsets.symmetric(horizontal: 12),
 | 
			
		||||
                child: ElevatedButton(
 | 
			
		||||
                  onPressed: controller.loading ? null : controller.signup,
 | 
			
		||||
                  child: controller.loading
 | 
			
		||||
                      ? const LinearProgressIndicator()
 | 
			
		||||
                      : Text(L10n.of(context).signUp),
 | 
			
		||||
              Padding(
 | 
			
		||||
                padding: const EdgeInsets.all(12.0),
 | 
			
		||||
                child: TextFormField(
 | 
			
		||||
                  readOnly: controller.loading,
 | 
			
		||||
                  autocorrect: false,
 | 
			
		||||
                  autofillHints:
 | 
			
		||||
                      controller.loading ? null : [AutofillHints.password],
 | 
			
		||||
                  controller: controller.passwordController2,
 | 
			
		||||
                  obscureText: true,
 | 
			
		||||
                  validator: controller.password2TextFieldValidator,
 | 
			
		||||
                  decoration: const InputDecoration(
 | 
			
		||||
                    prefixIcon: Icon(Icons.repeat_outlined),
 | 
			
		||||
                    hintText: '****',
 | 
			
		||||
                    labelText: 'Repeat password',
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          ],
 | 
			
		||||
              Padding(
 | 
			
		||||
                padding: const EdgeInsets.all(12.0),
 | 
			
		||||
                child: TextFormField(
 | 
			
		||||
                  readOnly: controller.loading,
 | 
			
		||||
                  autocorrect: false,
 | 
			
		||||
                  controller: controller.emailController,
 | 
			
		||||
                  keyboardType: TextInputType.emailAddress,
 | 
			
		||||
                  autofillHints:
 | 
			
		||||
                      controller.loading ? null : [AutofillHints.username],
 | 
			
		||||
                  validator: controller.emailTextFieldValidator,
 | 
			
		||||
                  decoration: InputDecoration(
 | 
			
		||||
                    prefixIcon: const Icon(Icons.mail_outlined),
 | 
			
		||||
                    labelText: L10n.of(context).addEmail,
 | 
			
		||||
                    hintText: 'email@example.abc',
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
              const Divider(),
 | 
			
		||||
              const SizedBox(height: 12),
 | 
			
		||||
              if (controller.error != null) ...[
 | 
			
		||||
                Padding(
 | 
			
		||||
                  padding: const EdgeInsets.symmetric(horizontal: 12),
 | 
			
		||||
                  child: Text(
 | 
			
		||||
                    controller.error,
 | 
			
		||||
                    style: const TextStyle(color: Colors.red),
 | 
			
		||||
                    textAlign: TextAlign.center,
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
                const SizedBox(height: 12),
 | 
			
		||||
                const Divider(),
 | 
			
		||||
                const SizedBox(height: 12),
 | 
			
		||||
              ],
 | 
			
		||||
              Hero(
 | 
			
		||||
                tag: 'loginButton',
 | 
			
		||||
                child: Padding(
 | 
			
		||||
                  padding: const EdgeInsets.symmetric(horizontal: 12),
 | 
			
		||||
                  child: ElevatedButton(
 | 
			
		||||
                    onPressed: controller.loading ? null : controller.signup,
 | 
			
		||||
                    child: controller.loading
 | 
			
		||||
                        ? const LinearProgressIndicator()
 | 
			
		||||
                        : Text(L10n.of(context).signUp),
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,8 @@ import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
 | 
			
		||||
import 'package:matrix/matrix.dart';
 | 
			
		||||
 | 
			
		||||
import 'uia_request_manager.dart';
 | 
			
		||||
 | 
			
		||||
extension LocalizedExceptionExtension on Object {
 | 
			
		||||
  String toLocalizedString(BuildContext context) {
 | 
			
		||||
    if (this is MatrixException) {
 | 
			
		||||
@ -48,6 +50,7 @@ extension LocalizedExceptionExtension on Object {
 | 
			
		||||
    if (this is MatrixConnectionException || this is SocketException) {
 | 
			
		||||
      return L10n.of(context).noConnectionToTheServer;
 | 
			
		||||
    }
 | 
			
		||||
    if (this is UiaException) return toString();
 | 
			
		||||
    Logs().w('Something went wrong: ', this);
 | 
			
		||||
    return L10n.of(context).oopsSomethingWentWrong;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,24 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'dart:async';
 | 
			
		||||
 | 
			
		||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
 | 
			
		||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
 | 
			
		||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
 | 
			
		||||
import 'package:matrix/matrix.dart';
 | 
			
		||||
import 'package:url_launcher/url_launcher.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:fluffychat/utils/platform_infos.dart';
 | 
			
		||||
import 'package:fluffychat/widgets/matrix.dart';
 | 
			
		||||
 | 
			
		||||
extension UiaRequestManager on MatrixState {
 | 
			
		||||
  Future uiaRequestHandler(UiaRequest uiaRequest) async {
 | 
			
		||||
    try {
 | 
			
		||||
      if (uiaRequest.state != UiaRequestState.waitForUser ||
 | 
			
		||||
          uiaRequest.nextStages.isEmpty) return;
 | 
			
		||||
          uiaRequest.nextStages.isEmpty) {
 | 
			
		||||
        Logs().d('Uia Request Stage: ${uiaRequest.state}');
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      final stage = uiaRequest.nextStages.first;
 | 
			
		||||
      Logs().d('Uia Request Stage: $stage');
 | 
			
		||||
      switch (stage) {
 | 
			
		||||
        case AuthenticationTypes.password:
 | 
			
		||||
          final input = cachedPassword ??
 | 
			
		||||
@ -31,7 +37,9 @@ extension UiaRequestManager on MatrixState {
 | 
			
		||||
                ],
 | 
			
		||||
              ))
 | 
			
		||||
                  ?.single;
 | 
			
		||||
          if (input?.isEmpty ?? true) return;
 | 
			
		||||
          if (input?.isEmpty ?? true) {
 | 
			
		||||
            return uiaRequest.cancel();
 | 
			
		||||
          }
 | 
			
		||||
          return uiaRequest.completeStage(
 | 
			
		||||
            AuthenticationPassword(
 | 
			
		||||
              session: uiaRequest.session,
 | 
			
		||||
@ -40,35 +48,18 @@ extension UiaRequestManager on MatrixState {
 | 
			
		||||
            ),
 | 
			
		||||
          );
 | 
			
		||||
        case AuthenticationTypes.emailIdentity:
 | 
			
		||||
          final emailInput = await showTextInputDialog(
 | 
			
		||||
            context: navigatorContext,
 | 
			
		||||
            message: L10n.of(context).serverRequiresEmail,
 | 
			
		||||
            okLabel: L10n.of(context).next,
 | 
			
		||||
            cancelLabel: L10n.of(context).cancel,
 | 
			
		||||
            textFields: [
 | 
			
		||||
              DialogTextField(
 | 
			
		||||
                hintText: L10n.of(context).addEmail,
 | 
			
		||||
                keyboardType: TextInputType.emailAddress,
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          );
 | 
			
		||||
          if (emailInput == null || emailInput.isEmpty) {
 | 
			
		||||
            return uiaRequest
 | 
			
		||||
                .cancel(Exception(L10n.of(context).serverRequiresEmail));
 | 
			
		||||
          if (currentThreepidCreds == null || currentClientSecret == null) {
 | 
			
		||||
            return uiaRequest.cancel(
 | 
			
		||||
              UiaException(L10n.of(widget.context).serverRequiresEmail),
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
          final clientSecret = DateTime.now().millisecondsSinceEpoch.toString();
 | 
			
		||||
          final currentThreepidCreds = await client.requestTokenToRegisterEmail(
 | 
			
		||||
            clientSecret,
 | 
			
		||||
            emailInput.single,
 | 
			
		||||
            0,
 | 
			
		||||
          );
 | 
			
		||||
          final auth = AuthenticationThreePidCreds(
 | 
			
		||||
            session: uiaRequest.session,
 | 
			
		||||
            type: AuthenticationTypes.emailIdentity,
 | 
			
		||||
            threepidCreds: [
 | 
			
		||||
              ThreepidCreds(
 | 
			
		||||
                sid: currentThreepidCreds.sid,
 | 
			
		||||
                clientSecret: clientSecret,
 | 
			
		||||
                clientSecret: currentClientSecret,
 | 
			
		||||
              ),
 | 
			
		||||
            ],
 | 
			
		||||
          );
 | 
			
		||||
@ -92,24 +83,41 @@ extension UiaRequestManager on MatrixState {
 | 
			
		||||
            ),
 | 
			
		||||
          );
 | 
			
		||||
        default:
 | 
			
		||||
          await launch(
 | 
			
		||||
            client.homeserver.toString() +
 | 
			
		||||
                '/_matrix/client/r0/auth/$stage/fallback/web?session=${uiaRequest.session}',
 | 
			
		||||
          );
 | 
			
		||||
          if (OkCancelResult.ok ==
 | 
			
		||||
              await showOkCancelAlertDialog(
 | 
			
		||||
                useRootNavigator: false,
 | 
			
		||||
                message: L10n.of(context).pleaseFollowInstructionsOnWeb,
 | 
			
		||||
                context: navigatorContext,
 | 
			
		||||
                okLabel: L10n.of(context).next,
 | 
			
		||||
                cancelLabel: L10n.of(context).cancel,
 | 
			
		||||
              )) {
 | 
			
		||||
            return uiaRequest.completeStage(
 | 
			
		||||
              AuthenticationData(session: uiaRequest.session),
 | 
			
		||||
          final url = Uri.parse(client.homeserver.toString() +
 | 
			
		||||
              '/_matrix/client/r0/auth/$stage/fallback/web?session=${uiaRequest.session}');
 | 
			
		||||
          if (PlatformInfos.isMobile) {
 | 
			
		||||
            final browser = UiaFallbackBrowser();
 | 
			
		||||
            browser.addMenuItem(
 | 
			
		||||
              ChromeSafariBrowserMenuItem(
 | 
			
		||||
                action: (_, __) {
 | 
			
		||||
                  uiaRequest.cancel();
 | 
			
		||||
                },
 | 
			
		||||
                label: L10n.of(context).cancel,
 | 
			
		||||
                id: 0,
 | 
			
		||||
              ),
 | 
			
		||||
            );
 | 
			
		||||
            await browser.open(url: url);
 | 
			
		||||
            await browser.whenClosed.stream.first;
 | 
			
		||||
          } else {
 | 
			
		||||
            return uiaRequest.cancel();
 | 
			
		||||
            launch(url.toString());
 | 
			
		||||
            if (OkCancelResult.ok ==
 | 
			
		||||
                await showOkCancelAlertDialog(
 | 
			
		||||
                  useRootNavigator: false,
 | 
			
		||||
                  message: L10n.of(context).pleaseFollowInstructionsOnWeb,
 | 
			
		||||
                  context: navigatorContext,
 | 
			
		||||
                  okLabel: L10n.of(context).next,
 | 
			
		||||
                  cancelLabel: L10n.of(context).cancel,
 | 
			
		||||
                )) {
 | 
			
		||||
              return uiaRequest.completeStage(
 | 
			
		||||
                AuthenticationData(session: uiaRequest.session),
 | 
			
		||||
              );
 | 
			
		||||
            } else {
 | 
			
		||||
              return uiaRequest.cancel();
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          await uiaRequest.completeStage(
 | 
			
		||||
            AuthenticationData(session: uiaRequest.session),
 | 
			
		||||
          );
 | 
			
		||||
      }
 | 
			
		||||
    } catch (e, s) {
 | 
			
		||||
      Logs().e('Error while background UIA', e, s);
 | 
			
		||||
@ -117,3 +125,19 @@ extension UiaRequestManager on MatrixState {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class UiaException implements Exception {
 | 
			
		||||
  final String reason;
 | 
			
		||||
 | 
			
		||||
  UiaException(this.reason);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  String toString() => reason;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class UiaFallbackBrowser extends ChromeSafariBrowser {
 | 
			
		||||
  final StreamController<bool> whenClosed = StreamController<bool>.broadcast();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  onClosed() => whenClosed.add(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -75,6 +75,9 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
 | 
			
		||||
  int getClientIndexByMatrixId(String matrixId) =>
 | 
			
		||||
      widget.clients.indexWhere((client) => client.userID == matrixId);
 | 
			
		||||
 | 
			
		||||
  String currentClientSecret;
 | 
			
		||||
  RequestTokenResponse currentThreepidCreds;
 | 
			
		||||
 | 
			
		||||
  int get _safeActiveClient {
 | 
			
		||||
    if (widget.clients.isEmpty) {
 | 
			
		||||
      widget.clients.add(getLoginClient());
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user