Login signup fixes (#1277)

* made button same height when loading, added timeout to language settings / avatar page

* fix: make button click always work, shrink inputs and add more space between logo and page content

* fix: don't open keyboard automatically in signup/login pages

* fix: make language dropdown hint text accurate

* feat: if a user logs in with SSO, allow them to set their username in the account setup page
pull/1544/head
ggurdin 11 months ago committed by GitHub
parent 940b65d007
commit c8bf68e4cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4647,5 +4647,6 @@
"letsStart": "Let's start", "letsStart": "Let's start",
"pleaseAgreeToTOS": "Please agree to the Terms and Conditions", "pleaseAgreeToTOS": "Please agree to the Terms and Conditions",
"pleaseEnterEmail": "Please enter a valid email address.", "pleaseEnterEmail": "Please enter a valid email address.",
"pleaseSelectALanguage": "Please select a language" "pleaseSelectALanguage": "Please select a language",
"myBaseLanguage": "My base language"
} }

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:fluffychat/pangea/constants/local.key.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/pages/sign_up/pangea_login_view.dart'; import 'package:fluffychat/pangea/pages/sign_up/pangea_login_view.dart';
import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; import 'package:fluffychat/pangea/utils/firebase_analytics.dart';
@ -146,6 +147,8 @@ class LoginController extends State<Login> {
password: passwordController.text, password: passwordController.text,
initialDeviceDisplayName: PlatformInfos.clientName, initialDeviceDisplayName: PlatformInfos.clientName,
); );
MatrixState.pangeaController.pStoreService
.save(PLocalKey.loginType, 'password');
// #Pangea // #Pangea
GoogleAnalytics.login("pangea", loginRes.userId); GoogleAnalytics.login("pangea", loginRes.userId);
// Pangea# // Pangea#

@ -86,8 +86,8 @@ class LoginView extends StatelessWidget {
child: TextField( child: TextField(
readOnly: controller.loading, readOnly: controller.loading,
autocorrect: false, autocorrect: false,
autofocus: true,
// #Pangea // #Pangea
// autofocus: true,
// onChanged: controller.checkWellKnownWithCoolDown, // onChanged: controller.checkWellKnownWithCoolDown,
// Pangea# // Pangea#
controller: controller.usernameController, controller: controller.usernameController,

@ -9,4 +9,5 @@ class PLocalKey {
static const String justInputtedCode = 'justInputtedCode'; static const String justInputtedCode = 'justInputtedCode';
static const String availableSubscriptionInfo = 'availableSubscriptionInfo'; static const String availableSubscriptionInfo = 'availableSubscriptionInfo';
static const String showedUpdateDialog = 'showedUpdateDialog'; static const String showedUpdateDialog = 'showedUpdateDialog';
static const String loginType = 'loginType';
} }

@ -29,7 +29,8 @@ class LanguageController {
_userL2Code != LanguageKeys.unknownLanguage; _userL2Code != LanguageKeys.unknownLanguage;
LanguageModel? get systemLanguage { LanguageModel? get systemLanguage {
final String systemLang = Platform.localeName.split('-').first; if (Platform.localeName.length < 2) return null;
final String systemLang = Platform.localeName.substring(0, 2);
return PangeaLanguage.byLangCode(systemLang); return PangeaLanguage.byLangCode(systemLang);
} }

@ -89,21 +89,15 @@ class PangeaSsoButtonState extends State<PangeaSsoButton> {
depressed: _loading, depressed: _loading,
error: _error, error: _error,
loading: _loading, loading: _loading,
title: Row( title: widget.title,
mainAxisAlignment: MainAxisAlignment.center, icon: SvgPicture.asset(
children: [ widget.provider.asset,
SvgPicture.asset( height: 20,
widget.provider.asset, width: 20,
height: 20, colorFilter: ColorFilter.mode(
width: 20, Theme.of(context).colorScheme.onPrimary,
colorFilter: ColorFilter.mode( BlendMode.srcIn,
Theme.of(context).colorScheme.onPrimary, ),
BlendMode.srcIn,
),
),
const SizedBox(width: 10),
Text(widget.title),
],
), ),
onPressed: _runSSOLogin, onPressed: _runSSOLogin,
); );

@ -3,7 +3,9 @@ import 'package:fluffychat/pangea/widgets/pressable_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class FullWidthButton extends StatefulWidget { class FullWidthButton extends StatefulWidget {
final Widget title; final String title;
final Widget? icon;
final void Function()? onPressed; final void Function()? onPressed;
final bool depressed; final bool depressed;
final String? error; final String? error;
@ -13,6 +15,7 @@ class FullWidthButton extends StatefulWidget {
const FullWidthButton({ const FullWidthButton({
required this.title, required this.title,
required this.onPressed, required this.onPressed,
this.icon,
this.depressed = false, this.depressed = false,
this.error, this.error,
this.loading = false, this.loading = false,
@ -31,7 +34,7 @@ class FullWidthButtonState extends State<FullWidthButton> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: EdgeInsets.fromLTRB(4, 4, 4, widget.error == null ? 4 : 0), padding: EdgeInsets.fromLTRB(6, 6, 6, widget.error == null ? 6 : 0),
child: AnimatedOpacity( child: AnimatedOpacity(
duration: FluffyThemes.animationDuration, duration: FluffyThemes.animationDuration,
opacity: widget.enabled ? 1 : 0.5, opacity: widget.enabled ? 1 : 0.5,
@ -40,40 +43,44 @@ class FullWidthButtonState extends State<FullWidthButton> {
onPressed: widget.onPressed, onPressed: widget.onPressed,
borderRadius: BorderRadius.circular(36), borderRadius: BorderRadius.circular(36),
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
child: Builder( child: Container(
builder: (context) { // internal padding
return ElevatedButton( padding: const EdgeInsets.symmetric(horizontal: 16),
style: ElevatedButton.styleFrom( height: 50,
backgroundColor: widget.enabled decoration: BoxDecoration(
? Theme.of(context).colorScheme.primary color: widget.enabled
: Theme.of(context).disabledColor, ? Theme.of(context).colorScheme.primary
foregroundColor: Theme.of(context).colorScheme.onPrimary, : Theme.of(context).disabledColor,
disabledForegroundColor: borderRadius: BorderRadius.circular(36),
Theme.of(context).colorScheme.onPrimary, ),
textStyle: const TextStyle(fontSize: 18), child: Row(
shape: RoundedRectangleBorder( mainAxisAlignment: MainAxisAlignment.center,
borderRadius: BorderRadius.circular(36), children: [
), widget.loading
), ? const Expanded(
onPressed: widget.enabled child: SizedBox(
? () => ButtonPressedNotification().dispatch(context) height: 18,
: null, child: Center(child: LinearProgressIndicator()),
child: Row( ),
mainAxisAlignment: MainAxisAlignment.center, )
children: [ : Row(
widget.loading mainAxisAlignment: MainAxisAlignment.center,
? const Expanded( children: [
child: SizedBox( if (widget.icon != null) widget.icon!,
height: 18, if (widget.icon != null)
child: const SizedBox(width: 10),
Center(child: LinearProgressIndicator()), Text(
widget.title,
style: TextStyle(
color:
Theme.of(context).colorScheme.onPrimary,
fontSize: 16,
), ),
) ),
: widget.title, ],
], ),
), ],
); ),
},
), ),
), ),
), ),
@ -104,7 +111,6 @@ class FullWidthButtonState extends State<FullWidthButton> {
class FullWidthTextField extends StatelessWidget { class FullWidthTextField extends StatelessWidget {
final String hintText; final String hintText;
final bool autocorrect; final bool autocorrect;
final bool autofocus;
final bool obscureText; final bool obscureText;
final TextInputAction? textInputAction; final TextInputAction? textInputAction;
final TextInputType? keyboardType; final TextInputType? keyboardType;
@ -115,7 +121,6 @@ class FullWidthTextField extends StatelessWidget {
const FullWidthTextField({ const FullWidthTextField({
required this.hintText, required this.hintText,
this.autocorrect = false, this.autocorrect = false,
this.autofocus = false,
this.obscureText = false, this.obscureText = false,
this.textInputAction, this.textInputAction,
this.keyboardType, this.keyboardType,
@ -128,11 +133,10 @@ class FullWidthTextField extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.all(4.0), padding: const EdgeInsets.all(6.0),
child: TextFormField( child: TextFormField(
obscureText: obscureText, obscureText: obscureText,
autocorrect: autocorrect, autocorrect: autocorrect,
autofocus: autofocus,
textInputAction: textInputAction, textInputAction: textInputAction,
keyboardType: keyboardType, keyboardType: keyboardType,
decoration: InputDecoration( decoration: InputDecoration(

@ -12,11 +12,11 @@ class LoginOrSignupView extends StatelessWidget {
return PangeaLoginScaffold( return PangeaLoginScaffold(
children: [ children: [
FullWidthButton( FullWidthButton(
title: Text(L10n.of(context).createAnAccount), title: L10n.of(context).createAnAccount,
onPressed: () => context.go('/home/signup'), onPressed: () => context.go('/home/signup'),
), ),
FullWidthButton( FullWidthButton(
title: Text(L10n.of(context).signIn), title: L10n.of(context).signIn,
onPressed: () => context.go('/home/login'), onPressed: () => context.go('/home/login'),
), ),
], ],

@ -32,14 +32,14 @@ class PangeaLoginScaffold extends StatelessWidget {
child: Center( child: Center(
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints( constraints: const BoxConstraints(
maxWidth: 450, maxWidth: 300,
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Container( Container(
width: 200, width: 175,
height: 200, height: 175,
decoration: const BoxDecoration( decoration: const BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: Colors.transparent, color: Colors.transparent,
@ -56,13 +56,13 @@ class PangeaLoginScaffold extends StatelessWidget {
), ),
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 24),
if (showAppName) if (showAppName)
Text( Text(
AppConfig.applicationName, AppConfig.applicationName,
style: Theme.of(context).textTheme.displaySmall, style: Theme.of(context).textTheme.displaySmall,
), ),
const SizedBox(height: 16), if (showAppName) const SizedBox(height: 12),
...children, ...children,
], ],
), ),

@ -19,7 +19,6 @@ class PangeaLoginView extends StatelessWidget {
children: [ children: [
FullWidthTextField( FullWidthTextField(
hintText: L10n.of(context).username, hintText: L10n.of(context).username,
autofocus: true,
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
@ -44,16 +43,10 @@ class PangeaLoginView extends StatelessWidget {
errorText: controller.passwordError, errorText: controller.passwordError,
), ),
FullWidthButton( FullWidthButton(
title: Row( title: L10n.of(context).signIn,
mainAxisAlignment: MainAxisAlignment.center, icon: PangeaLogoSvg(
children: [ width: 20,
PangeaLogoSvg( forceColor: Theme.of(context).colorScheme.onPrimary,
width: 20,
forceColor: Theme.of(context).colorScheme.onPrimary,
),
const SizedBox(width: 10),
Text(L10n.of(context).signIn),
],
), ),
onPressed: controller.enabledSignIn ? controller.login : null, onPressed: controller.enabledSignIn ? controller.login : null,
loading: controller.loading, loading: controller.loading,

@ -19,18 +19,12 @@ class SignupPageView extends StatelessWidget {
return PangeaLoginScaffold( return PangeaLoginScaffold(
children: [ children: [
FullWidthButton( FullWidthButton(
title: Row( title: L10n.of(context).signUpWithEmail,
mainAxisAlignment: MainAxisAlignment.center,
children: [
PangeaLogoSvg(
width: 20,
forceColor: Theme.of(context).colorScheme.onPrimary,
),
const SizedBox(width: 10),
Text(L10n.of(context).signUpWithEmail),
],
),
onPressed: () => context.go('/home/signup/email'), onPressed: () => context.go('/home/signup/email'),
icon: PangeaLogoSvg(
width: 20,
forceColor: Theme.of(context).colorScheme.onPrimary,
),
), ),
PangeaSsoButton( PangeaSsoButton(
provider: SSOProvider.google, provider: SSOProvider.google,

@ -21,7 +21,6 @@ class SignupWithEmailView extends StatelessWidget {
children: [ children: [
FullWidthTextField( FullWidthTextField(
hintText: L10n.of(context).yourUsername, hintText: L10n.of(context).yourUsername,
autofocus: true,
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (text) { validator: (text) {
if (text == null || text.isEmpty) { if (text == null || text.isEmpty) {
@ -47,16 +46,10 @@ class SignupWithEmailView extends StatelessWidget {
), ),
TosCheckbox(controller), TosCheckbox(controller),
FullWidthButton( FullWidthButton(
title: Row( title: L10n.of(context).signUp,
mainAxisAlignment: MainAxisAlignment.center, icon: PangeaLogoSvg(
children: [ width: 20,
PangeaLogoSvg( forceColor: Theme.of(context).colorScheme.onPrimary,
width: 20,
forceColor: Theme.of(context).colorScheme.onPrimary,
),
const SizedBox(width: 10),
Text(L10n.of(context).signUp),
],
), ),
onPressed: controller.enableSignUp ? controller.signup : null, onPressed: controller.enableSignUp ? controller.signup : null,
error: controller.error, error: controller.error,

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:fluffychat/pangea/constants/local.key.dart';
import 'package:fluffychat/pangea/controllers/language_list_controller.dart'; import 'package:fluffychat/pangea/controllers/language_list_controller.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/models/language_model.dart'; import 'package:fluffychat/pangea/models/language_model.dart';
@ -51,11 +52,26 @@ class UserSettingsState extends State<UserSettingsPage> {
: PangeaLanguage.byLangCode(systemLangCode); : PangeaLanguage.byLangCode(systemLangCode);
} }
bool canSetDisplayName = false;
TextEditingController displayNameController = TextEditingController();
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
selectedTargetLanguage = _pangeaController.languageController.userL2; selectedTargetLanguage = _pangeaController.languageController.userL2;
selectedAvatarPath = avatarPaths.first; selectedAvatarPath = avatarPaths.first;
final loginTypeEntry =
_pangeaController.pStoreService.read(PLocalKey.loginType);
if (loginTypeEntry is String && loginTypeEntry == 'sso') {
canSetDisplayName = true;
}
}
@override
void dispose() {
displayNameController.dispose();
super.dispose();
} }
void setSelectedTargetLanguage(LanguageModel? language) { void setSelectedTargetLanguage(LanguageModel? language) {
@ -118,6 +134,15 @@ class UserSettingsState extends State<UserSettingsPage> {
} }
} }
Future<void> _setDisplayName() async {
final displayName = displayNameController.text.trim();
if (displayName.isEmpty) return;
final client = Matrix.of(context).client;
if (client.userID == null) return;
await client.setDisplayName(client.userID!, displayName);
}
Future<void> createUserInPangea() async { Future<void> createUserInPangea() async {
setState(() => profileCreationError = null); setState(() => profileCreationError = null);
@ -128,10 +153,12 @@ class UserSettingsState extends State<UserSettingsPage> {
return; return;
} }
if (!formKey.currentState!.validate()) return;
setState(() => loading = true); setState(() => loading = true);
try { try {
final updateFuture = [ final updateFuture = [
_setDisplayName(),
_setAvatar(), _setAvatar(),
_pangeaController.subscriptionController.reinitialize(), _pangeaController.subscriptionController.reinitialize(),
_pangeaController.userController.updateProfile( _pangeaController.userController.updateProfile(

@ -15,6 +15,8 @@ class UserSettingsView extends StatelessWidget {
super.key, super.key,
}); });
final double avatarSize = 55.0;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final List<Widget> avatarOptions = controller.avatarPaths final List<Widget> avatarOptions = controller.avatarPaths
@ -25,6 +27,7 @@ class UserSettingsView extends StatelessWidget {
onTap: () => controller.setSelectedAvatarPath(index), onTap: () => controller.setSelectedAvatarPath(index),
path: path, path: path,
selected: controller.selectedAvatarIndex == index, selected: controller.selectedAvatarIndex == index,
size: avatarSize,
), ),
); );
}) })
@ -37,8 +40,8 @@ class UserSettingsView extends StatelessWidget {
child: InkWell( child: InkWell(
onTap: controller.uploadAvatar, onTap: controller.uploadAvatar,
child: Container( child: Container(
width: 50, width: avatarSize,
height: 50, height: avatarSize,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: Colors.white, color: Colors.white,
@ -51,7 +54,7 @@ class UserSettingsView extends StatelessWidget {
), ),
child: Icon( child: Icon(
Icons.upload, Icons.upload,
color: Theme.of(context).colorScheme.onPrimary, color: Theme.of(context).colorScheme.primary,
size: 30, size: 30,
), ),
), ),
@ -59,48 +62,59 @@ class UserSettingsView extends StatelessWidget {
), ),
); );
return PangeaLoginScaffold( return Form(
showAppName: false, key: controller.formKey,
mainAssetPath: controller.selectedAvatarPath ?? "", child: PangeaLoginScaffold(
mainAssetBytes: controller.avatar, showAppName: false,
children: [ mainAssetPath: controller.selectedAvatarPath ?? "",
Opacity( mainAssetBytes: controller.avatar,
opacity: 0.9, children: [
child: Text( Opacity(
L10n.of(context).chooseYourAvatar, opacity: 0.9,
style: const TextStyle( child: Text(
fontWeight: FontWeight.w100, L10n.of(context).chooseYourAvatar,
fontStyle: FontStyle.italic, style: const TextStyle(
fontWeight: FontWeight.w100,
fontStyle: FontStyle.italic,
),
), ),
), ),
), Wrap(
Row( alignment: WrapAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, children: avatarOptions,
children: avatarOptions,
),
Padding(
padding: const EdgeInsets.all(8),
child: PLanguageDropdown(
languages: controller.targetOptions,
onChange: controller.setSelectedTargetLanguage,
initialLanguage: controller.selectedTargetLanguage,
isL2List: true,
error: controller.selectedLanguageError,
), ),
), Padding(
FullWidthButton( padding: const EdgeInsets.all(8),
title: Row( child: PLanguageDropdown(
mainAxisAlignment: MainAxisAlignment.center, languages: controller.targetOptions,
children: [Text(L10n.of(context).letsStart)], onChange: controller.setSelectedTargetLanguage,
initialLanguage: controller.selectedTargetLanguage,
isL2List: true,
error: controller.selectedLanguageError,
),
), ),
onPressed: controller.selectedTargetLanguage != null if (controller.canSetDisplayName)
? controller.createUserInPangea FullWidthTextField(
: null, hintText: L10n.of(context).username,
error: controller.profileCreationError, validator: (username) {
loading: controller.loading, if (username == null || username.isEmpty) {
enabled: controller.selectedTargetLanguage != null, return L10n.of(context).pleaseChooseAUsername;
), }
], return null;
},
controller: controller.displayNameController,
),
FullWidthButton(
title: L10n.of(context).letsStart,
onPressed: controller.selectedTargetLanguage != null
? controller.createUserInPangea
: null,
error: controller.profileCreationError,
loading: controller.loading,
enabled: controller.selectedTargetLanguage != null,
),
],
),
); );
} }
} }
@ -115,7 +129,7 @@ class AvatarOption extends StatelessWidget {
super.key, super.key,
required this.onTap, required this.onTap,
required this.path, required this.path,
this.size = 50.0, this.size = 40.0,
this.selected = false, this.selected = false,
}); });

@ -1,5 +1,6 @@
import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.dart'; import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.dart';
import 'package:fluffychat/pangea/constants/local.key.dart';
import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; import 'package:fluffychat/pangea/utils/firebase_analytics.dart';
import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
@ -42,7 +43,6 @@ Future<void> pangeaSSOLoginAction(
result = await FlutterWebAuth2.authenticate( result = await FlutterWebAuth2.authenticate(
url: url.toString(), url: url.toString(),
callbackUrlScheme: urlScheme, callbackUrlScheme: urlScheme,
options: const FlutterWebAuth2Options(),
); );
} catch (err) { } catch (err) {
if (err is PlatformException && err.code == 'CANCELED') { if (err is PlatformException && err.code == 'CANCELED') {
@ -60,5 +60,6 @@ Future<void> pangeaSSOLoginAction(
token: token, token: token,
initialDeviceDisplayName: PlatformInfos.clientName, initialDeviceDisplayName: PlatformInfos.clientName,
); );
MatrixState.pangeaController.pStoreService.save(PLocalKey.loginType, 'sso');
GoogleAnalytics.login(provider.name!, loginRes.userId); GoogleAnalytics.login(provider.name!, loginRes.userId);
} }

@ -126,12 +126,8 @@ class PressableButtonState extends State<PressableButton>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return NotificationListener<ButtonPressedNotification>( return MouseRegion(
onNotification: (notification) { cursor: SystemMouseCursors.click,
_onTapDown(null);
_onTapUp(null);
return true; // Stop the notification from bubbling further
},
child: GestureDetector( child: GestureDetector(
onTapDown: _onTapDown, onTapDown: _onTapDown,
onTapUp: _onTapUp, onTapUp: _onTapUp,
@ -167,5 +163,3 @@ class PressableButtonState extends State<PressableButton>
); );
} }
} }
class ButtonPressedNotification extends Notification {}

@ -23,65 +23,62 @@ class TosCheckboxState extends State<TosCheckbox>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Row(
padding: const EdgeInsets.all(8), crossAxisAlignment: CrossAxisAlignment.center,
child: Row( children: [
crossAxisAlignment: CrossAxisAlignment.center, Expanded(
children: [ child: Column(
Expanded( crossAxisAlignment: CrossAxisAlignment.start,
child: Column( mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start, children: [
mainAxisAlignment: MainAxisAlignment.center, InkWell(
children: [ onTap: () => UrlLauncher(context, AppConfig.termsOfServiceUrl)
InkWell( .launchUrl(),
onTap: () => UrlLauncher(context, AppConfig.termsOfServiceUrl) child: Padding(
.launchUrl(), padding: const EdgeInsets.only(left: 15),
child: Padding( child: RichText(
padding: const EdgeInsets.only(left: 15), text: TextSpan(
child: RichText( text: L10n.of(context).iAgreeToThe,
text: TextSpan( children: [
text: L10n.of(context).iAgreeToThe, TextSpan(
children: [ text: L10n.of(context).termsAndConditions,
TextSpan( style: const TextStyle(
text: L10n.of(context).termsAndConditions, decoration: TextDecoration.underline,
style: const TextStyle(
decoration: TextDecoration.underline,
),
), ),
],
style: TextStyle(
fontSize: 16,
color: Theme.of(context).colorScheme.onSurface,
), ),
],
style: TextStyle(
fontSize: 14,
color: Theme.of(context).colorScheme.onSurface,
), ),
), ),
), ),
), ),
AnimatedSize( ),
duration: FluffyThemes.animationDuration, AnimatedSize(
child: widget.controller.signupError == null duration: FluffyThemes.animationDuration,
? const SizedBox.shrink() child: widget.controller.signupError == null
: Padding( ? const SizedBox.shrink()
padding: const EdgeInsets.only(top: 4, left: 30), : Padding(
child: Text( padding: const EdgeInsets.only(top: 4, left: 30),
widget.controller.signupError!, child: Text(
style: TextStyle( widget.controller.signupError!,
color: Theme.of(context).colorScheme.error, style: TextStyle(
fontSize: 12, color: Theme.of(context).colorScheme.error,
), fontSize: 12,
), ),
), ),
), ),
], ),
), ],
),
Checkbox(
value: widget.controller.isTnCChecked,
activeColor: Theme.of(context).colorScheme.primary,
onChanged: widget.controller.onTncChange,
), ),
], ),
), Checkbox(
value: widget.controller.isTnCChecked,
activeColor: Theme.of(context).colorScheme.primary,
onChanged: widget.controller.onTncChange,
),
],
); );
} }
} }

@ -76,7 +76,11 @@ class _PLanguageDropdownState extends State<PLanguageDropdown> {
children: [ children: [
const Icon(Icons.language_outlined), const Icon(Icons.language_outlined),
const SizedBox(width: 10), const SizedBox(width: 10),
Text(L10n.of(context).iWantToLearn), Text(
widget.isL2List
? L10n.of(context).iWantToLearn
: L10n.of(context).myBaseLanguage,
),
], ],
), ),
isExpanded: true, isExpanded: true,

Loading…
Cancel
Save