Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 5200 - currency selector #5236

Merged
merged 1 commit into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class UserPreferences extends ChangeNotifier {
static const String _TAG_CURRENT_COLOR_SCHEME = 'currentColorScheme';
static const String _TAG_CURRENT_CONTRAST_MODE = 'contrastMode';
static const String _TAG_USER_COUNTRY_CODE = 'userCountry';
static const String _TAG_USER_CURRENCY_CODE = 'userCurrency';
static const String _TAG_LAST_VISITED_ONBOARDING_PAGE =
'lastVisitedOnboardingPage';
static const String _TAG_PREFIX_FLAG = 'FLAG_PREFIX_';
Expand Down Expand Up @@ -213,6 +214,14 @@ class UserPreferences extends ChangeNotifier {
String? get userCountryCode =>
_sharedPreferences.getString(_TAG_USER_COUNTRY_CODE);

Future<void> setUserCurrencyCode(final String code) async {
await _sharedPreferences.setString(_TAG_USER_CURRENCY_CODE, code);
notifyListeners();
}

String? get userCurrencyCode =>
_sharedPreferences.getString(_TAG_USER_CURRENCY_CODE);

Future<void> setLastVisitedOnboardingPage(final OnboardingPage page) async {
await _sharedPreferences.setInt(
_TAG_LAST_VISITED_ONBOARDING_PAGE, page.index);
Expand All @@ -223,6 +232,7 @@ class UserPreferences extends ChangeNotifier {
await setLastVisitedOnboardingPage(OnboardingPage.NOT_STARTED);
// for tests with a fresh null country
await _sharedPreferences.remove(_TAG_USER_COUNTRY_CODE);
await _sharedPreferences.remove(_TAG_USER_CURRENCY_CODE);
notifyListeners();
}

Expand Down
8 changes: 8 additions & 0 deletions packages/smooth_app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,10 @@
"@country_chooser_label": {
"description": "Label shown above a selector where the user can select their country (in the preferences)"
},
"currency_chooser_label": "Please choose a currency",
"@currency_chooser_label": {
"description": "Label shown above a selector where the user can select their currency (in the preferences)"
},
"onboarding_country_chooser_label": "Please choose a country:",
"@onboarding_country_chooser_label": {
"description": "The label shown above a selector where the user can select their country (in the onboarding)"
Expand Down Expand Up @@ -2462,6 +2466,10 @@
"@country_selector_title": {
"description": "Label written as the title of the dialog to select the user country"
},
"currency_selector_title": "Select your currency:",
"@currency_selector_title": {
"description": "Label written as the title of the dialog to select the user currency"
},
"language_selector_title": "Select your language:",
"@language_selector_title": {
"description": "Label written as the title of the dialog to select the user language"
Expand Down
15 changes: 2 additions & 13 deletions packages/smooth_app/lib/pages/onboarding/country_selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,13 @@ class CountrySelector extends StatefulWidget {
this.textStyle,
this.padding,
this.icon,
this.iconDecoration,
this.inkWellBorderRadius,
});

final TextStyle? textStyle;
final EdgeInsetsGeometry? padding;
final BorderRadius? inkWellBorderRadius;
final Icon? icon;
final BoxDecoration? iconDecoration;
final Widget? icon;

@override
State<CountrySelector> createState() => _CountrySelectorState();
Expand Down Expand Up @@ -199,16 +197,7 @@ class _CountrySelectorState extends State<CountrySelector> {
),
),
),
Container(
height: double.infinity,
decoration:
widget.iconDecoration ?? const BoxDecoration(),
child: AspectRatio(
aspectRatio: 1.0,
child:
widget.icon ?? const Icon(Icons.arrow_drop_down),
),
),
widget.icon ?? const Icon(Icons.arrow_drop_down),
],
),
),
Expand Down
198 changes: 198 additions & 0 deletions packages/smooth_app/lib/pages/onboarding/currency_selector.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/data_models/preferences/user_preferences.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/generic_lib/dialogs/smooth_alert_dialog.dart';
import 'package:smooth_app/generic_lib/widgets/smooth_text_form_field.dart';
import 'package:smooth_app/widgets/smooth_text.dart';

/// A selector for selecting user's currency.
class CurrencySelector extends StatefulWidget {
const CurrencySelector({
this.textStyle,
this.padding,
this.icon,
});

final TextStyle? textStyle;
final EdgeInsetsGeometry? padding;
final Icon? icon;

@override
State<CurrencySelector> createState() => _CurrencySelectorState();
}

class _CurrencySelectorState extends State<CurrencySelector> {
final ScrollController _scrollController = ScrollController();
final TextEditingController _currencyController = TextEditingController();
final List<Currency> _currencyList = List<Currency>.from(Currency.values);

@override
Widget build(BuildContext context) {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
return Selector<UserPreferences, String?>(
selector: (BuildContext buildContext, UserPreferences userPreferences) =>
userPreferences.appLanguageCode,
builder: (BuildContext context, String? appLanguageCode, _) {
final UserPreferences userPreferences =
context.watch<UserPreferences>();
final Currency selected = _getSelected(
userPreferences.userCurrencyCode,
);
final EdgeInsetsGeometry innerPadding = const EdgeInsets.symmetric(
vertical: SMALL_SPACE,
).add(widget.padding ?? EdgeInsets.zero);

return InkWell(
borderRadius: ANGULAR_BORDER_RADIUS,
onTap: () async {
_reorderCurrencies(selected);
List<Currency> filteredList = List<Currency>.from(_currencyList);
final Currency? currency = await showDialog<Currency>(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context,
void Function(VoidCallback fn) setState) {
const double horizontalPadding = 16.0 + SMALL_SPACE;

return SmoothListAlertDialog(
title: appLocalizations.currency_selector_title,
header: SmoothTextFormField(
type: TextFieldTypes.PLAIN_TEXT,
prefixIcon: const Icon(Icons.search),
controller: _currencyController,
onChanged: (String? query) {
query = query!.trim()..getComparisonSafeString();

setState(
() {
filteredList = _currencyList
.where((Currency item) => item.name
.getComparisonSafeString()
.contains(
query!,
))
.toList(growable: false);
},
);
},
hintText: appLocalizations.search,
),
scrollController: _scrollController,
list: ListView.separated(
controller: _scrollController,
itemBuilder: (BuildContext context, int index) {
final Currency currency = filteredList[index];
final bool isSelected = currency == selected;
return ListTile(
dense: true,
contentPadding: const EdgeInsets.symmetric(
horizontal: horizontalPadding,
),
trailing:
isSelected ? const Icon(Icons.check) : null,
title: TextHighlighter(
text: currency.name,
filter: _currencyController.text,
selected: isSelected,
),
onTap: () {
Navigator.of(context).pop(currency);
_currencyController.clear();
},
);
},
separatorBuilder: (_, __) => const Divider(
height: 1.0,
),
itemCount: filteredList.length,
shrinkWrap: true,
),
positiveAction: SmoothActionButton(
onPressed: () {
Navigator.pop(context);
_currencyController.clear();
},
text: appLocalizations.cancel,
),
);
},
);
},
);
if (currency != null) {
await userPreferences.setUserCurrencyCode(currency.name);
}
},
child: DecoratedBox(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: innerPadding,
child: const Icon(Icons.currency_exchange),
),
Expanded(
flex: 1,
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: LARGE_SPACE),
child: Text(
selected.name,
style: Theme.of(context)
.textTheme
.displaySmall
?.merge(widget.textStyle),
),
),
),
widget.icon ?? const Icon(Icons.arrow_drop_down),
],
),
),
),
);
},
);
}

Currency _getSelected(final String? code) {
if (code != null) {
for (final Currency currency in _currencyList) {
if (currency.name == code) {
return currency;
}
}
}
return _currencyList[0];
}

/// Reorder currencies alphabetically, bring user's selected one to top.
void _reorderCurrencies(final Currency selected) {
_currencyList.sort(
(final Currency a, final Currency b) {
if (a == selected) {
return -1;
}
if (b == selected) {
return 1;
}
return a.name.compareTo(b.name);
},
);
}

@override
void dispose() {
_currencyController.dispose();
super.dispose();
}
}
20 changes: 13 additions & 7 deletions packages/smooth_app/lib/pages/onboarding/welcome_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,19 @@ class WelcomePage extends StatelessWidget {
horizontal: SMALL_SPACE,
),
inkWellBorderRadius: ROUNDED_BORDER_RADIUS,
icon: Icon(
Icons.edit,
color: Colors.white.withOpacity(0.9),
),
iconDecoration: BoxDecoration(
color: theme.primaryColor,
borderRadius: ROUNDED_BORDER_RADIUS,
icon: Container(
height: double.infinity,
decoration: BoxDecoration(
color: theme.primaryColor,
borderRadius: ROUNDED_BORDER_RADIUS,
),
child: AspectRatio(
aspectRatio: 1.0,
child: Icon(
Icons.edit,
color: Colors.white.withOpacity(0.9),
),
),
),
textStyle: TextStyle(color: theme.primaryColor),
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/pages/onboarding/currency_selector.dart';
import 'package:smooth_app/pages/preferences/user_preferences_item.dart';

/// Currency selector within user preferences.
class UserPreferencesCurrencySelector extends StatelessWidget {
const UserPreferencesCurrencySelector();

static UserPreferencesItem getUserPreferencesItem(
final BuildContext context,
) {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
return UserPreferencesItemSimple(
labels: <String>[_getLabel(appLocalizations)],
builder: (_) => const UserPreferencesCurrencySelector(),
);
}

static String _getLabel(final AppLocalizations appLocalizations) =>
appLocalizations.currency_chooser_label;

@override
Widget build(BuildContext context) {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final ThemeData themeData = Theme.of(context);
return ListTile(
title: Text(
_getLabel(appLocalizations),
style: themeData.textTheme.headlineMedium,
),
subtitle: Padding(
padding: const EdgeInsetsDirectional.only(
top: SMALL_SPACE,
bottom: SMALL_SPACE,
),
child: CurrencySelector(
textStyle: themeData.textTheme.bodyMedium,
icon: const Icon(Icons.edit),
padding: const EdgeInsetsDirectional.only(
start: SMALL_SPACE,
),
),
),
minVerticalPadding: MEDIUM_SPACE,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:smooth_app/pages/preferences/user_preferences_choose_accent_colo
import 'package:smooth_app/pages/preferences/user_preferences_choose_app_theme.dart';
import 'package:smooth_app/pages/preferences/user_preferences_choose_text_color_contrast.dart';
import 'package:smooth_app/pages/preferences/user_preferences_country_selector.dart';
import 'package:smooth_app/pages/preferences/user_preferences_currency_selector.dart';
import 'package:smooth_app/pages/preferences/user_preferences_image_source.dart';
import 'package:smooth_app/pages/preferences/user_preferences_item.dart';
import 'package:smooth_app/pages/preferences/user_preferences_language_selector.dart';
Expand Down Expand Up @@ -66,6 +67,8 @@ class UserPreferencesSettings extends AbstractUserPreferences {
_getDivider(),
UserPreferencesCountrySelector.getUserPreferencesItem(context),
_getDivider(),
UserPreferencesCurrencySelector.getUserPreferencesItem(context),
_getDivider(),
UserPreferencesLanguageSelector.getUserPreferencesItem(context),
_getDivider(),
UserPreferencesImageSource.getUserPreferencesItem(context),
Expand Down