mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-31 15:59:26 +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_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/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.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 {
|
||||
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,
|
||||
initialDate: DateTime.now(),
|
||||
height: MediaQuery.of(context).size.height / 3.0,
|
||||
theme: ThemeData(
|
||||
primarySwatch: Util.createMaterialColor(
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark),
|
||||
),
|
||||
//TODO pick a better initial date
|
||||
// 2007 chosen as that is just before bitcoin launched
|
||||
firstDate: DateTime(2007),
|
||||
lastDate: DateTime.now(),
|
||||
borderRadius: Constants.size.circularBorderRadius * 2,
|
||||
|
||||
textPositiveButton: "SELECT",
|
||||
|
||||
styleDatePicker: _buildDatePickerStyle(context),
|
||||
styleYearPicker: _buildYearPickerStyle(context),
|
||||
);
|
||||
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,
|
||||
value: [now],
|
||||
dialogSize: size,
|
||||
config: CalendarDatePicker2WithActionButtonsConfig(
|
||||
firstDate: DateTime(2007),
|
||||
lastDate: now,
|
||||
currentDate: now,
|
||||
buttonPadding: const EdgeInsets.only(
|
||||
right: 16,
|
||||
),
|
||||
centerAlignModePicker: true,
|
||||
selectedDayHighlightColor:
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||
daySplashColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark
|
||||
.withOpacity(0.6),
|
||||
),
|
||||
);
|
||||
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"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -757,14 +765,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -124,7 +124,6 @@ dependencies:
|
|||
decimal: ^2.1.0
|
||||
event_bus: ^2.0.0
|
||||
uuid: ^3.0.5
|
||||
flutter_rounded_date_picker: ^3.0.1
|
||||
crypto: ^3.0.2
|
||||
barcode_scan2: ^4.2.3
|
||||
wakelock: ^0.6.2
|
||||
|
@ -178,6 +177,7 @@ dependencies:
|
|||
url: https://github.com/cypherstack/espresso-cash-public.git
|
||||
ref: a83e375678eb22fe544dc125d29bbec0fb833882
|
||||
path: packages/solana
|
||||
calendar_date_picker2: ^1.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Reference in a new issue