mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-18 16:44:32 +00:00
use nicer looking date picker
This commit is contained in:
parent
12c47fcbec
commit
70e9566135
4 changed files with 291 additions and 77 deletions
|
@ -1,78 +1,108 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:calendar_date_picker2/calendar_date_picker2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart';
|
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
import 'package:stackwallet/utilities/constants.dart';
|
import 'package:stackwallet/utilities/constants.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||||
|
|
||||||
|
part 'sw_date_picker.dart';
|
||||||
|
|
||||||
Future<DateTime?> showSWDatePicker(BuildContext context) async {
|
Future<DateTime?> showSWDatePicker(BuildContext context) async {
|
||||||
final date = await showRoundedDatePicker(
|
final Size size;
|
||||||
|
if (Util.isDesktop) {
|
||||||
|
size = const Size(450, 450);
|
||||||
|
} else {
|
||||||
|
final _size = MediaQuery.of(context).size;
|
||||||
|
size = Size(
|
||||||
|
_size.width - 32,
|
||||||
|
_size.height >= 550 ? 450 : _size.height - 32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
print("=====================================");
|
||||||
|
print(size);
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
|
||||||
|
final date = await _showDatePickerDialog(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: DateTime.now(),
|
value: [now],
|
||||||
height: MediaQuery.of(context).size.height / 3.0,
|
dialogSize: size,
|
||||||
theme: ThemeData(
|
config: CalendarDatePicker2WithActionButtonsConfig(
|
||||||
primarySwatch: Util.createMaterialColor(
|
firstDate: DateTime(2007),
|
||||||
Theme.of(context).extension<StackColors>()!.accentColorDark),
|
lastDate: now,
|
||||||
),
|
currentDate: now,
|
||||||
//TODO pick a better initial date
|
buttonPadding: const EdgeInsets.only(
|
||||||
// 2007 chosen as that is just before bitcoin launched
|
right: 16,
|
||||||
firstDate: DateTime(2007),
|
),
|
||||||
lastDate: DateTime.now(),
|
centerAlignModePicker: true,
|
||||||
borderRadius: Constants.size.circularBorderRadius * 2,
|
selectedDayHighlightColor:
|
||||||
|
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||||
textPositiveButton: "SELECT",
|
daySplashColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
styleDatePicker: _buildDatePickerStyle(context),
|
.accentColorDark
|
||||||
styleYearPicker: _buildYearPickerStyle(context),
|
.withOpacity(0.6),
|
||||||
);
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialRoundedDatePickerStyle _buildDatePickerStyle(BuildContext context) {
|
|
||||||
final baseColor = Theme.of(context).extension<StackColors>()!.textSubtitle2;
|
|
||||||
return MaterialRoundedDatePickerStyle(
|
|
||||||
backgroundPicker: Theme.of(context).extension<StackColors>()!.popupBG,
|
|
||||||
paddingMonthHeader: const EdgeInsets.only(top: 11),
|
|
||||||
colorArrowNext: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
|
||||||
colorArrowPrevious:
|
|
||||||
Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
|
||||||
textStyleButtonNegative: STextStyles.datePicker600(context).copyWith(
|
|
||||||
color: baseColor,
|
|
||||||
),
|
|
||||||
textStyleButtonPositive: STextStyles.datePicker600(context).copyWith(
|
|
||||||
color: baseColor,
|
|
||||||
),
|
|
||||||
textStyleCurrentDayOnCalendar: STextStyles.datePicker400(context),
|
|
||||||
textStyleDayHeader: STextStyles.datePicker600(context),
|
|
||||||
textStyleDayOnCalendar: STextStyles.datePicker400(context).copyWith(
|
|
||||||
color: baseColor,
|
|
||||||
),
|
|
||||||
textStyleDayOnCalendarDisabled: STextStyles.datePicker400(context).copyWith(
|
|
||||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle3,
|
|
||||||
),
|
|
||||||
textStyleDayOnCalendarSelected: STextStyles.datePicker400(context).copyWith(
|
|
||||||
color: Theme.of(context).extension<StackColors>()!.textWhite,
|
|
||||||
),
|
|
||||||
textStyleMonthYearHeader: STextStyles.datePicker600(context).copyWith(
|
|
||||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle1,
|
|
||||||
),
|
|
||||||
textStyleYearButton: STextStyles.datePicker600(context).copyWith(
|
|
||||||
color: Theme.of(context).extension<StackColors>()!.textWhite,
|
|
||||||
),
|
|
||||||
textStyleButtonAction: GoogleFonts.inter(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialRoundedYearPickerStyle _buildYearPickerStyle(BuildContext context) {
|
|
||||||
return MaterialRoundedYearPickerStyle(
|
|
||||||
backgroundPicker: Theme.of(context).extension<StackColors>()!.popupBG,
|
|
||||||
textStyleYear: STextStyles.datePicker600(context).copyWith(
|
|
||||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle2,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
textStyleYearSelected: STextStyles.datePicker600(context).copyWith(
|
|
||||||
fontSize: 18,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
return date?.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<DateTime?>?> _showDatePickerDialog({
|
||||||
|
required BuildContext context,
|
||||||
|
required CalendarDatePicker2WithActionButtonsConfig config,
|
||||||
|
required Size dialogSize,
|
||||||
|
List<DateTime?> value = const [],
|
||||||
|
bool useRootNavigator = true,
|
||||||
|
bool barrierDismissible = true,
|
||||||
|
Color? barrierColor = Colors.black54,
|
||||||
|
bool useSafeArea = true,
|
||||||
|
RouteSettings? routeSettings,
|
||||||
|
String? barrierLabel,
|
||||||
|
TransitionBuilder? builder,
|
||||||
|
}) {
|
||||||
|
final dialog = Dialog(
|
||||||
|
insetPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 16,
|
||||||
|
),
|
||||||
|
backgroundColor: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
surfaceTintColor: Colors.transparent,
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
elevation: 0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius * 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: SizedBox(
|
||||||
|
width: dialogSize.width,
|
||||||
|
height: max(dialogSize.height, 410),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_SWDatePicker(
|
||||||
|
value: value,
|
||||||
|
config: config.copyWith(openedFromDialog: true),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return showDialog<List<DateTime?>>(
|
||||||
|
context: context,
|
||||||
|
useRootNavigator: useRootNavigator,
|
||||||
|
routeSettings: routeSettings,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return builder == null ? dialog : builder(context, dialog);
|
||||||
|
},
|
||||||
|
barrierDismissible: barrierDismissible,
|
||||||
|
barrierColor: barrierColor,
|
||||||
|
barrierLabel: barrierLabel,
|
||||||
|
useSafeArea: useSafeArea,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
184
lib/widgets/date_picker/sw_date_picker.dart
Normal file
184
lib/widgets/date_picker/sw_date_picker.dart
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
part of 'date_picker.dart';
|
||||||
|
|
||||||
|
class _SWDatePicker extends StatefulWidget {
|
||||||
|
const _SWDatePicker({
|
||||||
|
super.key,
|
||||||
|
required this.value,
|
||||||
|
required this.config,
|
||||||
|
this.onValueChanged,
|
||||||
|
this.onDisplayedMonthChanged,
|
||||||
|
this.onCancelTapped,
|
||||||
|
this.onOkTapped,
|
||||||
|
});
|
||||||
|
final List<DateTime?> value;
|
||||||
|
|
||||||
|
/// Called when the user taps 'OK' button
|
||||||
|
final ValueChanged<List<DateTime?>>? onValueChanged;
|
||||||
|
|
||||||
|
/// Called when the user navigates to a new month/year in the picker.
|
||||||
|
final ValueChanged<DateTime>? onDisplayedMonthChanged;
|
||||||
|
|
||||||
|
/// The calendar configurations including action buttons
|
||||||
|
final CalendarDatePicker2WithActionButtonsConfig config;
|
||||||
|
|
||||||
|
/// The callback when cancel button is tapped
|
||||||
|
final Function? onCancelTapped;
|
||||||
|
|
||||||
|
/// The callback when ok button is tapped
|
||||||
|
final Function? onOkTapped;
|
||||||
|
@override
|
||||||
|
State<_SWDatePicker> createState() => _SWDatePickerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SWDatePickerState extends State<_SWDatePicker> {
|
||||||
|
List<DateTime?> _values = [];
|
||||||
|
List<DateTime?> _editCache = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_values = widget.value;
|
||||||
|
_editCache = widget.value;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(covariant _SWDatePicker oldWidget) {
|
||||||
|
var isValueSame = oldWidget.value.length == widget.value.length;
|
||||||
|
|
||||||
|
if (isValueSame) {
|
||||||
|
for (int i = 0; i < oldWidget.value.length; i++) {
|
||||||
|
final isSame =
|
||||||
|
(oldWidget.value[i] == null && widget.value[i] == null) ||
|
||||||
|
DateUtils.isSameDay(oldWidget.value[i], widget.value[i]);
|
||||||
|
if (!isSame) {
|
||||||
|
isValueSame = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isValueSame) {
|
||||||
|
_values = widget.value;
|
||||||
|
_editCache = widget.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
hoverColor: Colors.transparent,
|
||||||
|
highlightColor: Colors.transparent,
|
||||||
|
focusColor: Colors.transparent,
|
||||||
|
colorScheme: Theme.of(context).colorScheme.copyWith(
|
||||||
|
background: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
onBackground:
|
||||||
|
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||||
|
surface: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
surfaceVariant:
|
||||||
|
Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
onSurface:
|
||||||
|
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||||
|
onSurfaceVariant:
|
||||||
|
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||||
|
surfaceTint: Colors.transparent,
|
||||||
|
shadow: Colors.transparent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
MediaQuery.removePadding(
|
||||||
|
context: context,
|
||||||
|
child: CalendarDatePicker2(
|
||||||
|
value: [..._editCache],
|
||||||
|
config: widget.config,
|
||||||
|
onValueChanged: (values) => _editCache = values,
|
||||||
|
onDisplayedMonthChanged: widget.onDisplayedMonthChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: widget.config.gapBetweenCalendarAndButtons ?? 10),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
if (!Util.isDesktop)
|
||||||
|
SizedBox(
|
||||||
|
width: widget.config.buttonPadding?.right ?? 0,
|
||||||
|
),
|
||||||
|
ConditionalParent(
|
||||||
|
condition: !Util.isDesktop,
|
||||||
|
builder: (child) => Expanded(
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: widget.config.buttonPadding ?? EdgeInsets.zero,
|
||||||
|
child: ConditionalParent(
|
||||||
|
condition: Util.isDesktop,
|
||||||
|
builder: (child) => SizedBox(
|
||||||
|
width: 140,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
child: SecondaryButton(
|
||||||
|
label: "Cancel",
|
||||||
|
buttonHeight: Util.isDesktop ? ButtonHeight.m : null,
|
||||||
|
onPressed: () {
|
||||||
|
setState(
|
||||||
|
() {
|
||||||
|
_editCache = _values;
|
||||||
|
widget.onCancelTapped?.call();
|
||||||
|
if ((widget.config.openedFromDialog ?? false) &&
|
||||||
|
(widget.config.closeDialogOnCancelTapped ??
|
||||||
|
true)) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if ((widget.config.gapBetweenCalendarAndButtons ?? 0) > 0)
|
||||||
|
SizedBox(width: widget.config.gapBetweenCalendarAndButtons),
|
||||||
|
ConditionalParent(
|
||||||
|
condition: !Util.isDesktop,
|
||||||
|
builder: (child) => Expanded(
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: widget.config.buttonPadding ?? EdgeInsets.zero,
|
||||||
|
child: ConditionalParent(
|
||||||
|
condition: Util.isDesktop,
|
||||||
|
builder: (child) => SizedBox(
|
||||||
|
width: 140,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
child: PrimaryButton(
|
||||||
|
buttonHeight: Util.isDesktop ? ButtonHeight.m : null,
|
||||||
|
label: "Ok",
|
||||||
|
onPressed: () {
|
||||||
|
setState(
|
||||||
|
() {
|
||||||
|
_values = _editCache;
|
||||||
|
widget.onValueChanged?.call(_values);
|
||||||
|
widget.onOkTapped?.call();
|
||||||
|
if ((widget.config.openedFromDialog ?? false) &&
|
||||||
|
(widget.config.closeDialogOnOkTapped ?? true)) {
|
||||||
|
Navigator.pop(context, _values);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
16
pubspec.lock
16
pubspec.lock
|
@ -238,6 +238,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.6.2"
|
version: "8.6.2"
|
||||||
|
calendar_date_picker2:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: calendar_date_picker2
|
||||||
|
sha256: "7ff3f372faff6814a2ba69427d116fb9a3d52e28644b9de4b06db6638fdac798"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -757,14 +765,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
flutter_rounded_date_picker:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_rounded_date_picker
|
|
||||||
sha256: e6aa2dc5d3b44e8bbe85ef901be69eac59ba4136427f11f4c8b2a303e1e774e7
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.4"
|
|
||||||
flutter_secure_storage:
|
flutter_secure_storage:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -124,7 +124,6 @@ dependencies:
|
||||||
decimal: ^2.1.0
|
decimal: ^2.1.0
|
||||||
event_bus: ^2.0.0
|
event_bus: ^2.0.0
|
||||||
uuid: ^3.0.5
|
uuid: ^3.0.5
|
||||||
flutter_rounded_date_picker: ^3.0.1
|
|
||||||
crypto: ^3.0.2
|
crypto: ^3.0.2
|
||||||
barcode_scan2: ^4.2.3
|
barcode_scan2: ^4.2.3
|
||||||
wakelock: ^0.6.2
|
wakelock: ^0.6.2
|
||||||
|
@ -178,6 +177,7 @@ dependencies:
|
||||||
url: https://github.com/cypherstack/espresso-cash-public.git
|
url: https://github.com/cypherstack/espresso-cash-public.git
|
||||||
ref: a83e375678eb22fe544dc125d29bbec0fb833882
|
ref: a83e375678eb22fe544dc125d29bbec0fb833882
|
||||||
path: packages/solana
|
path: packages/solana
|
||||||
|
calendar_date_picker2: ^1.0.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in a new issue