mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-24 12:29:37 +00:00
commit
cb4ba48d5d
17 changed files with 1154 additions and 160 deletions
|
@ -76,11 +76,17 @@ void main() async {
|
||||||
Util.libraryPath = await getLibraryDirectory();
|
Util.libraryPath = await getLibraryDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Screen? screen;
|
||||||
|
if (Platform.isLinux || Util.isDesktop) {
|
||||||
|
screen = await getCurrentScreen();
|
||||||
|
Util.screenWidth = screen?.frame.width;
|
||||||
|
}
|
||||||
|
|
||||||
if (Util.isDesktop) {
|
if (Util.isDesktop) {
|
||||||
setWindowTitle('Stack Wallet');
|
setWindowTitle('Stack Wallet');
|
||||||
setWindowMinSize(const Size(1220, 100));
|
setWindowMinSize(const Size(1220, 100));
|
||||||
setWindowMaxSize(Size.infinite);
|
setWindowMaxSize(Size.infinite);
|
||||||
final screen = await getCurrentScreen();
|
|
||||||
final screenHeight = screen?.frame.height;
|
final screenHeight = screen?.frame.height;
|
||||||
if (screenHeight != null) {
|
if (screenHeight != null) {
|
||||||
// starting to height be 3/4 screen height or 900, whichever is smaller
|
// starting to height be 3/4 screen height or 900, whichever is smaller
|
||||||
|
@ -312,17 +318,17 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
||||||
final colorScheme = DB.instance
|
final colorScheme = DB.instance
|
||||||
.get<dynamic>(boxName: DB.boxNameTheme, key: "colorScheme") as String?;
|
.get<dynamic>(boxName: DB.boxNameTheme, key: "colorScheme") as String?;
|
||||||
|
|
||||||
ThemeType themeType;
|
StackColorTheme colorTheme;
|
||||||
switch (colorScheme) {
|
switch (colorScheme) {
|
||||||
case "dark":
|
case "dark":
|
||||||
themeType = ThemeType.dark;
|
colorTheme = DarkColors();
|
||||||
break;
|
break;
|
||||||
case "oceanBreeze":
|
case "oceanBreeze":
|
||||||
themeType = ThemeType.oceanBreeze;
|
colorTheme = OceanBreezeColors();
|
||||||
break;
|
break;
|
||||||
case "light":
|
case "light":
|
||||||
default:
|
default:
|
||||||
themeType = ThemeType.light;
|
colorTheme = LightColors();
|
||||||
}
|
}
|
||||||
loadingCompleter = Completer();
|
loadingCompleter = Completer();
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
@ -333,11 +339,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
ref.read(colorThemeProvider.state).state =
|
ref.read(colorThemeProvider.state).state =
|
||||||
StackColors.fromStackColorTheme(themeType == ThemeType.dark
|
StackColors.fromStackColorTheme(colorTheme);
|
||||||
? DarkColors()
|
|
||||||
: (themeType == ThemeType.light
|
|
||||||
? LightColors()
|
|
||||||
: OceanBreezeColors()));
|
|
||||||
|
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
// fetch open file if it exists
|
// fetch open file if it exists
|
||||||
|
|
|
@ -23,6 +23,8 @@ 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/desktop/desktop_app_bar.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_date_picker/flutter_rounded_date_picker_widget.dart'
|
||||||
|
as datePicker;
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
|
@ -152,10 +154,10 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
||||||
await Future<void>.delayed(const Duration(milliseconds: 125));
|
await Future<void>.delayed(const Duration(milliseconds: 125));
|
||||||
}
|
}
|
||||||
|
|
||||||
final date = await showRoundedDatePicker(
|
final date = await datePicker.showRoundedDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: DateTime.now(),
|
initialDate: DateTime.now(),
|
||||||
height: height / 3.2,
|
height: height * 0.5,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
primarySwatch: Util.createMaterialColor(fetchedColor),
|
primarySwatch: Util.createMaterialColor(fetchedColor),
|
||||||
),
|
),
|
||||||
|
|
|
@ -25,6 +25,9 @@ import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart';
|
||||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||||
|
|
||||||
|
import '../../../../../pages_desktop_specific/home/desktop_home_view.dart';
|
||||||
|
import '../../../../../pages_desktop_specific/home/desktop_menu.dart';
|
||||||
|
import '../../../../../providers/desktop/current_desktop_menu_item.dart';
|
||||||
import '../../../../../widgets/desktop/primary_button.dart';
|
import '../../../../../widgets/desktop/primary_button.dart';
|
||||||
|
|
||||||
class StackRestoreProgressView extends ConsumerStatefulWidget {
|
class StackRestoreProgressView extends ConsumerStatefulWidget {
|
||||||
|
@ -685,7 +688,19 @@ class _StackRestoreProgressViewState
|
||||||
enabled: true,
|
enabled: true,
|
||||||
label: "Done",
|
label: "Done",
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.of(context).pop();
|
DesktopMenuItemId keyID =
|
||||||
|
DesktopMenuItemId.myStack;
|
||||||
|
|
||||||
|
ref
|
||||||
|
.read(currentDesktopMenuItemProvider
|
||||||
|
.state)
|
||||||
|
.state = keyID;
|
||||||
|
|
||||||
|
Navigator.of(context, rootNavigator: true)
|
||||||
|
.popUntil(
|
||||||
|
ModalRoute.withName(
|
||||||
|
DesktopHomeView.routeName),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: SecondaryButton(
|
: SecondaryButton(
|
||||||
|
|
|
@ -49,6 +49,8 @@ class _FavoriteCardState extends ConsumerState<FavoriteCard> {
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _hovering = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final coin = ref.watch(managerProvider.select((value) => value.coin));
|
final coin = ref.watch(managerProvider.select((value) => value.coin));
|
||||||
|
@ -59,7 +61,48 @@ class _FavoriteCardState extends ConsumerState<FavoriteCard> {
|
||||||
condition: Util.isDesktop,
|
condition: Util.isDesktop,
|
||||||
builder: (child) => MouseRegion(
|
builder: (child) => MouseRegion(
|
||||||
cursor: SystemMouseCursors.click,
|
cursor: SystemMouseCursors.click,
|
||||||
child: child,
|
onEnter: (_) {
|
||||||
|
setState(() {
|
||||||
|
_hovering = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onExit: (_) {
|
||||||
|
setState(() {
|
||||||
|
_hovering = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: AnimatedScale(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
scale: _hovering ? 1.05 : 1,
|
||||||
|
child: AnimatedContainer(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
decoration: _hovering
|
||||||
|
? BoxDecoration(
|
||||||
|
color: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
boxShadow: [
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.standardBoxShadow,
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.standardBoxShadow,
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.standardBoxShadow,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: BoxDecoration(
|
||||||
|
color: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
|
|
@ -9,12 +9,19 @@ import 'package:stackwallet/pages_desktop_specific/home/notifications/desktop_no
|
||||||
import 'package:stackwallet/pages_desktop_specific/home/support_and_about_view/desktop_about_view.dart';
|
import 'package:stackwallet/pages_desktop_specific/home/support_and_about_view/desktop_about_view.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/home/support_and_about_view/desktop_support_view.dart';
|
import 'package:stackwallet/pages_desktop_specific/home/support_and_about_view/desktop_support_view.dart';
|
||||||
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart';
|
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart';
|
||||||
|
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
|
||||||
import 'package:stackwallet/providers/global/notifications_provider.dart';
|
import 'package:stackwallet/providers/global/notifications_provider.dart';
|
||||||
|
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||||
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
|
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
|
||||||
import 'package:stackwallet/providers/ui/unread_notifications_provider.dart';
|
import 'package:stackwallet/providers/ui/unread_notifications_provider.dart';
|
||||||
import 'package:stackwallet/route_generator.dart';
|
import 'package:stackwallet/route_generator.dart';
|
||||||
|
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
|
||||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
import 'package:stackwallet/widgets/background.dart';
|
import 'package:stackwallet/widgets/background.dart';
|
||||||
|
|
||||||
|
final currentWalletIdProvider = StateProvider<String?>((_) => null);
|
||||||
|
|
||||||
class DesktopHomeView extends ConsumerStatefulWidget {
|
class DesktopHomeView extends ConsumerStatefulWidget {
|
||||||
const DesktopHomeView({Key? key}) : super(key: key);
|
const DesktopHomeView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@ -25,12 +32,25 @@ class DesktopHomeView extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DesktopHomeViewState extends ConsumerState<DesktopHomeView> {
|
class _DesktopHomeViewState extends ConsumerState<DesktopHomeView> {
|
||||||
final Map<DesktopMenuItemId, Widget> contentViews = {
|
final GlobalKey key = GlobalKey<NavigatorState>();
|
||||||
DesktopMenuItemId.myStack: const Navigator(
|
late final Navigator myStackViewNav;
|
||||||
key: Key("desktopStackHomeKey"),
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
myStackViewNav = Navigator(
|
||||||
|
key: key,
|
||||||
onGenerateRoute: RouteGenerator.generateRoute,
|
onGenerateRoute: RouteGenerator.generateRoute,
|
||||||
initialRoute: MyStackView.routeName,
|
initialRoute: MyStackView.routeName,
|
||||||
),
|
);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<DesktopMenuItemId, Widget> contentViews = {
|
||||||
|
DesktopMenuItemId.myStack: Container(
|
||||||
|
// key: Key("desktopStackHomeKey"),
|
||||||
|
// onGenerateRoute: RouteGenerator.generateRoute,
|
||||||
|
// initialRoute: MyStackView.routeName,
|
||||||
|
),
|
||||||
DesktopMenuItemId.exchange: const Navigator(
|
DesktopMenuItemId.exchange: const Navigator(
|
||||||
key: Key("desktopExchangeHomeKey"),
|
key: Key("desktopExchangeHomeKey"),
|
||||||
onGenerateRoute: RouteGenerator.generateRoute,
|
onGenerateRoute: RouteGenerator.generateRoute,
|
||||||
|
@ -63,7 +83,30 @@ class _DesktopHomeViewState extends ConsumerState<DesktopHomeView> {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DesktopMenuItemId prev = DesktopMenuItemId.myStack;
|
||||||
|
|
||||||
void onMenuSelectionWillChange(DesktopMenuItemId newKey) {
|
void onMenuSelectionWillChange(DesktopMenuItemId newKey) {
|
||||||
|
if (prev == DesktopMenuItemId.myStack && prev == newKey) {
|
||||||
|
Navigator.of(key.currentContext!)
|
||||||
|
.popUntil(ModalRoute.withName(MyStackView.routeName));
|
||||||
|
if (ref.read(currentWalletIdProvider.state).state != null) {
|
||||||
|
final managerProvider = ref
|
||||||
|
.read(walletsChangeNotifierProvider)
|
||||||
|
.getManagerProvider(ref.read(currentWalletIdProvider.state).state!);
|
||||||
|
if (ref.read(managerProvider).shouldAutoSync) {
|
||||||
|
ref.read(managerProvider).shouldAutoSync = false;
|
||||||
|
}
|
||||||
|
ref.read(transactionFilterProvider.state).state = null;
|
||||||
|
if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled &&
|
||||||
|
ref.read(prefsChangeNotifierProvider).backupFrequencyType ==
|
||||||
|
BackupFrequencyType.afterClosingAWallet) {
|
||||||
|
ref.read(autoSWBServiceProvider).doBackup();
|
||||||
|
}
|
||||||
|
ref.read(managerProvider.notifier).isActiveWallet = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = newKey;
|
||||||
|
|
||||||
// check for unread notifications and refresh provider before
|
// check for unread notifications and refresh provider before
|
||||||
// showing notifications view
|
// showing notifications view
|
||||||
if (newKey == DesktopMenuItemId.notifications) {
|
if (newKey == DesktopMenuItemId.notifications) {
|
||||||
|
@ -111,9 +154,25 @@ class _DesktopHomeViewState extends ConsumerState<DesktopHomeView> {
|
||||||
color: Theme.of(context).extension<StackColors>()!.background,
|
color: Theme.of(context).extension<StackColors>()!.background,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: contentViews[
|
child: IndexedStack(
|
||||||
ref.watch(currentDesktopMenuItemProvider.state).state]!,
|
index: ref
|
||||||
|
.watch(currentDesktopMenuItemProvider.state)
|
||||||
|
.state
|
||||||
|
.index >
|
||||||
|
0
|
||||||
|
? 1
|
||||||
|
: 0,
|
||||||
|
children: [
|
||||||
|
myStackViewNav,
|
||||||
|
contentViews[
|
||||||
|
ref.watch(currentDesktopMenuItemProvider.state).state]!,
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
// Expanded(
|
||||||
|
// child: contentViews[
|
||||||
|
// ref.watch(currentDesktopMenuItemProvider.state).state]!,
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -9,6 +9,7 @@ import 'package:stackwallet/providers/providers.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/widgets/desktop/living_stack_icon.dart';
|
||||||
|
|
||||||
enum DesktopMenuItemId {
|
enum DesktopMenuItemId {
|
||||||
myStack,
|
myStack,
|
||||||
|
@ -38,6 +39,9 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
static const expandedWidth = 225.0;
|
static const expandedWidth = 225.0;
|
||||||
static const minimizedWidth = 72.0;
|
static const minimizedWidth = 72.0;
|
||||||
|
|
||||||
|
final Duration duration = const Duration(milliseconds: 250);
|
||||||
|
late final List<DMIController> controllers;
|
||||||
|
|
||||||
double _width = expandedWidth;
|
double _width = expandedWidth;
|
||||||
|
|
||||||
void updateSelectedMenuItem(DesktopMenuItemId idKey) {
|
void updateSelectedMenuItem(DesktopMenuItemId idKey) {
|
||||||
|
@ -49,45 +53,84 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggleMinimize() {
|
void toggleMinimize() {
|
||||||
|
final expanded = _width == expandedWidth;
|
||||||
|
|
||||||
|
for (var e in controllers) {
|
||||||
|
e.toggle?.call();
|
||||||
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_width = _width == expandedWidth ? minimizedWidth : expandedWidth;
|
_width = expanded ? minimizedWidth : expandedWidth;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
controllers = [
|
||||||
|
DMIController(),
|
||||||
|
DMIController(),
|
||||||
|
DMIController(),
|
||||||
|
DMIController(),
|
||||||
|
DMIController(),
|
||||||
|
DMIController(),
|
||||||
|
DMIController(),
|
||||||
|
DMIController(),
|
||||||
|
];
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
for (var e in controllers) {
|
||||||
|
e.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Material(
|
return Material(
|
||||||
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
child: SizedBox(
|
child: AnimatedContainer(
|
||||||
width: _width,
|
width: _width,
|
||||||
|
duration: duration,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: _width == expandedWidth ? 22 : 25,
|
height: 25,
|
||||||
),
|
),
|
||||||
SizedBox(
|
AnimatedContainer(
|
||||||
|
duration: duration,
|
||||||
width: _width == expandedWidth ? 70 : 32,
|
width: _width == expandedWidth ? 70 : 32,
|
||||||
height: _width == expandedWidth ? 70 : 32,
|
child: LivingStackIcon(
|
||||||
child: SvgPicture.asset(
|
onPressed: toggleMinimize,
|
||||||
Assets.svg.stackIcon(context),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
Text(
|
AnimatedOpacity(
|
||||||
_width == expandedWidth ? "Stack Wallet" : "",
|
duration: duration,
|
||||||
style: STextStyles.desktopH2(context).copyWith(
|
opacity: _width == expandedWidth ? 1 : 0,
|
||||||
fontSize: 18,
|
child: SizedBox(
|
||||||
height: 23.4 / 18,
|
height: 28,
|
||||||
|
child: Text(
|
||||||
|
"Stack Wallet",
|
||||||
|
style: STextStyles.desktopH2(context).copyWith(
|
||||||
|
fontSize: 18,
|
||||||
|
height: 23.4 / 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 60,
|
height: 60,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SizedBox(
|
child: AnimatedContainer(
|
||||||
|
duration: duration,
|
||||||
width: _width == expandedWidth
|
width: _width == expandedWidth
|
||||||
? _width - 32 // 16 padding on either side
|
? _width - 32 // 16 padding on either side
|
||||||
: _width - 16, // 8 padding on either side
|
: _width - 16, // 8 padding on either side
|
||||||
|
@ -95,6 +138,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
DesktopMenuItem(
|
DesktopMenuItem(
|
||||||
|
duration: duration,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
Assets.svg.walletDesktop,
|
Assets.svg.walletDesktop,
|
||||||
width: 20,
|
width: 20,
|
||||||
|
@ -113,15 +157,14 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
),
|
),
|
||||||
label: "My Stack",
|
label: "My Stack",
|
||||||
value: DesktopMenuItemId.myStack,
|
value: DesktopMenuItemId.myStack,
|
||||||
group:
|
|
||||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
|
||||||
onChanged: updateSelectedMenuItem,
|
onChanged: updateSelectedMenuItem,
|
||||||
iconOnly: _width == minimizedWidth,
|
controller: controllers[0],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 2,
|
height: 2,
|
||||||
),
|
),
|
||||||
DesktopMenuItem(
|
DesktopMenuItem(
|
||||||
|
duration: duration,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
Assets.svg.exchangeDesktop,
|
Assets.svg.exchangeDesktop,
|
||||||
width: 20,
|
width: 20,
|
||||||
|
@ -140,15 +183,14 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
),
|
),
|
||||||
label: "Exchange",
|
label: "Exchange",
|
||||||
value: DesktopMenuItemId.exchange,
|
value: DesktopMenuItemId.exchange,
|
||||||
group:
|
|
||||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
|
||||||
onChanged: updateSelectedMenuItem,
|
onChanged: updateSelectedMenuItem,
|
||||||
iconOnly: _width == minimizedWidth,
|
controller: controllers[1],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 2,
|
height: 2,
|
||||||
),
|
),
|
||||||
DesktopMenuItem(
|
DesktopMenuItem(
|
||||||
|
duration: duration,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
ref.watch(notificationsProvider.select(
|
ref.watch(notificationsProvider.select(
|
||||||
(value) => value.hasUnreadNotifications))
|
(value) => value.hasUnreadNotifications))
|
||||||
|
@ -174,15 +216,14 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
),
|
),
|
||||||
label: "Notifications",
|
label: "Notifications",
|
||||||
value: DesktopMenuItemId.notifications,
|
value: DesktopMenuItemId.notifications,
|
||||||
group:
|
|
||||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
|
||||||
onChanged: updateSelectedMenuItem,
|
onChanged: updateSelectedMenuItem,
|
||||||
iconOnly: _width == minimizedWidth,
|
controller: controllers[2],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 2,
|
height: 2,
|
||||||
),
|
),
|
||||||
DesktopMenuItem(
|
DesktopMenuItem(
|
||||||
|
duration: duration,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
Assets.svg.addressBookDesktop,
|
Assets.svg.addressBookDesktop,
|
||||||
width: 20,
|
width: 20,
|
||||||
|
@ -201,15 +242,14 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
),
|
),
|
||||||
label: "Address Book",
|
label: "Address Book",
|
||||||
value: DesktopMenuItemId.addressBook,
|
value: DesktopMenuItemId.addressBook,
|
||||||
group:
|
|
||||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
|
||||||
onChanged: updateSelectedMenuItem,
|
onChanged: updateSelectedMenuItem,
|
||||||
iconOnly: _width == minimizedWidth,
|
controller: controllers[3],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 2,
|
height: 2,
|
||||||
),
|
),
|
||||||
DesktopMenuItem(
|
DesktopMenuItem(
|
||||||
|
duration: duration,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
Assets.svg.gear,
|
Assets.svg.gear,
|
||||||
width: 20,
|
width: 20,
|
||||||
|
@ -228,15 +268,14 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
),
|
),
|
||||||
label: "Settings",
|
label: "Settings",
|
||||||
value: DesktopMenuItemId.settings,
|
value: DesktopMenuItemId.settings,
|
||||||
group:
|
|
||||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
|
||||||
onChanged: updateSelectedMenuItem,
|
onChanged: updateSelectedMenuItem,
|
||||||
iconOnly: _width == minimizedWidth,
|
controller: controllers[4],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 2,
|
height: 2,
|
||||||
),
|
),
|
||||||
DesktopMenuItem(
|
DesktopMenuItem(
|
||||||
|
duration: duration,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
Assets.svg.messageQuestion,
|
Assets.svg.messageQuestion,
|
||||||
width: 20,
|
width: 20,
|
||||||
|
@ -255,15 +294,14 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
),
|
),
|
||||||
label: "Support",
|
label: "Support",
|
||||||
value: DesktopMenuItemId.support,
|
value: DesktopMenuItemId.support,
|
||||||
group:
|
|
||||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
|
||||||
onChanged: updateSelectedMenuItem,
|
onChanged: updateSelectedMenuItem,
|
||||||
iconOnly: _width == minimizedWidth,
|
controller: controllers[5],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 2,
|
height: 2,
|
||||||
),
|
),
|
||||||
DesktopMenuItem(
|
DesktopMenuItem(
|
||||||
|
duration: duration,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
Assets.svg.aboutDesktop,
|
Assets.svg.aboutDesktop,
|
||||||
width: 20,
|
width: 20,
|
||||||
|
@ -282,13 +320,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
),
|
),
|
||||||
label: "About",
|
label: "About",
|
||||||
value: DesktopMenuItemId.about,
|
value: DesktopMenuItemId.about,
|
||||||
group:
|
|
||||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
|
||||||
onChanged: updateSelectedMenuItem,
|
onChanged: updateSelectedMenuItem,
|
||||||
iconOnly: _width == minimizedWidth,
|
controller: controllers[6],
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
DesktopMenuItem(
|
DesktopMenuItem(
|
||||||
|
duration: duration,
|
||||||
|
labelLength: 123,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
Assets.svg.exitDesktop,
|
Assets.svg.exitDesktop,
|
||||||
width: 20,
|
width: 20,
|
||||||
|
@ -300,13 +338,11 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
||||||
),
|
),
|
||||||
label: "Exit",
|
label: "Exit",
|
||||||
value: 7,
|
value: 7,
|
||||||
group:
|
|
||||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
|
||||||
onChanged: (_) {
|
onChanged: (_) {
|
||||||
// todo: save stuff/ notify before exit?
|
// todo: save stuff/ notify before exit?
|
||||||
exit(0);
|
exit(0);
|
||||||
},
|
},
|
||||||
iconOnly: _width == minimizedWidth,
|
controller: controllers[7],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,27 +1,96 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.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';
|
||||||
|
|
||||||
class DesktopMenuItem<T> extends StatelessWidget {
|
class DMIController {
|
||||||
|
VoidCallback? toggle;
|
||||||
|
void dispose() {
|
||||||
|
toggle = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DesktopMenuItem<T> extends ConsumerStatefulWidget {
|
||||||
const DesktopMenuItem({
|
const DesktopMenuItem({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.value,
|
required this.value,
|
||||||
required this.group,
|
|
||||||
required this.onChanged,
|
required this.onChanged,
|
||||||
required this.iconOnly,
|
required this.duration,
|
||||||
|
this.labelLength = 125,
|
||||||
|
this.controller,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final Widget icon;
|
final Widget icon;
|
||||||
final String label;
|
final String label;
|
||||||
final T value;
|
final T value;
|
||||||
final T group;
|
|
||||||
final void Function(T) onChanged;
|
final void Function(T) onChanged;
|
||||||
final bool iconOnly;
|
final Duration duration;
|
||||||
|
final double labelLength;
|
||||||
|
final DMIController? controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<DesktopMenuItem<T>> createState() => _DesktopMenuItemState<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DesktopMenuItemState<T> extends ConsumerState<DesktopMenuItem<T>>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late final Widget icon;
|
||||||
|
late final String label;
|
||||||
|
late final T value;
|
||||||
|
late final void Function(T) onChanged;
|
||||||
|
late final Duration duration;
|
||||||
|
late final double labelLength;
|
||||||
|
|
||||||
|
late final DMIController? controller;
|
||||||
|
|
||||||
|
late final AnimationController animationController;
|
||||||
|
|
||||||
|
bool _iconOnly = false;
|
||||||
|
|
||||||
|
void toggle() {
|
||||||
|
setState(() {
|
||||||
|
_iconOnly = !_iconOnly;
|
||||||
|
});
|
||||||
|
if (_iconOnly) {
|
||||||
|
animationController.reverse();
|
||||||
|
} else {
|
||||||
|
animationController.forward();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
icon = widget.icon;
|
||||||
|
label = widget.label;
|
||||||
|
value = widget.value;
|
||||||
|
onChanged = widget.onChanged;
|
||||||
|
duration = widget.duration;
|
||||||
|
labelLength = widget.labelLength;
|
||||||
|
controller = widget.controller;
|
||||||
|
|
||||||
|
controller?.toggle = toggle;
|
||||||
|
animationController = AnimationController(
|
||||||
|
vsync: this,
|
||||||
|
duration: duration,
|
||||||
|
)..forward();
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
controller?.dispose();
|
||||||
|
animationController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final group = ref.watch(currentDesktopMenuItemProvider.state).state;
|
||||||
|
debugPrint("============ value:$value ============ group:$group");
|
||||||
return TextButton(
|
return TextButton(
|
||||||
style: value == group
|
style: value == group
|
||||||
? Theme.of(context)
|
? Theme.of(context)
|
||||||
|
@ -34,26 +103,42 @@ class DesktopMenuItem<T> extends StatelessWidget {
|
||||||
onChanged(value);
|
onChanged(value);
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: 16,
|
vertical: 16,
|
||||||
horizontal: iconOnly ? 0 : 16,
|
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
iconOnly ? MainAxisAlignment.center : MainAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
|
AnimatedContainer(
|
||||||
|
duration: duration,
|
||||||
|
width: _iconOnly ? 0 : 16,
|
||||||
|
),
|
||||||
icon,
|
icon,
|
||||||
if (!iconOnly)
|
AnimatedOpacity(
|
||||||
const SizedBox(
|
duration: duration,
|
||||||
width: 12,
|
opacity: _iconOnly ? 0 : 1.0,
|
||||||
),
|
child: SizeTransition(
|
||||||
if (!iconOnly)
|
sizeFactor: animationController,
|
||||||
Text(
|
axis: Axis.horizontal,
|
||||||
label,
|
axisAlignment: -1,
|
||||||
style: value == group
|
child: SizedBox(
|
||||||
? STextStyles.desktopMenuItemSelected(context)
|
width: labelLength,
|
||||||
: STextStyles.desktopMenuItem(context),
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
width: 12,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: value == group
|
||||||
|
? STextStyles.desktopMenuItemSelected(context)
|
||||||
|
: STextStyles.desktopMenuItem(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
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/pages_desktop_specific/home/desktop_home_view.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart';
|
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart';
|
||||||
import 'package:stackwallet/utilities/constants.dart';
|
import 'package:stackwallet/utilities/constants.dart';
|
||||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||||
import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart';
|
import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart';
|
||||||
|
|
||||||
class CoinWalletsTable extends ConsumerWidget {
|
class CoinWalletsTable extends ConsumerWidget {
|
||||||
|
@ -24,8 +26,10 @@ class CoinWalletsTable extends ConsumerWidget {
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 20,
|
// horizontal: 20,
|
||||||
vertical: 16,
|
// vertical: 16,
|
||||||
|
horizontal: 6,
|
||||||
|
vertical: 6,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -36,14 +40,29 @@ class CoinWalletsTable extends ConsumerWidget {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 32,
|
height: 32,
|
||||||
),
|
),
|
||||||
WalletInfoRow(
|
Stack(
|
||||||
walletId: walletIds[i],
|
children: [
|
||||||
onPressed: () async {
|
WalletInfoRow(
|
||||||
await Navigator.of(context).pushNamed(
|
padding: const EdgeInsets.symmetric(
|
||||||
DesktopWalletView.routeName,
|
horizontal: 14,
|
||||||
arguments: walletIds[i],
|
vertical: 10,
|
||||||
);
|
),
|
||||||
},
|
walletId: walletIds[i],
|
||||||
|
),
|
||||||
|
Positioned.fill(
|
||||||
|
child: WalletRowHoverOverlay(
|
||||||
|
onPressed: () async {
|
||||||
|
ref.read(currentWalletIdProvider.state).state =
|
||||||
|
walletIds[i];
|
||||||
|
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
DesktopWalletView.routeName,
|
||||||
|
arguments: walletIds[i],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -53,3 +72,55 @@ class CoinWalletsTable extends ConsumerWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class WalletRowHoverOverlay extends StatefulWidget {
|
||||||
|
const WalletRowHoverOverlay({
|
||||||
|
Key? key,
|
||||||
|
required this.onPressed,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<WalletRowHoverOverlay> createState() => _WalletRowHoverOverlayState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _WalletRowHoverOverlayState extends State<WalletRowHoverOverlay> {
|
||||||
|
late final VoidCallback onPressed;
|
||||||
|
|
||||||
|
bool _hovering = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
onPressed = widget.onPressed;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MouseRegion(
|
||||||
|
cursor: SystemMouseCursors.click,
|
||||||
|
onEnter: (_) {
|
||||||
|
setState(() {
|
||||||
|
_hovering = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onExit: (_) {
|
||||||
|
setState(() {
|
||||||
|
_hovering = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: onPressed,
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
duration: const Duration(milliseconds: 100),
|
||||||
|
opacity: _hovering ? 0.1 : 0,
|
||||||
|
child: RoundedContainer(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.buttonBackSecondary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -81,13 +81,13 @@ class _DesktopWalletViewState extends ConsumerState<DesktopWalletView> {
|
||||||
// disable auto sync if it was enabled only when loading wallet
|
// disable auto sync if it was enabled only when loading wallet
|
||||||
ref.read(managerProvider).shouldAutoSync = false;
|
ref.read(managerProvider).shouldAutoSync = false;
|
||||||
}
|
}
|
||||||
ref.read(managerProvider.notifier).isActiveWallet = false;
|
|
||||||
ref.read(transactionFilterProvider.state).state = null;
|
ref.read(transactionFilterProvider.state).state = null;
|
||||||
if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled &&
|
if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled &&
|
||||||
ref.read(prefsChangeNotifierProvider).backupFrequencyType ==
|
ref.read(prefsChangeNotifierProvider).backupFrequencyType ==
|
||||||
BackupFrequencyType.afterClosingAWallet) {
|
BackupFrequencyType.afterClosingAWallet) {
|
||||||
unawaited(ref.read(autoSWBServiceProvider).doBackup());
|
unawaited(ref.read(autoSWBServiceProvider).doBackup());
|
||||||
}
|
}
|
||||||
|
ref.read(managerProvider.notifier).isActiveWallet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _loadCNData() {
|
void _loadCNData() {
|
||||||
|
|
|
@ -95,7 +95,8 @@ class _DeleteWalletKeysPopup extends ConsumerState<DeleteWalletKeysPopup> {
|
||||||
horizontal: 32,
|
horizontal: 32,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Please write down your recovery phrase in the correct order and save it to keep your funds secure. You will also be asked to verify the words on the next screen.",
|
"Please write down your recovery phrase in the correct order and "
|
||||||
|
"save it to keep your funds secure. You will be shown your recovery phrase on the next screen.",
|
||||||
style: STextStyles.desktopTextExtraExtraSmall(context),
|
style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,14 +1,24 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
|
|
||||||
abstract class Util {
|
abstract class Util {
|
||||||
static Directory? libraryPath;
|
static Directory? libraryPath;
|
||||||
|
static double? screenWidth;
|
||||||
|
|
||||||
static bool get isDesktop {
|
static bool get isDesktop {
|
||||||
if(Platform.isIOS && libraryPath != null && !libraryPath!.path.contains("/var/mobile/")){
|
// special check for running on linux based phones
|
||||||
|
if (Platform.isLinux && screenWidth != null && screenWidth! < 800) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// special check for running under ipad mode in macos
|
||||||
|
if (Platform.isIOS &&
|
||||||
|
libraryPath != null &&
|
||||||
|
!libraryPath!.path.contains("/var/mobile/")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Platform.isLinux || Platform.isMacOS || Platform.isWindows;
|
return Platform.isLinux || Platform.isMacOS || Platform.isWindows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
54
lib/widgets/desktop/living_stack_icon.dart
Normal file
54
lib/widgets/desktop/living_stack_icon.dart
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
|
|
||||||
|
class LivingStackIcon extends StatefulWidget {
|
||||||
|
const LivingStackIcon({Key? key, this.onPressed,}) : super(key: key);
|
||||||
|
|
||||||
|
final VoidCallback? onPressed;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LivingStackIcon> createState() => _LivingStackIconState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LivingStackIconState extends State<LivingStackIcon> {
|
||||||
|
bool _hovering = false;
|
||||||
|
|
||||||
|
late final VoidCallback? onPressed;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
onPressed = widget.onPressed;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
height: 76,
|
||||||
|
child: MouseRegion(
|
||||||
|
cursor: SystemMouseCursors.click,
|
||||||
|
onEnter: (_) {
|
||||||
|
setState(() {
|
||||||
|
_hovering = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onExit: (_) {
|
||||||
|
setState(() {
|
||||||
|
_hovering = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => onPressed?.call(),
|
||||||
|
child: AnimatedScale(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
scale: _hovering ? 1.2 : 1,
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.svg.stackIcon(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
5
lib/widgets/rounded_date_picker/LICENSE
Normal file
5
lib/widgets/rounded_date_picker/LICENSE
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
@ -0,0 +1,332 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/semantics.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/flutter_rounded_button_action.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/material_rounded_date_picker_style.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/material_rounded_year_picker_style.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_date_picker_header.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_day_picker.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_month_picker.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_year_picker.dart';
|
||||||
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
|
||||||
|
///
|
||||||
|
/// This file uses code taken from https://github.com/benznest/flutter_rounded_date_picker
|
||||||
|
///
|
||||||
|
|
||||||
|
class FlutterRoundedDatePickerDialog extends StatefulWidget {
|
||||||
|
const FlutterRoundedDatePickerDialog(
|
||||||
|
{Key? key,
|
||||||
|
this.height,
|
||||||
|
required this.initialDate,
|
||||||
|
required this.firstDate,
|
||||||
|
required this.lastDate,
|
||||||
|
this.selectableDayPredicate,
|
||||||
|
required this.initialDatePickerMode,
|
||||||
|
required this.era,
|
||||||
|
this.locale,
|
||||||
|
required this.borderRadius,
|
||||||
|
this.imageHeader,
|
||||||
|
this.description = "",
|
||||||
|
this.fontFamily,
|
||||||
|
this.textNegativeButton,
|
||||||
|
this.textPositiveButton,
|
||||||
|
this.textActionButton,
|
||||||
|
this.onTapActionButton,
|
||||||
|
this.styleDatePicker,
|
||||||
|
this.styleYearPicker,
|
||||||
|
this.customWeekDays,
|
||||||
|
this.builderDay,
|
||||||
|
this.listDateDisabled,
|
||||||
|
this.onTapDay,
|
||||||
|
this.onMonthChange})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
final DateTime initialDate;
|
||||||
|
final DateTime firstDate;
|
||||||
|
final DateTime lastDate;
|
||||||
|
final SelectableDayPredicate? selectableDayPredicate;
|
||||||
|
final DatePickerMode initialDatePickerMode;
|
||||||
|
|
||||||
|
/// double height.
|
||||||
|
final double? height;
|
||||||
|
|
||||||
|
/// Custom era year.
|
||||||
|
final EraMode era;
|
||||||
|
final Locale? locale;
|
||||||
|
|
||||||
|
/// Border
|
||||||
|
final double borderRadius;
|
||||||
|
|
||||||
|
/// Header;
|
||||||
|
final ImageProvider? imageHeader;
|
||||||
|
final String description;
|
||||||
|
|
||||||
|
/// Font
|
||||||
|
final String? fontFamily;
|
||||||
|
|
||||||
|
/// Button
|
||||||
|
final String? textNegativeButton;
|
||||||
|
final String? textPositiveButton;
|
||||||
|
final String? textActionButton;
|
||||||
|
|
||||||
|
final VoidCallback? onTapActionButton;
|
||||||
|
|
||||||
|
/// Style
|
||||||
|
final MaterialRoundedDatePickerStyle? styleDatePicker;
|
||||||
|
final MaterialRoundedYearPickerStyle? styleYearPicker;
|
||||||
|
|
||||||
|
/// Custom Weekday
|
||||||
|
final List<String>? customWeekDays;
|
||||||
|
|
||||||
|
final BuilderDayOfDatePicker? builderDay;
|
||||||
|
|
||||||
|
final List<DateTime>? listDateDisabled;
|
||||||
|
final OnTapDay? onTapDay;
|
||||||
|
|
||||||
|
final Function? onMonthChange;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_FlutterRoundedDatePickerDialogState createState() =>
|
||||||
|
_FlutterRoundedDatePickerDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FlutterRoundedDatePickerDialogState
|
||||||
|
extends State<FlutterRoundedDatePickerDialog> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_selectedDate = widget.initialDate;
|
||||||
|
_mode = widget.initialDatePickerMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _announcedInitialDate = false;
|
||||||
|
|
||||||
|
late MaterialLocalizations localizations;
|
||||||
|
late TextDirection textDirection;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
localizations = MaterialLocalizations.of(context);
|
||||||
|
textDirection = Directionality.of(context);
|
||||||
|
if (!_announcedInitialDate) {
|
||||||
|
_announcedInitialDate = true;
|
||||||
|
SemanticsService.announce(
|
||||||
|
localizations.formatFullDate(_selectedDate),
|
||||||
|
textDirection,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
late DateTime _selectedDate;
|
||||||
|
late DatePickerMode _mode;
|
||||||
|
final GlobalKey _pickerKey = GlobalKey();
|
||||||
|
|
||||||
|
void _vibrate() {
|
||||||
|
switch (Theme.of(context).platform) {
|
||||||
|
case TargetPlatform.android:
|
||||||
|
case TargetPlatform.fuchsia:
|
||||||
|
HapticFeedback.vibrate();
|
||||||
|
break;
|
||||||
|
case TargetPlatform.iOS:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleModeChanged(DatePickerMode mode) {
|
||||||
|
_vibrate();
|
||||||
|
setState(() {
|
||||||
|
_mode = mode;
|
||||||
|
if (_mode == DatePickerMode.day) {
|
||||||
|
SemanticsService.announce(
|
||||||
|
localizations.formatMonthYear(_selectedDate),
|
||||||
|
textDirection,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
SemanticsService.announce(
|
||||||
|
localizations.formatYear(_selectedDate),
|
||||||
|
textDirection,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleYearChanged(DateTime value) async {
|
||||||
|
if (value.isBefore(widget.firstDate)) {
|
||||||
|
value = widget.firstDate;
|
||||||
|
} else if (value.isAfter(widget.lastDate)) {
|
||||||
|
value = widget.lastDate;
|
||||||
|
}
|
||||||
|
if (value == _selectedDate) return;
|
||||||
|
|
||||||
|
if (widget.onMonthChange != null) await widget.onMonthChange!(value);
|
||||||
|
|
||||||
|
_vibrate();
|
||||||
|
setState(() {
|
||||||
|
_mode = DatePickerMode.day;
|
||||||
|
_selectedDate = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleDayChanged(DateTime value) {
|
||||||
|
_vibrate();
|
||||||
|
setState(() {
|
||||||
|
_selectedDate = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleCancel() {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleOk() {
|
||||||
|
Navigator.of(context).pop(_selectedDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPicker() {
|
||||||
|
switch (_mode) {
|
||||||
|
case DatePickerMode.year:
|
||||||
|
return FlutterRoundedYearPicker(
|
||||||
|
key: _pickerKey,
|
||||||
|
selectedDate: _selectedDate,
|
||||||
|
onChanged: (DateTime date) async => await _handleYearChanged(date),
|
||||||
|
firstDate: widget.firstDate,
|
||||||
|
lastDate: widget.lastDate,
|
||||||
|
era: widget.era,
|
||||||
|
fontFamily: widget.fontFamily,
|
||||||
|
style: widget.styleYearPicker,
|
||||||
|
);
|
||||||
|
case DatePickerMode.day:
|
||||||
|
default:
|
||||||
|
return FlutterRoundedMonthPicker(
|
||||||
|
key: _pickerKey,
|
||||||
|
selectedDate: _selectedDate,
|
||||||
|
onChanged: _handleDayChanged,
|
||||||
|
firstDate: widget.firstDate,
|
||||||
|
lastDate: widget.lastDate,
|
||||||
|
era: widget.era,
|
||||||
|
locale: widget.locale,
|
||||||
|
selectableDayPredicate: widget.selectableDayPredicate,
|
||||||
|
fontFamily: widget.fontFamily,
|
||||||
|
style: widget.styleDatePicker,
|
||||||
|
borderRadius: widget.borderRadius,
|
||||||
|
customWeekDays: widget.customWeekDays,
|
||||||
|
builderDay: widget.builderDay,
|
||||||
|
listDateDisabled: widget.listDateDisabled,
|
||||||
|
onTapDay: widget.onTapDay,
|
||||||
|
onMonthChange: widget.onMonthChange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final ThemeData theme = Theme.of(context);
|
||||||
|
final Widget picker = _buildPicker();
|
||||||
|
final isDesktop = Util.isDesktop;
|
||||||
|
|
||||||
|
final Widget actions = FlutterRoundedButtonAction(
|
||||||
|
textButtonNegative: widget.textNegativeButton,
|
||||||
|
textButtonPositive: widget.textPositiveButton,
|
||||||
|
onTapButtonNegative: _handleCancel,
|
||||||
|
onTapButtonPositive: _handleOk,
|
||||||
|
textActionButton: widget.textActionButton,
|
||||||
|
onTapButtonAction: widget.onTapActionButton,
|
||||||
|
localizations: localizations,
|
||||||
|
textStyleButtonNegative: widget.styleDatePicker?.textStyleButtonNegative,
|
||||||
|
textStyleButtonPositive: widget.styleDatePicker?.textStyleButtonPositive,
|
||||||
|
textStyleButtonAction: widget.styleDatePicker?.textStyleButtonAction,
|
||||||
|
borderRadius: widget.borderRadius,
|
||||||
|
paddingActionBar: widget.styleDatePicker?.paddingActionBar,
|
||||||
|
background: widget.styleDatePicker?.backgroundActionBar,
|
||||||
|
);
|
||||||
|
|
||||||
|
Color backgroundPicker = theme.dialogBackgroundColor;
|
||||||
|
if (_mode == DatePickerMode.day) {
|
||||||
|
backgroundPicker = widget.styleDatePicker?.backgroundPicker ??
|
||||||
|
theme.dialogBackgroundColor;
|
||||||
|
} else {
|
||||||
|
backgroundPicker = widget.styleYearPicker?.backgroundPicker ??
|
||||||
|
theme.dialogBackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Dialog dialog = Dialog(
|
||||||
|
child: OrientationBuilder(
|
||||||
|
builder: (BuildContext context, Orientation orientation) {
|
||||||
|
final Widget header = FlutterRoundedDatePickerHeader(
|
||||||
|
selectedDate: _selectedDate,
|
||||||
|
mode: _mode,
|
||||||
|
onModeChanged: _handleModeChanged,
|
||||||
|
orientation: orientation,
|
||||||
|
era: widget.era,
|
||||||
|
borderRadius: widget.borderRadius,
|
||||||
|
imageHeader: widget.imageHeader,
|
||||||
|
description: widget.description,
|
||||||
|
fontFamily: widget.fontFamily,
|
||||||
|
style: widget.styleDatePicker);
|
||||||
|
switch (orientation) {
|
||||||
|
case Orientation.landscape:
|
||||||
|
return Container(
|
||||||
|
height: isDesktop ? 600 : null,
|
||||||
|
width: isDesktop ? 700 : null,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: backgroundPicker,
|
||||||
|
borderRadius: BorderRadius.circular(widget.borderRadius),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
Flexible(flex: 1, child: header),
|
||||||
|
Flexible(
|
||||||
|
flex: 2, // have the picker take up 2/3 of the dialog width
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
SizedBox(
|
||||||
|
height: isDesktop ? 530 : null,
|
||||||
|
width: isDesktop ? 700 : null,
|
||||||
|
child: picker),
|
||||||
|
actions,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
case Orientation.portrait:
|
||||||
|
default:
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: backgroundPicker,
|
||||||
|
borderRadius: BorderRadius.circular(widget.borderRadius),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
header,
|
||||||
|
if (widget.height == null)
|
||||||
|
Flexible(child: picker)
|
||||||
|
else
|
||||||
|
SizedBox(
|
||||||
|
height: widget.height,
|
||||||
|
child: picker,
|
||||||
|
),
|
||||||
|
actions,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Theme(
|
||||||
|
data: theme.copyWith(dialogBackgroundColor: Colors.transparent),
|
||||||
|
child: dialog,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,216 @@
|
||||||
|
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
// import 'package:flutter_rounded_date_picker/src/dialogs/flutter_rounded_date_picker_dialog.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/era_mode.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/material_rounded_date_picker_style.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/material_rounded_year_picker_style.dart';
|
||||||
|
import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_day_picker.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_date_picker/flutter_rounded_date_picker_dialog.dart';
|
||||||
|
|
||||||
|
///
|
||||||
|
/// This file uses code taken from https://github.com/benznest/flutter_rounded_date_picker
|
||||||
|
///
|
||||||
|
|
||||||
|
// Examples can assume:
|
||||||
|
// BuildContext context;
|
||||||
|
|
||||||
|
/// Initial display mode of the date picker dialog.
|
||||||
|
///
|
||||||
|
/// Date picker UI mode for either showing a list of available years or a
|
||||||
|
/// monthly calendar initially in the dialog shown by calling [showDatePicker].
|
||||||
|
///
|
||||||
|
|
||||||
|
// Shows the selected date in large font and toggles between year and day mode
|
||||||
|
|
||||||
|
/// Signature for predicating dates for enabled date selections.
|
||||||
|
///
|
||||||
|
/// See [showDatePicker].
|
||||||
|
typedef SelectableDayPredicate = bool Function(DateTime day);
|
||||||
|
|
||||||
|
/// Shows a dialog containing a material design date picker.
|
||||||
|
///
|
||||||
|
/// The returned [Future] resolves to the date selected by the user when the
|
||||||
|
/// user closes the dialog. If the user cancels the dialog, null is returned.
|
||||||
|
///
|
||||||
|
/// An optional [selectableDayPredicate] function can be passed in to customize
|
||||||
|
/// the days to enable for selection. If provided, only the days that
|
||||||
|
/// [selectableDayPredicate] returned true for will be selectable.
|
||||||
|
///
|
||||||
|
/// An optional [initialDatePickerMode] argument can be used to display the
|
||||||
|
/// date picker initially in the year or month+day picker mode. It defaults
|
||||||
|
/// to month+day, and must not be null.
|
||||||
|
///
|
||||||
|
/// An optional [locale] argument can be used to set the locale for the date
|
||||||
|
/// picker. It defaults to the ambient locale provided by [Localizations].
|
||||||
|
///
|
||||||
|
/// An optional [textDirection] argument can be used to set the text direction
|
||||||
|
/// (RTL or LTR) for the date picker. It defaults to the ambient text direction
|
||||||
|
/// provided by [Directionality]. If both [locale] and [textDirection] are not
|
||||||
|
/// null, [textDirection] overrides the direction chosen for the [locale].
|
||||||
|
///
|
||||||
|
/// The [context] argument is passed to [showDialog], the documentation for
|
||||||
|
/// which discusses how it is used.
|
||||||
|
///
|
||||||
|
/// The [builder] parameter can be used to wrap the dialog widget
|
||||||
|
/// to add inherited widgets like [Theme].
|
||||||
|
///
|
||||||
|
/// {@tool sample}
|
||||||
|
/// Show a date picker with the dark theme.
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// Future<DateTime> selectedDate = showDatePicker(
|
||||||
|
/// context: context,
|
||||||
|
/// initialDate: DateTime.now(),
|
||||||
|
/// firstDate: DateTime(2018),
|
||||||
|
/// lastDate: DateTime(2030),
|
||||||
|
/// builder: (BuildContext context, Widget child) {
|
||||||
|
/// return Theme(
|
||||||
|
/// data: ThemeData.dark(),
|
||||||
|
/// child: child,
|
||||||
|
/// );
|
||||||
|
/// },
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
/// {@end-tool}
|
||||||
|
///
|
||||||
|
/// The [context], [initialDate], [firstDate], and [lastDate] parameters must
|
||||||
|
/// not be null.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [showTimePicker], which shows a dialog that contains a material design
|
||||||
|
/// time picker.
|
||||||
|
/// * [DayPicker], which displays the days of a given month and allows
|
||||||
|
/// choosing a day.
|
||||||
|
/// * [MonthPicker], which displays a scrollable list of months to allow
|
||||||
|
/// picking a month.
|
||||||
|
/// * [YearPicker], which displays a scrollable list of years to allow picking
|
||||||
|
/// a year.
|
||||||
|
///
|
||||||
|
|
||||||
|
Future<DateTime?> showRoundedDatePicker(
|
||||||
|
{required BuildContext context,
|
||||||
|
double? height,
|
||||||
|
DateTime? initialDate,
|
||||||
|
DateTime? firstDate,
|
||||||
|
DateTime? lastDate,
|
||||||
|
SelectableDayPredicate? selectableDayPredicate,
|
||||||
|
DatePickerMode initialDatePickerMode = DatePickerMode.day,
|
||||||
|
Locale? locale,
|
||||||
|
TextDirection? textDirection,
|
||||||
|
ThemeData? theme,
|
||||||
|
double borderRadius = 16,
|
||||||
|
EraMode era = EraMode.CHRIST_YEAR,
|
||||||
|
ImageProvider? imageHeader,
|
||||||
|
String description = "",
|
||||||
|
String? fontFamily,
|
||||||
|
bool barrierDismissible = false,
|
||||||
|
Color background = Colors.transparent,
|
||||||
|
String? textNegativeButton,
|
||||||
|
String? textPositiveButton,
|
||||||
|
String? textActionButton,
|
||||||
|
VoidCallback? onTapActionButton,
|
||||||
|
MaterialRoundedDatePickerStyle? styleDatePicker,
|
||||||
|
MaterialRoundedYearPickerStyle? styleYearPicker,
|
||||||
|
List<String>? customWeekDays,
|
||||||
|
BuilderDayOfDatePicker? builderDay,
|
||||||
|
List<DateTime>? listDateDisabled,
|
||||||
|
OnTapDay? onTapDay,
|
||||||
|
Function? onMonthChange}) async {
|
||||||
|
initialDate ??= DateTime.now();
|
||||||
|
firstDate ??= DateTime(initialDate.year - 1);
|
||||||
|
lastDate ??= DateTime(initialDate.year + 1);
|
||||||
|
theme ??= ThemeData();
|
||||||
|
|
||||||
|
assert(
|
||||||
|
!initialDate.isBefore(firstDate),
|
||||||
|
'initialDate must be on or after firstDate',
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
!initialDate.isAfter(lastDate),
|
||||||
|
'initialDate must be on or before lastDate',
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
!firstDate.isAfter(lastDate),
|
||||||
|
'lastDate must be on or after firstDate',
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
selectableDayPredicate == null || selectableDayPredicate(initialDate),
|
||||||
|
'Provided initialDate must satisfy provided selectableDayPredicate',
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
(onTapActionButton != null && textActionButton != null) ||
|
||||||
|
onTapActionButton == null,
|
||||||
|
"If you provide onLeftBtn, you must provide leftBtn",
|
||||||
|
);
|
||||||
|
assert(debugCheckHasMaterialLocalizations(context));
|
||||||
|
|
||||||
|
Widget child = GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if (!barrierDismissible) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
color: background,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
child: FlutterRoundedDatePickerDialog(
|
||||||
|
height: height,
|
||||||
|
initialDate: initialDate,
|
||||||
|
firstDate: firstDate,
|
||||||
|
lastDate: lastDate,
|
||||||
|
selectableDayPredicate: selectableDayPredicate,
|
||||||
|
initialDatePickerMode: initialDatePickerMode,
|
||||||
|
era: era,
|
||||||
|
locale: locale,
|
||||||
|
borderRadius: borderRadius,
|
||||||
|
imageHeader: imageHeader,
|
||||||
|
description: description,
|
||||||
|
fontFamily: fontFamily,
|
||||||
|
textNegativeButton: textNegativeButton,
|
||||||
|
textPositiveButton: textPositiveButton,
|
||||||
|
textActionButton: textActionButton,
|
||||||
|
onTapActionButton: onTapActionButton,
|
||||||
|
styleDatePicker: styleDatePicker,
|
||||||
|
styleYearPicker: styleYearPicker,
|
||||||
|
customWeekDays: customWeekDays,
|
||||||
|
builderDay: builderDay,
|
||||||
|
listDateDisabled: listDateDisabled,
|
||||||
|
onTapDay: onTapDay,
|
||||||
|
onMonthChange: onMonthChange,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (textDirection != null) {
|
||||||
|
child = Directionality(
|
||||||
|
textDirection: textDirection,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locale != null) {
|
||||||
|
child = Localizations.override(
|
||||||
|
context: context,
|
||||||
|
locale: locale,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await showDialog<DateTime>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: barrierDismissible,
|
||||||
|
builder: (_) => Theme(data: theme!, child: child),
|
||||||
|
);
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
import 'package:stackwallet/widgets/expandable.dart';
|
import 'package:stackwallet/widgets/expandable.dart';
|
||||||
import 'package:stackwallet/widgets/table_view/table_view_cell.dart';
|
import 'package:stackwallet/widgets/table_view/table_view_cell.dart';
|
||||||
|
|
||||||
class TableViewRow extends StatelessWidget {
|
class TableViewRow extends StatefulWidget {
|
||||||
const TableViewRow({
|
const TableViewRow({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.cells,
|
required this.cells,
|
||||||
|
@ -17,40 +17,66 @@ class TableViewRow extends StatelessWidget {
|
||||||
|
|
||||||
final List<TableViewCell> cells;
|
final List<TableViewCell> cells;
|
||||||
final Widget? expandingChild;
|
final Widget? expandingChild;
|
||||||
final Decoration? decoration;
|
final BoxDecoration? decoration;
|
||||||
final void Function(ExpandableState)? onExpandChanged;
|
final void Function(ExpandableState)? onExpandChanged;
|
||||||
final EdgeInsetsGeometry padding;
|
final EdgeInsetsGeometry padding;
|
||||||
final double spacing;
|
final double spacing;
|
||||||
final CrossAxisAlignment crossAxisAlignment;
|
final CrossAxisAlignment crossAxisAlignment;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TableViewRow> createState() => _TableViewRowState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TableViewRowState extends State<TableViewRow> {
|
||||||
|
late final List<TableViewCell> cells;
|
||||||
|
late final Widget? expandingChild;
|
||||||
|
late final BoxDecoration? decoration;
|
||||||
|
late final void Function(ExpandableState)? onExpandChanged;
|
||||||
|
late final EdgeInsetsGeometry padding;
|
||||||
|
late final double spacing;
|
||||||
|
late final CrossAxisAlignment crossAxisAlignment;
|
||||||
|
|
||||||
|
bool _hovering = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
cells = widget.cells;
|
||||||
|
expandingChild = widget.expandingChild;
|
||||||
|
decoration = widget.decoration;
|
||||||
|
onExpandChanged = widget.onExpandChanged;
|
||||||
|
padding = widget.padding;
|
||||||
|
spacing = widget.spacing;
|
||||||
|
crossAxisAlignment = widget.crossAxisAlignment;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: decoration,
|
decoration: !_hovering
|
||||||
|
? decoration
|
||||||
|
: decoration?.copyWith(
|
||||||
|
boxShadow: [
|
||||||
|
Theme.of(context).extension<StackColors>()!.standardBoxShadow,
|
||||||
|
Theme.of(context).extension<StackColors>()!.standardBoxShadow,
|
||||||
|
],
|
||||||
|
),
|
||||||
child: expandingChild == null
|
child: expandingChild == null
|
||||||
? Padding(
|
? MouseRegion(
|
||||||
padding: padding,
|
onEnter: (_) {
|
||||||
child: Row(
|
setState(() {
|
||||||
crossAxisAlignment: crossAxisAlignment,
|
_hovering = true;
|
||||||
children: [
|
});
|
||||||
for (int i = 0; i < cells.length; i++) ...[
|
},
|
||||||
if (i != 0 && i != cells.length)
|
onExit: (_) {
|
||||||
SizedBox(
|
setState(() {
|
||||||
width: spacing,
|
_hovering = false;
|
||||||
),
|
});
|
||||||
Expanded(
|
},
|
||||||
flex: cells[i].flex,
|
child: Padding(
|
||||||
child: cells[i],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Expandable(
|
|
||||||
onExpandChanged: onExpandChanged,
|
|
||||||
header: Padding(
|
|
||||||
padding: padding,
|
padding: padding,
|
||||||
child: Row(
|
child: Row(
|
||||||
|
crossAxisAlignment: crossAxisAlignment,
|
||||||
children: [
|
children: [
|
||||||
for (int i = 0; i < cells.length; i++) ...[
|
for (int i = 0; i < cells.length; i++) ...[
|
||||||
if (i != 0 && i != cells.length)
|
if (i != 0 && i != cells.length)
|
||||||
|
@ -65,6 +91,38 @@ class TableViewRow extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
: Expandable(
|
||||||
|
onExpandChanged: onExpandChanged,
|
||||||
|
header: MouseRegion(
|
||||||
|
onEnter: (_) {
|
||||||
|
setState(() {
|
||||||
|
_hovering = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onExit: (_) {
|
||||||
|
setState(() {
|
||||||
|
_hovering = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: padding,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
for (int i = 0; i < cells.length; i++) ...[
|
||||||
|
if (i != 0 && i != cells.length)
|
||||||
|
SizedBox(
|
||||||
|
width: spacing,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: cells[i].flex,
|
||||||
|
child: cells[i],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
|
|
|
@ -14,10 +14,12 @@ class WalletInfoRow extends ConsumerWidget {
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.walletId,
|
required this.walletId,
|
||||||
this.onPressed,
|
this.onPressed,
|
||||||
|
this.padding = const EdgeInsets.all(0),
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String walletId;
|
final String walletId;
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback? onPressed;
|
||||||
|
final EdgeInsets padding;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
@ -30,53 +32,56 @@ class WalletInfoRow extends ConsumerWidget {
|
||||||
cursor: SystemMouseCursors.click,
|
cursor: SystemMouseCursors.click,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: onPressed,
|
onTap: onPressed,
|
||||||
child: Container(
|
child: Padding(
|
||||||
color: Colors.transparent,
|
padding: padding,
|
||||||
child: Row(
|
child: Container(
|
||||||
children: [
|
color: Colors.transparent,
|
||||||
Expanded(
|
child: Row(
|
||||||
flex: 4,
|
children: [
|
||||||
child: Row(
|
Expanded(
|
||||||
children: [
|
flex: 4,
|
||||||
WalletInfoCoinIcon(coin: manager.coin),
|
child: Row(
|
||||||
const SizedBox(
|
children: [
|
||||||
width: 12,
|
WalletInfoCoinIcon(coin: manager.coin),
|
||||||
),
|
const SizedBox(
|
||||||
Text(
|
width: 12,
|
||||||
manager.walletName,
|
),
|
||||||
style:
|
Text(
|
||||||
STextStyles.desktopTextExtraSmall(context).copyWith(
|
manager.walletName,
|
||||||
|
style: STextStyles.desktopTextExtraSmall(context)
|
||||||
|
.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: WalletInfoRowBalanceFuture(
|
||||||
|
walletId: walletId,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 6,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
Assets.svg.chevronRight,
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.extension<StackColors>()!
|
.extension<StackColors>()!
|
||||||
.textDark,
|
.textSubtitle1,
|
||||||
),
|
)
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
)
|
||||||
),
|
],
|
||||||
Expanded(
|
),
|
||||||
flex: 4,
|
|
||||||
child: WalletInfoRowBalanceFuture(
|
|
||||||
walletId: walletId,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 6,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
SvgPicture.asset(
|
|
||||||
Assets.svg.chevronRight,
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.textSubtitle1,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue