fully working setting with ease of use option, tests pass

This commit is contained in:
Marco 2022-10-10 17:41:43 -06:00
parent 75d15246ea
commit 7f8392522d
14 changed files with 164 additions and 122 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View file

@ -21,10 +21,10 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart';
class HomeView extends ConsumerStatefulWidget { class HomeView extends ConsumerStatefulWidget {
const HomeView({Key? key}) : super(key: key); const HomeView({Key? key}) : super(key: key);
@ -86,9 +86,8 @@ class _HomeViewState extends ConsumerState<HomeView> {
void _loadCNData() { void _loadCNData() {
// unawaited future // unawaited future
// //
final externalCalls = DB.instance final externalCalls = Prefs.instance.externalCalls;
.get<dynamic>(boxName: DB.boxNamePrefs, key: "externalCalls") as bool?; if (externalCalls) {
if (externalCalls ?? false) {
_cnLoadingService.loadAll(ref); _cnLoadingService.loadAll(ref);
} else { } else {
Logging.instance.log("User does not want to use external calls", Logging.instance.log("User does not want to use external calls",

View file

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
@ -6,8 +8,7 @@ import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/hive/db.dart'; import 'package:stackwallet/utilities/prefs.dart';
import 'package:stackwallet/services/change_now/change_now_loading_service.dart';
class HomeViewButtonBar extends ConsumerStatefulWidget { class HomeViewButtonBar extends ConsumerStatefulWidget {
const HomeViewButtonBar({Key? key}) : super(key: key); const HomeViewButtonBar({Key? key}) : super(key: key);
@ -104,11 +105,9 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
ref.read(homeViewPageIndexStateProvider.state).state = 1; ref.read(homeViewPageIndexStateProvider.state).state = 1;
} }
DateTime now = DateTime.now(); DateTime now = DateTime.now();
// TODO: find out why it infinitely loads final _cnLoadingService = ExchangeDataLoadingService();
final _cnLoadingService = ChangeNowLoadingService(); final externalCalls = Prefs.instance.externalCalls;
final externalCalls = DB.instance.get<dynamic>( if (!externalCalls) {
boxName: DB.boxNamePrefs, key: "externalCalls") as bool?;
if (!(externalCalls ?? false)) {
print("loading?"); print("loading?");
unawaited(_cnLoadingService.loadAll(ref)); unawaited(_cnLoadingService.loadAll(ref));
} }

View file

@ -1,16 +1,16 @@
import 'dart:async';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/pages/stack_privacy_calls.dart'; import 'package:stackwallet/pages/stack_privacy_calls.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:tuple/tuple.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:stackwallet/utilities/prefs.dart';
class IntroView extends StatefulWidget { class IntroView extends StatefulWidget {
const IntroView({Key? key}) : super(key: key); const IntroView({Key? key}) : super(key: key);
@ -244,10 +244,11 @@ class GetStartedButton extends StatelessWidget {
.extension<StackColors>()! .extension<StackColors>()!
.getPrimaryEnabledButtonColor(context), .getPrimaryEnabledButtonColor(context),
onPressed: () { onPressed: () {
unawaited(DB.instance.put<dynamic>( Prefs.instance.externalCalls = true;
boxName: DB.boxNamePrefs, key: "externalCalls", value: true)); Navigator.of(context).pushNamed(
Navigator.of(context) StackPrivacyCalls.routeName,
.pushNamed(StackPrivacyCalls.routeName, arguments: false); arguments: false,
);
}, },
child: Text( child: Text(
"Get started", "Get started",
@ -262,8 +263,10 @@ class GetStartedButton extends StatelessWidget {
.extension<StackColors>()! .extension<StackColors>()!
.getPrimaryEnabledButtonColor(context), .getPrimaryEnabledButtonColor(context),
onPressed: () { onPressed: () {
Navigator.of(context) Navigator.of(context).pushNamed(
.pushNamed(StackPrivacyCalls.routeName, arguments: false); StackPrivacyCalls.routeName,
arguments: false,
);
}, },
child: Text( child: Text(
"Get started", "Get started",

View file

@ -8,9 +8,9 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart'; import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:tuple/tuple.dart';
import '../../../../hive/db.dart'; import 'package:stackwallet/pages/stack_privacy_calls.dart';
import '../../../stack_privacy_calls.dart';
class AdvancedSettingsView extends StatelessWidget { class AdvancedSettingsView extends StatelessWidget {
const AdvancedSettingsView({ const AdvancedSettingsView({
@ -23,10 +23,6 @@ class AdvancedSettingsView extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType"); debugPrint("BUILD: $runtimeType");
final externalCalls = DB.instance
.get<dynamic>(boxName: DB.boxNamePrefs, key: "externalCalls") ??
true;
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background, backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar( appBar: AppBar(
@ -127,45 +123,55 @@ class AdvancedSettingsView extends StatelessWidget {
), ),
RoundedWhiteContainer( RoundedWhiteContainer(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
child: RawMaterialButton( child: Consumer(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, builder: (_, ref, __) {
shape: RoundedRectangleBorder( final externalCalls = ref.watch(
borderRadius: BorderRadius.circular( prefsChangeNotifierProvider
Constants.size.circularBorderRadius, .select((value) => value.externalCalls),
), );
), return RawMaterialButton(
onPressed: () { materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
Navigator.of(context) shape: RoundedRectangleBorder(
.pushNamed(StackPrivacyCalls.routeName, arguments: true); borderRadius: BorderRadius.circular(
}, Constants.size.circularBorderRadius,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 20,
),
child: Row(
children: [
RichText(
textAlign: TextAlign.left,
text: TextSpan(
children: [
TextSpan(
text: "Stack Experience",
style: STextStyles.titleBold12(context),
),
TextSpan(
text: externalCalls as bool
? "\nEasy crypto"
: "\nIncognito",
style: STextStyles.label(context)
.copyWith(fontSize: 15.0),
)
],
),
), ),
], ),
), onPressed: () {
), Navigator.of(context).pushNamed(
StackPrivacyCalls.routeName,
arguments: true,
);
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 20,
),
child: Row(
children: [
RichText(
textAlign: TextAlign.left,
text: TextSpan(
children: [
TextSpan(
text: "Stack Experience",
style: STextStyles.titleBold12(context),
),
TextSpan(
text: externalCalls
? "\nEasy crypto"
: "\nIncognito",
style: STextStyles.label(context)
.copyWith(fontSize: 15.0),
)
],
),
),
],
),
),
);
},
), ),
), ),
], ],

View file

@ -10,6 +10,9 @@ import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/utilities/prefs.dart';
class StackPrivacyCalls extends ConsumerStatefulWidget { class StackPrivacyCalls extends ConsumerStatefulWidget {
const StackPrivacyCalls({ const StackPrivacyCalls({
Key? key, Key? key,
@ -26,7 +29,7 @@ class StackPrivacyCalls extends ConsumerStatefulWidget {
class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> { class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
late final bool isDesktop; late final bool isDesktop;
bool isEasy = true; bool isEasy = Prefs.instance.externalCalls;
final PageController _pageController = final PageController _pageController =
PageController(initialPage: 0, keepPage: true); PageController(initialPage: 0, keepPage: true);
@ -78,11 +81,19 @@ class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
height: 36, height: 36,
), ),
Center( Center(
child: CustomRadio((bool isEasy) { child: Consumer(
setState(() { builder: (_, ref, __) {
this.isEasy = isEasy; final externalCalls = ref.watch(
}); prefsChangeNotifierProvider
}), .select((value) => value.externalCalls),
);
return CustomRadio((bool isEasy) {
setState(() {
this.isEasy = isEasy;
});
}, externalCalls);
},
),
), ),
const SizedBox( const SizedBox(
height: 36, height: 36,
@ -191,11 +202,7 @@ class ContinueButton extends StatelessWidget {
print("Output of isEasy:"); print("Output of isEasy:");
print(isEasy); print(isEasy);
DB.instance.put<dynamic>( Prefs.instance.externalCalls = isEasy;
boxName: DB.boxNamePrefs,
key: "externalCalls",
value: isEasy,
);
if (!isSettings) { if (!isSettings) {
Navigator.of(context).pushNamed(CreatePinView.routeName); Navigator.of(context).pushNamed(CreatePinView.routeName);
} }
@ -216,14 +223,10 @@ class ContinueButton extends StatelessWidget {
print("Output of isEasy:"); print("Output of isEasy:");
print(isEasy); print(isEasy);
DB.instance.put<dynamic>( Prefs.instance.externalCalls = isEasy;
boxName: DB.boxNamePrefs,
key: "externalCalls",
value: isEasy,
);
if (!isSettings) { if (!isSettings) {
Navigator.of(context).pushNamed(StackPrivacyCalls.routeName); Navigator.of(context).pushNamed(CreatePinView.routeName);
} }
}, },
child: Text( child: Text(
@ -236,8 +239,9 @@ class ContinueButton extends StatelessWidget {
} }
class CustomRadio extends StatefulWidget { class CustomRadio extends StatefulWidget {
CustomRadio(this.upperCall, {Key? key}) : super(key: key); CustomRadio(this.upperCall, this.isEasy, {Key? key}) : super(key: key);
bool isEasy;
Function upperCall; Function upperCall;
@override @override
@ -252,10 +256,10 @@ class CustomRadioState extends State<CustomRadio> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
sampleData.add(
RadioModel(true, Assets.svg.personaEasy, 'Easy Crypto', 'Recommended'));
sampleData.add(RadioModel( sampleData.add(RadioModel(
false, Assets.svg.personaIncognito, 'Incognito', 'Privacy conscious')); widget.isEasy, Assets.svg.personaEasy, 'Easy Crypto', 'Recommended'));
sampleData.add(RadioModel(!widget.isEasy, Assets.svg.personaIncognito,
'Incognito', 'Privacy conscious'));
} }
@override @override

View file

@ -49,6 +49,8 @@ import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart';
/// [eventBus] should only be set during testing /// [eventBus] should only be set during testing
class WalletView extends ConsumerStatefulWidget { class WalletView extends ConsumerStatefulWidget {
const WalletView({ const WalletView({
@ -233,6 +235,12 @@ class _WalletViewState extends ConsumerState<WalletView> {
} }
void _onExchangePressed(BuildContext context) async { void _onExchangePressed(BuildContext context) async {
final _cnLoadingService = ExchangeDataLoadingService();
final externalCalls = Prefs.instance.externalCalls;
if (!externalCalls) {
print("loading?");
unawaited(_cnLoadingService.loadAll(ref));
}
final coin = ref.read(managerProvider).coin; final coin = ref.read(managerProvider).coin;
if (coin == Coin.epicCash) { if (coin == Coin.epicCash) {

View file

@ -9,6 +9,8 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import 'package:stackwallet/utilities/prefs.dart';
class PriceAPI { class PriceAPI {
static const refreshInterval = 60; static const refreshInterval = 60;
@ -76,9 +78,8 @@ class PriceAPI {
return _cachedPrices; return _cachedPrices;
} }
final externalCalls = DB.instance final externalCalls = Prefs.instance.externalCalls;
.get<dynamic>(boxName: DB.boxNamePrefs, key: "externalCalls") as bool?; if (!externalCalls) {
if (!(externalCalls ?? false)) {
Logging.instance.log("User does not want to use external calls", Logging.instance.log("User does not want to use external calls",
level: LogLevel.Info); level: LogLevel.Info);
return _cachedPrices; return _cachedPrices;
@ -122,10 +123,8 @@ class PriceAPI {
} }
static Future<List<String>?> availableBaseCurrencies() async { static Future<List<String>?> availableBaseCurrencies() async {
final externalCalls = DB.instance final externalCalls = Prefs.instance.externalCalls;
.get<dynamic>(boxName: DB.boxNamePrefs, key: "externalCalls") as bool?; if (!externalCalls) {
print("externalCalls hi2 $externalCalls");
if (!(externalCalls ?? false)) {
Logging.instance.log("User does not want to use external calls", Logging.instance.log("User does not want to use external calls",
level: LogLevel.Info); level: LogLevel.Info);
return null; return null;

View file

@ -36,6 +36,7 @@ class Prefs extends ChangeNotifier {
_hideBlockExplorerWarning = await _getHideBlockExplorerWarning(); _hideBlockExplorerWarning = await _getHideBlockExplorerWarning();
_gotoWalletOnStartup = await _getGotoWalletOnStartup(); _gotoWalletOnStartup = await _getGotoWalletOnStartup();
_startupWalletId = await _getStartupWalletId(); _startupWalletId = await _getStartupWalletId();
_externalCalls = await _getExternalCalls();
_initialized = true; _initialized = true;
} }
@ -179,6 +180,27 @@ class Prefs extends ChangeNotifier {
false; false;
} }
// external calls
bool _externalCalls = true;
bool get externalCalls => _externalCalls;
set externalCalls(bool eCalls) {
if (_externalCalls != eCalls) {
DB.instance.put<dynamic>(
boxName: DB.boxNamePrefs, key: "externalCalls", value: eCalls);
_externalCalls = eCalls;
notifyListeners();
}
}
Future<bool> _getExternalCalls() async {
return await DB.instance.get<dynamic>(
boxName: DB.boxNamePrefs, key: "externalCalls") as bool? ??
true;
}
// show favorites // show favorites
bool _showFavoriteWallets = true; bool _showFavoriteWallets = true;

View file

@ -276,6 +276,14 @@ class MockPrefs extends _i1.Mock implements _i5.Prefs {
super.noSuchMethod(Invocation.setter(#wifiOnly, wifiOnly), super.noSuchMethod(Invocation.setter(#wifiOnly, wifiOnly),
returnValueForMissingStub: null); returnValueForMissingStub: null);
@override @override
bool get externalCalls =>
(super.noSuchMethod(Invocation.getter(#externalCalls), returnValue: false)
as bool);
@override
set externalCalls(bool? eCalls) =>
super.noSuchMethod(Invocation.setter(#externalCalls, eCalls),
returnValueForMissingStub: null);
@override
bool get showFavoriteWallets => bool get showFavoriteWallets =>
(super.noSuchMethod(Invocation.getter(#showFavoriteWallets), (super.noSuchMethod(Invocation.getter(#showFavoriteWallets),
returnValue: false) as bool); returnValue: false) as bool);

View file

@ -125,6 +125,14 @@ class MockPrefs extends _i1.Mock implements _i4.Prefs {
super.noSuchMethod(Invocation.setter(#wifiOnly, wifiOnly), super.noSuchMethod(Invocation.setter(#wifiOnly, wifiOnly),
returnValueForMissingStub: null); returnValueForMissingStub: null);
@override @override
bool get externalCalls =>
(super.noSuchMethod(Invocation.getter(#externalCalls), returnValue: false)
as bool);
@override
set externalCalls(bool? eCalls) =>
super.noSuchMethod(Invocation.setter(#externalCalls, eCalls),
returnValueForMissingStub: null);
@override
bool get showFavoriteWallets => bool get showFavoriteWallets =>
(super.noSuchMethod(Invocation.getter(#showFavoriteWallets), (super.noSuchMethod(Invocation.getter(#showFavoriteWallets),
returnValue: false) as bool); returnValue: false) as bool);

View file

@ -10,6 +10,8 @@
// //
// import 'estimated_rate_exchange_form_state_test.mocks.dart'; // import 'estimated_rate_exchange_form_state_test.mocks.dart';
// //
void main() {}
// @GenerateMocks([ChangeNowAPI]) // @GenerateMocks([ChangeNowAPI])
// void main() { // void main() {
// final currencyA = Currency( // final currencyA = Currency(

View file

@ -107,6 +107,14 @@ class MockPrefs extends _i1.Mock implements _i3.Prefs {
super.noSuchMethod(Invocation.setter(#wifiOnly, wifiOnly), super.noSuchMethod(Invocation.setter(#wifiOnly, wifiOnly),
returnValueForMissingStub: null); returnValueForMissingStub: null);
@override @override
bool get externalCalls =>
(super.noSuchMethod(Invocation.getter(#externalCalls), returnValue: false)
as bool);
@override
set externalCalls(bool? eCalls) =>
super.noSuchMethod(Invocation.setter(#externalCalls, eCalls),
returnValueForMissingStub: null);
@override
bool get showFavoriteWallets => bool get showFavoriteWallets =>
(super.noSuchMethod(Invocation.getter(#showFavoriteWallets), (super.noSuchMethod(Invocation.getter(#showFavoriteWallets),
returnValue: false) as bool); returnValue: false) as bool);

View file

@ -8,6 +8,7 @@ import 'package:mockito/mockito.dart';
import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart'; import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'; import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'; import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
import 'package:stackwallet/models/exchange/response_objects/pair.dart'; import 'package:stackwallet/models/exchange/response_objects/pair.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_api.dart'; import 'package:stackwallet/services/exchange/change_now/change_now_api.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart'; import 'package:stackwallet/services/exchange/exchange_response.dart';
@ -290,7 +291,7 @@ void main() {
expect(result.exception, null); expect(result.exception, null);
expect(result.value == null, false); expect(result.value == null, false);
expect(result.value, isA<EstimatedExchangeAmount>()); expect(result.value, isA<Estimate>());
}); });
test( test(
@ -574,7 +575,7 @@ void main() {
"https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"), "https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: body:
'{"from":"btc","to":"eth","address":"0x57f31ad4b64095347F87eDB1675566DAfF5EC886","amount":"0.3","flow":"fixed-rate","extraId":"","userId":"","contactEmail":"","refundAddress":"","refundExtraId":"","rateId":""}', '{"from":"btc","to":"eth","address":"0x57f31ad4b64095347F87eDB1675566DAfF5EC886","flow":"fixed-rate","extraId":"","userId":"","contactEmail":"","refundAddress":"","refundExtraId":"","rateId":"","amount":"0.3"}',
encoding: null, encoding: null,
)).thenAnswer((realInvocation) async => Response( )).thenAnswer((realInvocation) async => Response(
'{"payinAddress": "33eFX2jfeWbXMSmRe9ewUUTrmSVSxZi5cj", "payoutAddress": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886","payoutExtraId": "", "fromCurrency": "btc", "toCurrency": "eth", "refundAddress": "","refundExtraId": "","validUntil": "2019-09-09T14:01:04.921Z","id": "a5c73e2603f40d","amount": 62.9737711}', '{"payinAddress": "33eFX2jfeWbXMSmRe9ewUUTrmSVSxZi5cj", "payoutAddress": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886","payoutExtraId": "", "fromCurrency": "btc", "toCurrency": "eth", "refundAddress": "","refundExtraId": "","validUntil": "2019-09-09T14:01:04.921Z","id": "a5c73e2603f40d","amount": 62.9737711}',
@ -625,8 +626,7 @@ void main() {
reversed: false, reversed: false,
); );
expect( expect(result.exception!.type, ExchangeExceptionType.generic);
result.exception!.type, ExchangeExceptionType.serializeResponseError);
expect(result.value == null, true); expect(result.value == null, true);
}); });