use nicer looking date picker

This commit is contained in:
julian 2024-05-07 16:34:08 -06:00
parent 12c47fcbec
commit 70e9566135
4 changed files with 291 additions and 77 deletions

View file

@ -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,
);
}

View 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);
}
},
);
},
),
),
),
),
],
),
],
),
);
}
}

View file

@ -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:

View file

@ -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: