diff --git a/lib/src/localization/generated/app_localizations.dart b/lib/src/localization/generated/app_localizations.dart index 2ed141e2..1f9e78ed 100644 --- a/lib/src/localization/generated/app_localizations.dart +++ b/lib/src/localization/generated/app_localizations.dart @@ -2435,13 +2435,13 @@ abstract class AppLocalizations { /// No description provided for @userDiscoverySettingsManualApproval. /// /// In en, this message translates to: - /// **'Manual approval'** + /// **'Ask before sharing'** String get userDiscoverySettingsManualApproval; /// No description provided for @userDiscoverySettingsManualApprovalDesc. /// /// In en, this message translates to: - /// **'Before someone is shared, you\'ll be asked first.'** + /// **'Before one of your friends is shared, you will be asked every time.'** String get userDiscoverySettingsManualApprovalDesc; /// No description provided for @onboardingUserDiscoveryLetFriendsFindYou. @@ -2882,6 +2882,18 @@ abstract class AppLocalizations { /// **'Mutual Friends'** String get userDiscoverySettingsTitle; + /// No description provided for @userDiscoveryWhyThisIsUsed. + /// + /// In en, this message translates to: + /// **'Why this is used'** + String get userDiscoveryWhyThisIsUsed; + + /// No description provided for @userDiscoveryFeatureOffers. + /// + /// In en, this message translates to: + /// **'Your benefits at a glance'** + String get userDiscoveryFeatureOffers; + /// No description provided for @userDiscoveryDisabledLearnMore. /// /// In en, this message translates to: diff --git a/lib/src/localization/generated/app_localizations_de.dart b/lib/src/localization/generated/app_localizations_de.dart index 83629f9a..e635f6fd 100644 --- a/lib/src/localization/generated/app_localizations_de.dart +++ b/lib/src/localization/generated/app_localizations_de.dart @@ -1330,11 +1330,11 @@ class AppLocalizationsDe extends AppLocalizations { 'Erfahre, wer dich anfragt'; @override - String get userDiscoverySettingsManualApproval => 'Manuelle Zustimmung'; + String get userDiscoverySettingsManualApproval => 'Vor dem Teilen fragen'; @override String get userDiscoverySettingsManualApprovalDesc => - 'Bevor jemand geteilt wird, wirst du zuerst gefragt.'; + 'Bevor einer deiner Freunde geteilt wird, wirst du jedes Mal gefragt.'; @override String get onboardingUserDiscoveryLetFriendsFindYou => @@ -1629,6 +1629,12 @@ class AppLocalizationsDe extends AppLocalizations { @override String get userDiscoverySettingsTitle => 'Gemeinsame Freunde'; + @override + String get userDiscoveryWhyThisIsUsed => 'Warum dies verwendet wird'; + + @override + String get userDiscoveryFeatureOffers => 'Dein Nutzen auf einen Blick'; + @override String get userDiscoveryDisabledLearnMore => 'Mehr erfahren'; diff --git a/lib/src/localization/generated/app_localizations_en.dart b/lib/src/localization/generated/app_localizations_en.dart index aafbf9dc..0bac7976 100644 --- a/lib/src/localization/generated/app_localizations_en.dart +++ b/lib/src/localization/generated/app_localizations_en.dart @@ -1321,11 +1321,11 @@ class AppLocalizationsEn extends AppLocalizations { 'Be informed about who is requesting'; @override - String get userDiscoverySettingsManualApproval => 'Manual approval'; + String get userDiscoverySettingsManualApproval => 'Ask before sharing'; @override String get userDiscoverySettingsManualApprovalDesc => - 'Before someone is shared, you\'ll be asked first.'; + 'Before one of your friends is shared, you will be asked every time.'; @override String get onboardingUserDiscoveryLetFriendsFindYou => @@ -1614,6 +1614,12 @@ class AppLocalizationsEn extends AppLocalizations { @override String get userDiscoverySettingsTitle => 'Mutual Friends'; + @override + String get userDiscoveryWhyThisIsUsed => 'Why this is used'; + + @override + String get userDiscoveryFeatureOffers => 'Your benefits at a glance'; + @override String get userDiscoveryDisabledLearnMore => 'Learn more'; diff --git a/lib/src/localization/translations b/lib/src/localization/translations index 3a9c589d..3142288c 160000 --- a/lib/src/localization/translations +++ b/lib/src/localization/translations @@ -1 +1 @@ -Subproject commit 3a9c589de2d2abc0042004dbfe943fa4fb2c92c7 +Subproject commit 3142288ce2597f051f4294cb1b3ef33a1fe23362 diff --git a/lib/src/visual/views/settings/developer/developer.view.dart b/lib/src/visual/views/settings/developer/developer.view.dart index 8329941a..fcef4c8d 100644 --- a/lib/src/visual/views/settings/developer/developer.view.dart +++ b/lib/src/visual/views/settings/developer/developer.view.dart @@ -369,9 +369,7 @@ class _DeveloperSettingsViewState extends State { title: const Text('Reopen Setup'), onTap: () async { await UserService.update((u) { - u - ..currentSetupPage = SetupPages.profile.name - ..isUserDiscoveryEnabled = false; + u.currentSetupPage = SetupPages.profile.name; }); }, ), diff --git a/lib/src/visual/views/settings/privacy/user_discovery/components/user_discovery_setup.comp.dart b/lib/src/visual/views/settings/privacy/user_discovery/components/user_discovery_setup.comp.dart index 5c214df0..c44499f5 100644 --- a/lib/src/visual/views/settings/privacy/user_discovery/components/user_discovery_setup.comp.dart +++ b/lib/src/visual/views/settings/privacy/user_discovery/components/user_discovery_setup.comp.dart @@ -8,7 +8,6 @@ import 'package:twonly/src/visual/components/avatar_icon.comp.dart'; import 'package:twonly/src/visual/components/verification_badge.comp.dart'; import 'package:twonly/src/visual/views/contact/add_new_contact_components/friend_suggestions.comp.dart'; import 'package:twonly/src/visual/views/onboarding/setup/components/mock_contact_request_actions.comp.dart'; -import 'package:twonly/src/visual/views/onboarding/setup/components/setup_switch_card.comp.dart'; List getExampleUsers(BuildContext context) => [ context.lang.exampleUserName1, @@ -103,91 +102,94 @@ class UserDiscoverySetupComp extends StatelessWidget { @override Widget build(BuildContext context) { + final showShareYourFriends = + showOnlySpecificPage == UserDiscoveryPages.all || + showOnlySpecificPage == UserDiscoveryPages.shareYourFriends; + final showLetYourFriendsFindYou = + showOnlySpecificPage == UserDiscoveryPages.all || + showOnlySpecificPage == UserDiscoveryPages.letYourFriendsFindYou; + return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - if (showOnlySpecificPage == UserDiscoveryPages.all || - showOnlySpecificPage == UserDiscoveryPages.shareYourFriends) ...[ + if (showShareYourFriends) ...[ Text( context.lang.onboardingUserDiscoveryShareFriends, style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), - const SizedBox(height: 32), + const SizedBox(height: 24), + // First description text (centered, no card/title/icon) RichText( text: TextSpan( children: formattedText( context, context.lang.onboardingUserDiscoveryShareFriendsDesc, ), + style: TextStyle( + color: context.color.onSurface, + fontSize: 13, + height: 1.4, + ), ), textAlign: TextAlign.center, ), - const SizedBox(height: 24), - SetupSwitchCard( - value: state.isUserDiscoveryEnabled, - onChanged: (val) => state.update(() { - state.isUserDiscoveryEnabled = val; - }), - title: context.lang.onboardingUserDiscoveryShareFriends, - expandedChild: Column( + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: context.color.surfaceContainerLow, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: context.color.outlineVariant.withValues(alpha: 0.5), + ), + ), + child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - SwitchListTile( - value: state.isManualApprovalEnabled, - onChanged: (val) => state.update( - () => state.isManualApprovalEnabled = val, - ), - title: Text( - context.lang.userDiscoverySettingsManualApproval, - style: const TextStyle(fontSize: 13), - ), - subtitle: Text( - context.lang.userDiscoverySettingsManualApprovalDesc, - style: const TextStyle(fontSize: 10), - ), - tileColor: context.color.surfaceContainerLow, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, + Text( + context.lang.userDiscoveryFeatureOffers, + style: TextStyle( + fontSize: 16, + color: context.color.primary, ), + textAlign: TextAlign.center, ), - const Padding( - padding: EdgeInsets.only(bottom: 8), - child: Divider(), - ), - const _ExampleLabel(), + const SizedBox(height: 12), Text( context.lang.onboardingUserDiscoveryWhoIsRequesting, style: TextStyle( color: context.color.onSurfaceVariant, fontSize: 12, + fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), - const SizedBox(height: 16), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), + const SizedBox(height: 8), + Center( child: Container( + constraints: const BoxConstraints(maxWidth: 320), padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 3, + horizontal: 12, + vertical: 8, ), decoration: BoxDecoration( - border: Border.all(color: Colors.grey, width: 0.5), + color: context.color.surface, borderRadius: BorderRadius.circular(12), + border: Border.all( + color: context.color.outlineVariant.withValues( + alpha: 0.3, + ), + ), ), child: Row( - mainAxisAlignment: MainAxisAlignment.center, children: [ const AvatarIcon(fontSize: 14), - const SizedBox(width: 5), + const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -208,7 +210,10 @@ class UserDiscoverySetupComp extends StatelessWidget { context.lang.exampleUserName1, ], ), - style: const TextStyle(fontSize: 10), + style: TextStyle( + fontSize: 10, + color: context.color.onSurfaceVariant, + ), ), ), ], @@ -219,37 +224,46 @@ class UserDiscoverySetupComp extends StatelessWidget { ), ), ), - - const SizedBox(height: 24), + const SizedBox(height: 16), Text( context.lang.onboardingUserDiscoveryContactsVerifiedBadge, style: TextStyle( color: context.color.onSurfaceVariant, fontSize: 12, + fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), - const SizedBox(height: 16), + const SizedBox(height: 8), Center( child: Container( - width: 100, - height: 40, + constraints: const BoxConstraints(maxWidth: 320), + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), decoration: BoxDecoration( - border: Border.all(color: Colors.grey, width: 0.5), + color: context.color.surface, borderRadius: BorderRadius.circular(12), + border: Border.all( + color: context.color.outlineVariant.withValues( + alpha: 0.3, + ), + ), ), child: Row( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, children: [ const AvatarIcon(fontSize: 12), - const SizedBox(width: 5), + const SizedBox(width: 8), Text( context.lang.exampleJane, style: const TextStyle( fontWeight: FontWeight.bold, + fontSize: 13, ), ), - const SizedBox(width: 5), + const SizedBox(width: 6), const VerificationBadgeComp( isVerifiedByTransferredTrust: true, size: 14, @@ -259,113 +273,171 @@ class UserDiscoverySetupComp extends StatelessWidget { ), ), ), - - const SizedBox(height: 16), ], ), ), + const SizedBox(height: 24), + // Checkboxes / settings Card + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: context.color.surfaceContainerLow, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: context.color.outlineVariant.withValues(alpha: 0.5), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SwitchListTile( + value: state.isUserDiscoveryEnabled, + onChanged: (val) => state.update(() { + state.isUserDiscoveryEnabled = val; + }), + title: Text( + context.lang.onboardingUserDiscoveryShareFriends, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + tileColor: Colors.transparent, + contentPadding: const EdgeInsets.symmetric(horizontal: 8), + ), + AnimatedCrossFade( + firstChild: const SizedBox( + width: double.infinity, + height: 0, + ), + secondChild: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Divider( + color: context.color.outlineVariant.withValues( + alpha: 0.3, + ), + ), + ), + SwitchListTile( + value: state.isManualApprovalEnabled, + onChanged: (val) => state.update( + () => state.isManualApprovalEnabled = val, + ), + title: Text( + context.lang.userDiscoverySettingsManualApproval, + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w600, + ), + ), + subtitle: Text( + context + .lang + .userDiscoverySettingsManualApprovalDesc, + style: TextStyle( + fontSize: 11, + color: context.color.onSurfaceVariant, + ), + ), + tileColor: Colors.transparent, + contentPadding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + ), + ], + ), + crossFadeState: state.isUserDiscoveryEnabled + ? CrossFadeState.showSecond + : CrossFadeState.showFirst, + duration: const Duration(milliseconds: 300), + ), + ], + ), + ), if (showOnlySpecificPage == UserDiscoveryPages.all) - const SizedBox(height: 80), + const SizedBox(height: 48), ], - - if (showOnlySpecificPage == UserDiscoveryPages.all || - showOnlySpecificPage == - UserDiscoveryPages.letYourFriendsFindYou) ...[ + if (showLetYourFriendsFindYou) ...[ Text( context.lang.onboardingUserDiscoveryLetFriendsFindYou, style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), - const SizedBox(height: 32), + const SizedBox(height: 24), + // First description text (centered, no card/title/icon) RichText( text: TextSpan( children: formattedText( context, context.lang.userDiscoveryDisabledIntro, ), + style: TextStyle( + color: context.color.onSurface, + fontSize: 13, + height: 1.4, + ), ), textAlign: TextAlign.center, ), + const SizedBox(height: 24), - const SizedBox(height: 32), - - SetupSwitchCard( - value: state.sharePromotion, - onChanged: (val) => state.update(() { - state.sharePromotion = val; - }), - title: context.lang.onboardingUserDiscoveryBeRecommended, - expandedChild: Column( + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: context.color.surfaceContainerLow, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: context.color.outlineVariant.withValues(alpha: 0.5), + ), + ), + child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - children: [ - Expanded( - child: Text( - context.lang.userDiscoverySettingsMutualFriends, - style: const TextStyle(fontSize: 12), - ), - ), - const SizedBox(width: 12), - DropdownButtonHideUnderline( - child: DropdownButton( - value: state.threshold, - items: List.generate( - 9, - (index) { - final value = index + 2; - return DropdownMenuItem( - value: value, - child: Text('$value'), - ); - }, - ), - onChanged: (newValue) { - if (newValue != null) { - state.update(() { - state.threshold = newValue; - }); - } - }, - ), - ), - ], + Text( + context.lang.userDiscoveryFeatureOffers, + style: TextStyle( + fontSize: 16, + color: context.color.primary, ), + textAlign: TextAlign.center, ), - const Padding( - padding: EdgeInsets.only(bottom: 8, top: 8), - child: Divider(), - ), - const _ExampleLabel(), + const SizedBox(height: 12), Text( context.lang.onboardingUserDiscoveryWhatOthersSee, style: TextStyle( color: context.color.onSurfaceVariant, fontSize: 12, + fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), - const SizedBox(height: 16), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), + const SizedBox(height: 8), + Center( child: Container( + constraints: const BoxConstraints(maxWidth: 320), padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 3, + horizontal: 12, + vertical: 8, ), decoration: BoxDecoration( - border: Border.all(color: Colors.grey, width: 0.5), + color: context.color.surface, borderRadius: BorderRadius.circular(12), + border: Border.all( + color: context.color.outlineVariant.withValues( + alpha: 0.3, + ), + ), ), child: Row( - mainAxisAlignment: MainAxisAlignment.center, children: [ const AvatarIcon(fontSize: 14), - const SizedBox(width: 5), + const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -374,6 +446,7 @@ class UserDiscoverySetupComp extends StatelessWidget { userService.currentUser.username, style: const TextStyle( fontWeight: FontWeight.bold, + fontSize: 13, ), ), RichText( @@ -385,7 +458,10 @@ class UserDiscoverySetupComp extends StatelessWidget { state.threshold, ), ), - style: const TextStyle(fontSize: 11), + style: TextStyle( + fontSize: 11, + color: context.color.onSurfaceVariant, + ), ), ), ], @@ -402,28 +478,31 @@ class UserDiscoverySetupComp extends StatelessWidget { style: TextStyle( color: context.color.onSurfaceVariant, fontSize: 12, + fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), - const SizedBox(height: 16), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - ), + const SizedBox(height: 8), + Center( child: Container( + constraints: const BoxConstraints(maxWidth: 320), padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 3, + horizontal: 12, + vertical: 8, ), decoration: BoxDecoration( - border: Border.all(color: Colors.grey, width: 0.5), + color: context.color.surface, borderRadius: BorderRadius.circular(12), + border: Border.all( + color: context.color.outlineVariant.withValues( + alpha: 0.3, + ), + ), ), child: Row( - mainAxisAlignment: MainAxisAlignment.center, children: [ const AvatarIcon(fontSize: 14), - const SizedBox(width: 5), + const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -444,7 +523,10 @@ class UserDiscoverySetupComp extends StatelessWidget { state.threshold, ), ), - style: const TextStyle(fontSize: 10), + style: TextStyle( + fontSize: 10, + color: context.color.onSurfaceVariant, + ), ), ), ], @@ -455,7 +537,125 @@ class UserDiscoverySetupComp extends StatelessWidget { ), ), ), - const SizedBox(height: 16), + ], + ), + ), + const SizedBox(height: 24), + + // Checkboxes / settings Card + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: context.color.surfaceContainerLow, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: context.color.outlineVariant.withValues(alpha: 0.5), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SwitchListTile( + value: state.sharePromotion, + onChanged: (val) => state.update(() { + state.sharePromotion = val; + }), + title: Text( + context.lang.onboardingUserDiscoveryBeRecommended, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + tileColor: Colors.transparent, + contentPadding: const EdgeInsets.symmetric(horizontal: 8), + ), + AnimatedCrossFade( + firstChild: const SizedBox( + width: double.infinity, + height: 0, + ), + secondChild: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Divider( + color: context.color.outlineVariant.withValues( + alpha: 0.3, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 8, + ), + child: Row( + children: [ + Expanded( + child: Text( + context + .lang + .userDiscoverySettingsMutualFriends, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + const SizedBox(width: 12), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + ), + decoration: BoxDecoration( + color: context.color.surface, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: context.color.outlineVariant + .withValues( + alpha: 0.5, + ), + ), + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: state.threshold, + style: TextStyle( + color: context.color.onSurface, + fontWeight: FontWeight.bold, + ), + items: List.generate( + 9, + (index) { + final value = index + 2; + return DropdownMenuItem( + value: value, + child: Text('$value'), + ); + }, + ), + onChanged: (newValue) { + if (newValue != null) { + state.update(() { + state.threshold = newValue; + }); + } + }, + ), + ), + ), + ], + ), + ), + ], + ), + crossFadeState: state.sharePromotion + ? CrossFadeState.showSecond + : CrossFadeState.showFirst, + duration: const Duration(milliseconds: 300), + ), ], ), ), @@ -465,28 +665,3 @@ class UserDiscoverySetupComp extends StatelessWidget { ); } } - -class _ExampleLabel extends StatelessWidget { - const _ExampleLabel(); - - @override - Widget build(BuildContext context) { - return Align( - alignment: Alignment.centerRight, - child: Padding( - padding: const EdgeInsets.only(right: 12), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey, width: 0.5), - borderRadius: BorderRadius.circular(12), - ), - child: Text( - context.lang.onboardingExampleLabel, - style: const TextStyle(fontSize: 10), - ), - ), - ), - ); - } -}