stack_wallet/lib/pages/home_view/home_view.dart

428 lines
14 KiB
Dart
Raw Normal View History

2023-05-26 21:21:16 +00:00
/*
* This file is part of Stack Wallet.
*
* Copyright (c) 2023 Cypher Stack
* All Rights Reserved.
* The code is distributed under GPLv3 license, see LICENSE file for details.
* Generated by Cypher Stack on 2023-05-26
*
*/
2022-08-26 08:11:35 +00:00
import 'dart:async';
import 'dart:io';
2022-08-26 08:11:35 +00:00
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import '../../app_config.dart';
import '../../providers/global/notifications_provider.dart';
import '../../providers/global/prefs_provider.dart';
import '../../providers/ui/home_view_index_provider.dart';
import '../../providers/ui/unread_notifications_provider.dart';
import '../../services/event_bus/events/global/tor_connection_status_changed_event.dart';
import '../../themes/stack_colors.dart';
import '../../themes/theme_providers.dart';
import '../../utilities/assets.dart';
import '../../utilities/constants.dart';
import '../../utilities/text_styles.dart';
import '../../widgets/animated_widgets/rotate_icon.dart';
import '../../widgets/app_icon.dart';
import '../../widgets/background.dart';
import '../../widgets/custom_buttons/app_bar_icon_button.dart';
import '../../widgets/small_tor_icon.dart';
import '../../widgets/stack_dialog.dart';
import '../buy_view/buy_view.dart';
import '../exchange_view/exchange_view.dart';
import '../notification_views/notifications_view.dart';
import '../settings_views/global_settings_view/global_settings_view.dart';
import '../settings_views/global_settings_view/hidden_settings.dart';
import '../wallets_view/wallets_view.dart';
import 'sub_widgets/home_view_button_bar.dart';
2022-08-26 08:11:35 +00:00
class HomeView extends ConsumerStatefulWidget {
const HomeView({super.key});
2022-08-26 08:11:35 +00:00
static const routeName = "/home";
@override
ConsumerState<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends ConsumerState<HomeView> {
final GlobalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>();
late final PageController _pageController;
2023-03-03 17:27:20 +00:00
late final RotateIconController _rotateIconController;
2022-08-26 08:11:35 +00:00
late final List<Widget> _children;
DateTime? _cachedTime;
bool _exitEnabled = false;
late TorConnectionStatus _currentSyncStatus;
2023-09-05 19:11:08 +00:00
2023-01-14 17:22:48 +00:00
// final _buyDataLoadingService = BuyDataLoadingService();
2022-09-09 14:03:36 +00:00
2022-08-26 08:11:35 +00:00
Future<bool> _onWillPop() async {
// go to home view when tapping back on the main exchange view
2023-02-01 00:14:06 +00:00
if (ref.read(homeViewPageIndexStateProvider.state).state != 0) {
ref.read(homeViewPageIndexStateProvider.state).state = 0;
return false;
}
2022-08-26 08:11:35 +00:00
if (_exitEnabled) {
return true;
}
final now = DateTime.now();
const timeout = Duration(milliseconds: 1500);
if (_cachedTime == null || now.difference(_cachedTime!) > timeout) {
_cachedTime = now;
await showDialog<dynamic>(
context: context,
barrierDismissible: false,
builder: (_) => WillPopScope(
onWillPop: () async {
_exitEnabled = true;
return true;
},
child: const StackDialog(title: "Tap back again to exit"),
),
).timeout(
timeout,
onTimeout: () {
_exitEnabled = false;
Navigator.of(context).pop();
},
);
}
return _exitEnabled;
}
2023-01-14 17:22:48 +00:00
// void _loadSimplexData() {
// // unawaited future
// if (ref.read(prefsChangeNotifierProvider).externalCalls) {
// _buyDataLoadingService.loadAll(ref);
// } else {
// Logging.instance.log("User does not want to use external calls",
// level: LogLevel.Info);
// }
// }
2023-01-12 00:13:34 +00:00
bool _lock = false;
Future<void> _animateToPage(int index) async {
await _pageController.animateToPage(
index,
duration: const Duration(milliseconds: 300),
curve: Curves.decelerate,
);
}
2022-08-26 08:11:35 +00:00
@override
void initState() {
_pageController = PageController();
2023-03-03 17:27:20 +00:00
_rotateIconController = RotateIconController();
2022-08-26 08:11:35 +00:00
_children = [
const WalletsView(),
if (AppConfig.hasFeature(AppFeature.swap) && Constants.enableExchange)
const ExchangeView(),
if (AppConfig.hasFeature(AppFeature.buy) && Constants.enableExchange)
const BuyView(),
2022-08-26 08:11:35 +00:00
];
ref.read(notificationsProvider).startCheckingWatchedNotifications();
2024-01-04 17:28:38 +00:00
// WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
// showOneTimeTorHasBeenAddedDialogIfRequired(context);
// });
2023-09-05 19:11:08 +00:00
2022-08-26 08:11:35 +00:00
super.initState();
}
@override
dispose() {
_pageController.dispose();
2023-03-03 17:27:20 +00:00
_rotateIconController.forward = null;
_rotateIconController.reverse = null;
_rotateIconController.reset = null;
2022-08-26 08:11:35 +00:00
super.dispose();
}
DateTime _hiddenTime = DateTime.now();
int _hiddenCount = 0;
void _hiddenOptions() {
2023-03-03 17:27:20 +00:00
_rotateIconController.reset?.call();
_rotateIconController.forward?.call();
2022-08-26 08:11:35 +00:00
if (_hiddenCount == 5) {
Navigator.of(context).pushNamed(HiddenSettings.routeName);
}
final now = DateTime.now();
const timeout = Duration(seconds: 1);
if (now.difference(_hiddenTime) < timeout) {
_hiddenCount++;
} else {
_hiddenCount = 0;
}
_hiddenTime = now;
}
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
// dirty hack
ref.listen(
prefsChangeNotifierProvider.select((value) => value.enableExchange),
(prev, next) {
if (next == false &&
mounted &&
ref.read(homeViewPageIndexStateProvider) != 0) {
WidgetsBinding.instance.addPostFrameCallback(
(_) => ref.read(homeViewPageIndexStateProvider.state).state = 0,
);
}
});
2022-08-26 08:11:35 +00:00
return WillPopScope(
onWillPop: _onWillPop,
child: Background(
child: Scaffold(
backgroundColor: Colors.transparent,
key: _key,
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor:
Theme.of(context).extension<StackColors>()!.backgroundAppBar,
title: Row(
children: [
GestureDetector(
onTap: _hiddenOptions,
2023-03-03 17:27:20 +00:00
child: RotateIcon(
icon: const AppIcon(
2023-03-03 17:27:20 +00:00
width: 24,
height: 24,
),
curve: Curves.easeInOutCubic,
rotationPercent: 1.0,
controller: _rotateIconController,
2022-08-26 08:11:35 +00:00
),
),
const SizedBox(
width: 16,
),
Text(
"My ${AppConfig.prefix}",
style: STextStyles.navBarTitle(context),
2024-05-27 23:56:22 +00:00
),
],
),
actions: [
2023-09-13 16:11:14 +00:00
const Padding(
padding: EdgeInsets.only(
top: 10,
bottom: 10,
right: 10,
),
2023-09-05 19:11:08 +00:00
child: AspectRatio(
aspectRatio: 1,
2023-09-13 16:11:14 +00:00
child: SmallTorIcon(),
2023-09-05 19:11:08 +00:00
),
),
Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
right: 10,
),
child: AspectRatio(
aspectRatio: 1,
child: AppBarIconButton(
semanticsLabel:
"Notifications Button. Takes To Notifications Page.",
key: const Key("walletsViewAlertsButton"),
size: 36,
shadows: const [],
color: Theme.of(context)
.extension<StackColors>()!
.backgroundAppBar,
2024-05-27 23:56:22 +00:00
icon: ref.watch(
notificationsProvider
.select((value) => value.hasUnreadNotifications),
)
? SvgPicture.file(
File(
ref.watch(
themeProvider.select(
(value) => value.assets.bellNew,
),
2023-04-24 14:38:17 +00:00
),
),
width: 20,
height: 20,
2024-05-27 23:56:22 +00:00
color: ref.watch(
notificationsProvider.select(
(value) => value.hasUnreadNotifications,
),
)
? null
: Theme.of(context)
.extension<StackColors>()!
.topNavIconPrimary,
)
: SvgPicture.asset(
Assets.svg.bell,
width: 20,
height: 20,
2024-05-27 23:56:22 +00:00
color: ref.watch(
notificationsProvider.select(
(value) => value.hasUnreadNotifications,
),
)
? null
: Theme.of(context)
.extension<StackColors>()!
.topNavIconPrimary,
),
onPressed: () {
// reset unread state
ref.refresh(unreadNotificationsStateProvider);
2022-08-26 08:11:35 +00:00
Navigator.of(context)
.pushNamed(NotificationsView.routeName)
.then((_) {
final Set<int> unreadNotificationIds = ref
.read(unreadNotificationsStateProvider.state)
.state;
if (unreadNotificationIds.isEmpty) return;
2022-08-26 08:11:35 +00:00
2024-05-27 23:56:22 +00:00
final List<Future<void>> futures = [];
for (int i = 0;
i < unreadNotificationIds.length - 1;
i++) {
2024-05-27 23:56:22 +00:00
futures.add(
ref.read(notificationsProvider).markAsRead(
unreadNotificationIds.elementAt(i),
false,
),
);
}
2022-08-26 08:11:35 +00:00
// wait for multiple to update if any
Future.wait(futures).then((_) {
// only notify listeners once
ref
.read(notificationsProvider)
.markAsRead(unreadNotificationIds.last, true);
});
2022-08-26 08:11:35 +00:00
});
},
),
2022-08-26 08:11:35 +00:00
),
),
Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
right: 10,
),
child: AspectRatio(
aspectRatio: 1,
child: AppBarIconButton(
semanticsLabel: "Settings Button. Takes To Settings Page.",
key: const Key("walletsViewSettingsButton"),
size: 36,
shadows: const [],
color: Theme.of(context)
.extension<StackColors>()!
.backgroundAppBar,
icon: SvgPicture.asset(
Assets.svg.gear,
color: Theme.of(context)
.extension<StackColors>()!
.topNavIconPrimary,
width: 20,
height: 20,
),
onPressed: () {
2022-12-13 00:17:02 +00:00
//todo: check if print needed
// debugPrint("main view settings tapped");
Navigator.of(context)
.pushNamed(GlobalSettingsView.routeName);
},
2022-08-26 08:11:35 +00:00
),
),
),
],
),
body: Column(
2022-08-26 08:11:35 +00:00
children: [
if (_children.length > 1 &&
ref.watch(prefsChangeNotifierProvider).enableExchange)
2022-08-26 08:11:35 +00:00
Container(
2022-09-21 00:46:07 +00:00
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.backgroundAppBar,
boxShadow: Theme.of(context)
.extension<StackColors>()!
.homeViewButtonBarBoxShadow !=
null
? [
Theme.of(context)
.extension<StackColors>()!
.homeViewButtonBarBoxShadow!,
]
: null,
2022-08-26 08:11:35 +00:00
),
child: const Padding(
padding: EdgeInsets.only(
left: 16,
bottom: 12,
right: 16,
top: 0,
),
child: HomeViewButtonBar(),
),
),
Expanded(
child: Consumer(
builder: (_, _ref, __) {
_ref.listen(homeViewPageIndexStateProvider,
(previous, next) {
if (next is int && next >= 0 && next <= 2) {
// if (next == 1) {
// _exchangeDataLoadingService.loadAll(ref);
// }
2023-01-14 17:22:48 +00:00
// if (next == 2) {
// _buyDataLoadingService.loadAll(ref);
// }
_lock = true;
_animateToPage(next).then((value) => _lock = false);
2022-08-26 08:11:35 +00:00
}
});
return PageView(
controller: _pageController,
children: _children,
onPageChanged: (pageIndex) {
if (!_lock) {
ref.read(homeViewPageIndexStateProvider.state).state =
pageIndex;
}
2022-08-26 08:11:35 +00:00
},
);
},
),
),
],
),
),
),
);
}
}