@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import ' package:flutter_gen/gen_l10n/l10n.dart ' ;
import ' package:flutter_linkify/flutter_linkify.dart ' ;
import ' package:url_launcher/url_launcher.dart ' ;
import ' package:url_launcher/url_launcher_string.dart ' ;
import ' package:fluffychat/config/app_config.dart ' ;
import ' package:fluffychat/widgets/adaptive_dialog_action.dart ' ;
@ -22,159 +23,228 @@ class HomeserverPickerView extends StatelessWidget {
return LoginScaffold (
enforceMobileMode: Matrix . of ( context ) . client . isLogged ( ) ,
appBar: controller . widget . addMultiAccount
? AppBar (
centerTitle: true ,
title: Text ( L10n . of ( context ) . addAccount ) ,
)
: null ,
body: Column (
crossAxisAlignment: CrossAxisAlignment . stretch ,
children: [
/ / display a prominent banner to import session for TOR browser
/ / users . This feature is just some UX sugar as TOR users are
/ / usually forced to logout as TOR browser is non - persistent
AnimatedContainer (
height: controller . isTorBrowser ? 64 : 0 ,
duration: FluffyThemes . animationDuration ,
curve: FluffyThemes . animationCurve ,
clipBehavior: Clip . hardEdge ,
decoration: const BoxDecoration ( ) ,
child: Material (
clipBehavior: Clip . hardEdge ,
borderRadius:
const BorderRadius . vertical ( bottom: Radius . circular ( 8 ) ) ,
color: theme . colorScheme . surface ,
child: ListTile (
leading: const Icon ( Icons . vpn_key ) ,
title: Text ( L10n . of ( context ) . hydrateTor ) ,
subtitle: Text ( L10n . of ( context ) . hydrateTorLong ) ,
trailing: const Icon ( Icons . chevron_right_outlined ) ,
onTap: controller . restoreBackup ,
appBar: AppBar (
centerTitle: true ,
title: Text ( L10n . of ( context ) . addAccount ) ,
actions: [
PopupMenuButton < MoreLoginActions > (
onSelected: controller . onMoreAction ,
itemBuilder: ( _ ) = > [
PopupMenuItem (
value: MoreLoginActions . passwordLogin ,
child: Row (
mainAxisSize: MainAxisSize . min ,
children: [
const Icon ( Icons . login_outlined ) ,
const SizedBox ( width: 12 ) ,
Text ( L10n . of ( context ) . loginWithMatrixId ) ,
] ,
) ,
) ,
) ,
) ,
if ( MediaQuery . of ( context ) . size . height > 512 )
ConstrainedBox (
constraints: BoxConstraints (
maxHeight: MediaQuery . of ( context ) . size . height / 4 ,
PopupMenuItem (
value: MoreLoginActions . privacy ,
child: Row (
mainAxisSize: MainAxisSize . min ,
children: [
const Icon ( Icons . privacy_tip_outlined ) ,
const SizedBox ( width: 12 ) ,
Text ( L10n . of ( context ) . privacy ) ,
] ,
) ,
) ,
child: Image . asset (
' assets/banner_transparent.png ' ,
alignment: Alignment . center ,
repeat: ImageRepeat . repeat ,
PopupMenuItem (
value: MoreLoginActions . about ,
child: Row (
mainAxisSize: MainAxisSize . min ,
children: [
const Icon ( Icons . info_outlined ) ,
const SizedBox ( width: 12 ) ,
Text ( L10n . of ( context ) . about ) ,
] ,
) ,
) ,
) ,
Padding (
padding: const EdgeInsets . all ( 32.0 ) ,
child: TextField (
onChanged: controller . tryCheckHomeserverActionWithCooldown ,
onEditingComplete:
controller . tryCheckHomeserverActionWithoutCooldown ,
onSubmitted: controller . tryCheckHomeserverActionWithoutCooldown ,
onTap: controller . tryCheckHomeserverActionWithCooldown ,
controller: controller . homeserverController ,
autocorrect: false ,
keyboardType: TextInputType . url ,
decoration: InputDecoration (
prefixIcon: controller . isLoading
? Container (
width: 16 ,
height: 16 ,
alignment: Alignment . center ,
child: const SizedBox (
width: 16 ,
height: 16 ,
child: CircularProgressIndicator . adaptive (
strokeWidth: 2 ,
) ,
] ,
) ,
] ,
) ,
body: LayoutBuilder (
builder: ( context , constraints ) {
return SingleChildScrollView (
child: ConstrainedBox (
constraints: BoxConstraints ( minHeight: constraints . maxHeight ) ,
child: IntrinsicHeight (
child: Column (
children: [
/ / display a prominent banner to import session for TOR browser
/ / users . This feature is just some UX sugar as TOR users are
/ / usually forced to logout as TOR browser is non - persistent
AnimatedContainer (
height: controller . isTorBrowser ? 64 : 0 ,
duration: FluffyThemes . animationDuration ,
curve: FluffyThemes . animationCurve ,
clipBehavior: Clip . hardEdge ,
decoration: const BoxDecoration ( ) ,
child: Material (
clipBehavior: Clip . hardEdge ,
borderRadius: const BorderRadius . vertical (
bottom: Radius . circular ( 8 ) ,
) ,
)
: const Icon ( Icons . search_outlined ) ,
filled: false ,
border: OutlineInputBorder (
borderRadius: BorderRadius . circular ( AppConfig . borderRadius ) ,
) ,
hintText: AppConfig . defaultHomeserver ,
labelText: L10n . of ( context ) . homeserver ,
errorText: controller . error ,
suffixIcon: IconButton (
onPressed: ( ) {
showDialog (
context: context ,
builder: ( context ) = > AlertDialog . adaptive (
title: Text ( L10n . of ( context ) . whatIsAHomeserver ) ,
content: Linkify (
text: L10n . of ( context ) . homeserverDescription ,
color: theme . colorScheme . surface ,
child: ListTile (
leading: const Icon ( Icons . vpn_key ) ,
title: Text ( L10n . of ( context ) . hydrateTor ) ,
subtitle: Text ( L10n . of ( context ) . hydrateTorLong ) ,
trailing: const Icon ( Icons . chevron_right_outlined ) ,
onTap: controller . restoreBackup ,
) ,
actions: [
AdaptiveDialogAction (
onPressed: ( ) = > launchUrl (
Uri . https ( ' servers.joinmatrix.org ' ) ,
) ,
) ,
Container (
alignment: Alignment . center ,
padding: const EdgeInsets . symmetric ( horizontal: 8.0 ) ,
child: Hero (
tag: ' info-logo ' ,
child: Image . asset (
' ./assets/banner_transparent.png ' ,
fit: BoxFit . fitWidth ,
) ,
) ,
) ,
const SizedBox ( height: 32 ) ,
Padding (
padding: const EdgeInsets . symmetric ( horizontal: 32.0 ) ,
child: SelectableLinkify (
text: L10n . of ( context ) . welcomeText ,
style: TextStyle (
color: theme . colorScheme . onSecondaryContainer ,
fontWeight: FontWeight . w500 ,
) ,
textAlign: TextAlign . center ,
linkStyle: TextStyle (
color: theme . colorScheme . secondary ,
decorationColor: theme . colorScheme . secondary ,
) ,
onOpen: ( link ) = > launchUrlString ( link . url ) ,
) ,
) ,
const Spacer ( ) ,
Padding (
padding: const EdgeInsets . all ( 32.0 ) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
crossAxisAlignment: CrossAxisAlignment . stretch ,
children: [
TextField (
onChanged:
controller . tryCheckHomeserverActionWithCooldown ,
onEditingComplete: controller
. tryCheckHomeserverActionWithoutCooldown ,
onSubmitted: controller
. tryCheckHomeserverActionWithoutCooldown ,
onTap:
controller . tryCheckHomeserverActionWithCooldown ,
controller: controller . homeserverController ,
autocorrect: false ,
keyboardType: TextInputType . url ,
decoration: InputDecoration (
prefixIcon: controller . isLoading
? Container (
width: 16 ,
height: 16 ,
alignment: Alignment . center ,
child: const SizedBox (
width: 16 ,
height: 16 ,
child:
CircularProgressIndicator . adaptive (
strokeWidth: 2 ,
) ,
) ,
)
: const Icon ( Icons . search_outlined ) ,
filled: false ,
border: OutlineInputBorder (
borderRadius: BorderRadius . circular (
AppConfig . borderRadius ,
) ,
) ,
hintText: AppConfig . defaultHomeserver ,
hintStyle: TextStyle (
color: theme . colorScheme . surfaceTint ,
) ,
labelText: ' Sign in with: ' ,
errorText: controller . error ,
errorMaxLines: 4 ,
suffixIcon: IconButton (
onPressed: ( ) {
showDialog (
context: context ,
builder: ( context ) = > AlertDialog . adaptive (
title: Text (
L10n . of ( context ) . whatIsAHomeserver ,
) ,
content: Linkify (
text: L10n . of ( context )
. homeserverDescription ,
) ,
actions: [
AdaptiveDialogAction (
onPressed: ( ) = > launchUrl (
Uri . https ( ' servers.joinmatrix.org ' ) ,
) ,
child: Text (
L10n . of ( context )
. discoverHomeservers ,
) ,
) ,
AdaptiveDialogAction (
onPressed: Navigator . of ( context ) . pop ,
child: Text ( L10n . of ( context ) . close ) ,
) ,
] ,
) ,
) ;
} ,
icon: const Icon ( Icons . info_outlined ) ,
) ,
) ,
child: Text (
L10n . of ( context ) . discoverHomeservers ,
) ,
const SizedBox ( height: 32 ) ,
ElevatedButton (
style: ElevatedButton . styleFrom (
backgroundColor: theme . colorScheme . primary ,
foregroundColor: theme . colorScheme . onPrimary ,
) ,
onPressed:
controller . isLoggingIn | | controller . isLoading
? null
: controller . supportsSso
? controller . ssoLoginAction
: controller . supportsPasswordLogin
? controller . login
: null ,
child: Text ( L10n . of ( context ) . continueText ) ,
) ,
AdaptiveDialogAction (
onPressed: Navigator . of ( context ) . pop ,
child: Text ( L10n . of ( context ) . close ) ,
TextButton (
style: TextButton . styleFrom (
foregroundColor: theme . colorScheme . secondary ,
textStyle: theme . textTheme . labelMedium ,
) ,
onPressed:
controller . isLoggingIn | | controller . isLoading
? null
: controller . restoreBackup ,
child: Text ( L10n . of ( context ) . hydrate ) ,
) ,
] ,
) ,
) ;
} ,
icon: const Icon ( Icons . info_outlined ) ,
) ,
] ,
) ,
) ,
) ,
) ,
if ( MediaQuery . of ( context ) . size . height > 512 ) const Spacer ( ) ,
ListView (
shrinkWrap: true ,
padding: const EdgeInsets . symmetric (
horizontal: 32.0 ,
vertical: 32.0 ,
) ,
children: [
TextButton (
style: TextButton . styleFrom (
textStyle: theme . textTheme . labelMedium ,
foregroundColor: theme . colorScheme . secondary ,
) ,
onPressed: controller . isLoggingIn | | controller . isLoading
? null
: controller . restoreBackup ,
child: Text ( L10n . of ( context ) . hydrate ) ,
) ,
if ( controller . supportsPasswordLogin & & controller . supportsSso )
TextButton (
style: TextButton . styleFrom (
foregroundColor: theme . colorScheme . secondary ,
textStyle: theme . textTheme . labelMedium ,
) ,
onPressed: controller . isLoggingIn | | controller . isLoading
? null
: controller . login ,
child: Text ( L10n . of ( context ) . loginWithMatrixId ) ,
) ,
const SizedBox ( height: 8.0 ) ,
if ( controller . supportsPasswordLogin | | controller . supportsSso )
ElevatedButton (
style: ElevatedButton . styleFrom (
backgroundColor: theme . colorScheme . primary ,
foregroundColor: theme . colorScheme . onPrimary ,
) ,
onPressed: controller . isLoggingIn | | controller . isLoading
? null
: controller . supportsSso
? controller . ssoLoginAction
: controller . login ,
child: Text ( L10n . of ( context ) . next ) ,
) ,
] ,
) ,
] ,
) ;
} ,
) ,
) ;
}