mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-18 05:51:34 +02:00
3rd-party-disclaimer (#2372)
* feat: enhance dEuro Savings UI and functionality with fiat support and tooltips * feat: add "Reinvest Interest" feature and improve dEuro Savings functionality - Implemented the "Reinvest Interest" feature for dEuro Savings. - Updated localized strings for multiple languages. - Enhanced error handling for insufficient gas fees. - Incorporated loading state and tooltips in Savings Card and Interest Card. - Improved UI responsiveness and button state management. * feat: localize deuro tooltips * feat: enhance dEuro Savings with reinvestment feature and localized strings - Added "Reinvest Interest" functionality for dEuro Savings. - Updated localized strings across multiple languages. - Improved modal bottom sheet handling for savings add/remove operations. - Enhanced tooltips and UI responsiveness. * feat: improve dEuro Savings page with info chips and localized strings * Update res/values/strings_de.arb * fix: update dEuro action type reset in transaction handling * feat: add third-party disclaimer support and UI enhancements * feat: add dEuro disclaimer functionality --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
co-authored by
Omar Hatem
parent
3ba2e4283e
commit
342269a496
@@ -62,6 +62,7 @@ class PreferencesKey {
|
||||
static const mwebNodeUri = 'mwebNodeUri';
|
||||
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||
static const shouldShowYatPopup = 'should_show_yat_popup';
|
||||
static const shouldShowDEuroDisclaimer = 'should_show_deuro_disclaimer';
|
||||
static const shouldShowRepWarning = 'should_show_rep_warning';
|
||||
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
|
||||
static const syncModeKey = 'sync_mode';
|
||||
|
||||
@@ -43,6 +43,7 @@ import 'package:cake_wallet/src/screens/dev/secure_preferences_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dev/shared_preferences_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dev/background_sync_logs_page.dart';
|
||||
import 'package:cake_wallet/src/screens/disclaimer/disclaimer_page.dart';
|
||||
import 'package:cake_wallet/src/screens/disclaimer/third_party_disclaimer_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dart';
|
||||
@@ -418,6 +419,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||
case Routes.readDisclaimer:
|
||||
return CupertinoPageRoute<void>(builder: (_) => DisclaimerPage(isReadOnly: true));
|
||||
|
||||
case Routes.readThirdPartyDisclaimer:
|
||||
return CupertinoPageRoute<void>(builder: (_) => ThirdPartyDisclaimerPage());
|
||||
|
||||
case Routes.changeRep:
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<NanoChangeRepPage>());
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ class Routes {
|
||||
static const walletEdit = '/walletEdit';
|
||||
static const disclaimer = '/disclaimer';
|
||||
static const readDisclaimer = '/read_disclaimer';
|
||||
static const readThirdPartyDisclaimer = '/disclaimer/third_party';
|
||||
static const changeRep = '/change_representative';
|
||||
static const walletList = '/view_model.wallet_list';
|
||||
static const auth = '/auth';
|
||||
|
||||
@@ -34,10 +34,10 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
bool _checked = false;
|
||||
String _fileText = '';
|
||||
|
||||
Future<void> getFileLines() async {
|
||||
_fileText = await rootBundle.loadString(
|
||||
isMoneroOnly ? 'assets/text/Monerocom_Terms_of_Use.txt' : 'assets/text/Terms_of_Use.txt');
|
||||
setState(() {});
|
||||
void getFileLines() {
|
||||
final fileName =
|
||||
isMoneroOnly ? 'assets/text/Monerocom_Terms_of_Use.txt' : 'assets/text/Terms_of_Use.txt';
|
||||
rootBundle.loadString(fileName).then((text) => setState(() => _fileText = text));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -48,8 +48,8 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async => widget.isReadOnly,
|
||||
return PopScope(
|
||||
canPop: widget.isReadOnly,
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: Column(
|
||||
@@ -121,7 +121,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).colorScheme.surface.withOpacity(0.0),
|
||||
Theme.of(context).colorScheme.surface.withAlpha(0),
|
||||
Theme.of(context).colorScheme.surface,
|
||||
],
|
||||
begin: FractionalOffset.topCenter,
|
||||
@@ -144,11 +144,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||
EdgeInsets.only(left: 24.0, top: 10.0, right: 24.0, bottom: 10.0),
|
||||
child: InkWell(
|
||||
key: ValueKey('disclaimer_check_key'),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_checked = !_checked;
|
||||
});
|
||||
},
|
||||
onTap: () => setState(() =>_checked = !_checked),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class ThirdPartyDisclaimerPage extends BasePage {
|
||||
ThirdPartyDisclaimerPage({this.title = "Disclaimer"});
|
||||
|
||||
@override
|
||||
final String title;
|
||||
|
||||
final String filePath = 'assets/text/disclaimer_deuro.txt';
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => _ThirdPartyDisclaimerPageBody(filePath: filePath);
|
||||
}
|
||||
|
||||
class _ThirdPartyDisclaimerPageBody extends StatefulWidget {
|
||||
_ThirdPartyDisclaimerPageBody({required this.filePath});
|
||||
|
||||
final String filePath;
|
||||
|
||||
@override
|
||||
_ThirdPartyDisclaimerPageBodyState createState() => _ThirdPartyDisclaimerPageBodyState();
|
||||
}
|
||||
|
||||
class _ThirdPartyDisclaimerPageBodyState extends State<_ThirdPartyDisclaimerPageBody> {
|
||||
String _fileText = '';
|
||||
|
||||
void getFileLines() =>
|
||||
rootBundle.loadString(widget.filePath).then((text) => setState(() => _fileText = text));
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
getFileLines();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Container(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
SizedBox(height: 10.0),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
SingleChildScrollView(
|
||||
padding: EdgeInsets.only(left: 24.0, right: 24.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
_fileText,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Container(
|
||||
height: 12,
|
||||
child: ClipRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 0.7, sigmaY: 0.7),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).colorScheme.surface.withAlpha(0),
|
||||
Theme.of(context).colorScheme.surface,
|
||||
],
|
||||
begin: FractionalOffset.topCenter,
|
||||
end: FractionalOffset.bottomCenter,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -139,6 +139,7 @@ class DEuroSavingsPage extends BasePage {
|
||||
|
||||
void _setReactions(BuildContext context, DEuroViewModel dEuroViewModel) {
|
||||
if (_isReactionsSet) return;
|
||||
if (_dEuroViewModel.isFistTime) _showWelcomeTooltip(context);
|
||||
|
||||
reaction((_) => dEuroViewModel.transaction, (PendingTransaction? tx) async {
|
||||
if (tx == null) return;
|
||||
@@ -315,7 +316,7 @@ class DEuroSavingsPage extends BasePage {
|
||||
Future<void> _showWelcomeTooltip(BuildContext context) async {
|
||||
if (!context.mounted) return;
|
||||
|
||||
return showModalBottomSheet<void>(
|
||||
await showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (BuildContext bottomSheetContext) => InfoBottomSheet(
|
||||
@@ -333,8 +334,11 @@ class DEuroSavingsPage extends BasePage {
|
||||
leftButtonText: S.of(context).learn_more,
|
||||
leftActionButtonKey: ValueKey('deuro_page_tooltip_dialog_welcome_learn_more_button_key'),
|
||||
actionLeftButton: () => Navigator.of(bottomSheetContext).pop(), // ToDo
|
||||
showDisclaimerText: _dEuroViewModel.isFistTime,
|
||||
),
|
||||
);
|
||||
|
||||
if (_dEuroViewModel.isFistTime) _dEuroViewModel.acceptDisclaimer();
|
||||
}
|
||||
|
||||
Future<void> _showNoEthTooltip(BuildContext context) async {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/themes/core/material_base_theme.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
@@ -29,6 +31,7 @@ class InfoBottomSheet extends BaseBottomSheet {
|
||||
final String? content;
|
||||
final bool isTwoAction;
|
||||
final bool showDontAskMeCheckbox;
|
||||
final bool showDisclaimerText;
|
||||
final Function(bool)? onCheckboxChanged;
|
||||
final String? actionButtonText;
|
||||
final VoidCallback? actionButton;
|
||||
@@ -52,6 +55,7 @@ class InfoBottomSheet extends BaseBottomSheet {
|
||||
this.content,
|
||||
this.isTwoAction = false,
|
||||
this.showDontAskMeCheckbox = false,
|
||||
this.showDisclaimerText = false,
|
||||
this.height = 200,
|
||||
this.onCheckboxChanged,
|
||||
this.actionButtonText,
|
||||
@@ -106,9 +110,40 @@ class InfoBottomSheet extends BaseBottomSheet {
|
||||
],
|
||||
),
|
||||
),
|
||||
if (showDisclaimerText)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20, bottom: 10),
|
||||
child: RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'By continuing you agree to this ',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'disclaimer',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
decoration: TextDecoration.underline,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => Navigator.pushNamed(context, Routes.readThirdPartyDisclaimer),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (showDontAskMeCheckbox)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 34.0),
|
||||
padding: const EdgeInsets.only(left: 34),
|
||||
child: Row(
|
||||
children: [
|
||||
SimpleCheckbox(onChanged: onCheckboxChanged),
|
||||
|
||||
@@ -87,6 +87,7 @@ abstract class SettingsStoreBase with Store {
|
||||
required Map<WalletType, Node> nodes,
|
||||
required Map<WalletType, Node> powNodes,
|
||||
required this.shouldShowYatPopup,
|
||||
required this.shouldShowDEuroDisclaimer,
|
||||
required this.shouldShowRepWarning,
|
||||
required this.isBitcoinBuyEnabled,
|
||||
required this.actionlistDisplayMode,
|
||||
@@ -251,6 +252,11 @@ abstract class SettingsStoreBase with Store {
|
||||
(bool shouldShowYatPopup) =>
|
||||
sharedPreferences.setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup));
|
||||
|
||||
reaction(
|
||||
(_) => shouldShowDEuroDisclaimer,
|
||||
(bool shouldShowDEuroDisclaimer) =>
|
||||
sharedPreferences.setBool(PreferencesKey.shouldShowDEuroDisclaimer, shouldShowDEuroDisclaimer));
|
||||
|
||||
reaction((_) => shouldShowRepWarning,
|
||||
(bool val) => sharedPreferences.setBool(PreferencesKey.shouldShowRepWarning, val));
|
||||
|
||||
@@ -648,6 +654,9 @@ abstract class SettingsStoreBase with Store {
|
||||
@observable
|
||||
bool shouldShowYatPopup;
|
||||
|
||||
@observable
|
||||
bool shouldShowDEuroDisclaimer;
|
||||
|
||||
@observable
|
||||
bool shouldShowRepWarning;
|
||||
|
||||
@@ -1092,6 +1101,7 @@ abstract class SettingsStoreBase with Store {
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
final deviceName = await _getDeviceName() ?? '';
|
||||
final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
|
||||
final shouldShowDEuroDisclaimer = sharedPreferences.getBool(PreferencesKey.shouldShowDEuroDisclaimer) ?? true;
|
||||
final shouldShowRepWarning =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowRepWarning) ?? true;
|
||||
|
||||
@@ -1363,6 +1373,7 @@ abstract class SettingsStoreBase with Store {
|
||||
initialSyncMode: savedSyncMode,
|
||||
initialSyncAll: savedSyncAll,
|
||||
shouldShowYatPopup: shouldShowYatPopup,
|
||||
shouldShowDEuroDisclaimer: shouldShowDEuroDisclaimer,
|
||||
shouldShowRepWarning: shouldShowRepWarning,
|
||||
initialBuiltinTor: builtinTor,
|
||||
);
|
||||
@@ -1489,6 +1500,8 @@ abstract class SettingsStoreBase with Store {
|
||||
languageCode = sharedPreferences.getString(PreferencesKey.currentLanguageCode) ?? languageCode;
|
||||
shouldShowYatPopup =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? shouldShowYatPopup;
|
||||
shouldShowDEuroDisclaimer =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowDEuroDisclaimer) ?? shouldShowDEuroDisclaimer;
|
||||
shouldShowRepWarning =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowRepWarning) ?? shouldShowRepWarning;
|
||||
sortBalanceBy = SortBalanceBy
|
||||
|
||||
@@ -38,6 +38,12 @@ abstract class DEuroViewModelBase with Store {
|
||||
@computed
|
||||
bool get isFiatDisabled => balanceViewModel.isFiatDisabled;
|
||||
|
||||
@computed
|
||||
bool get isFistTime => _settingsStore.shouldShowDEuroDisclaimer;
|
||||
|
||||
@action
|
||||
void acceptDisclaimer() => _settingsStore.shouldShowDEuroDisclaimer = false;
|
||||
|
||||
@computed
|
||||
String get pendingTransactionFiatAmountFormatted =>
|
||||
isFiatDisabled ? '' : '$pendingTransactionFiatAmount ${fiat.title}';
|
||||
|
||||
Reference in New Issue
Block a user