Allow customizing map browser default time range

This commit is contained in:
Ming Ming 2024-08-24 19:33:21 +08:00
parent f35860c7b6
commit d4d0160642
12 changed files with 281 additions and 80 deletions

View file

@ -19,6 +19,7 @@ import 'package:np_string/np_string.dart';
import 'package:rxdart/rxdart.dart';
part 'pref_controller.g.dart';
part 'pref_controller/type.dart';
part 'pref_controller/util.dart';
@npSubjectAccessor
@ -196,6 +197,13 @@ class PrefController {
value: value,
);
Future<bool> setMapDefaultRangeType(PrefMapDefaultRangeType value) =>
_set<PrefMapDefaultRangeType>(
controller: _mapDefaultRangeTypeController,
setter: (pref, value) => pref.setMapDefaultRangeType(value),
value: value,
);
Future<bool> _set<T>({
required BehaviorSubject<T> controller,
required Future<bool> Function(Pref pref, T value) setter,
@ -317,6 +325,9 @@ class PrefController {
BehaviorSubject.seeded(pref.getLastVersion() ??
// v6 is the last version without saving the version number in pref
(pref.getSetupProgress() == null ? k.version : 6));
@npSubjectAccessor
late final _mapDefaultRangeTypeController = BehaviorSubject.seeded(
pref.getMapDefaultRangeType() ?? PrefMapDefaultRangeType.thisMonth);
}
extension PrefControllerExtension on PrefController {

View file

@ -188,6 +188,15 @@ extension $PrefControllerNpSubjectAccessor on PrefController {
Stream<int> get lastVersionNew => lastVersion.skip(1);
Stream<int> get lastVersionChange => lastVersion.distinct().skip(1);
int get lastVersionValue => _lastVersionController.value;
// _mapDefaultRangeTypeController
ValueStream<PrefMapDefaultRangeType> get mapDefaultRangeType =>
_mapDefaultRangeTypeController.stream;
Stream<PrefMapDefaultRangeType> get mapDefaultRangeTypeNew =>
mapDefaultRangeType.skip(1);
Stream<PrefMapDefaultRangeType> get mapDefaultRangeTypeChange =>
mapDefaultRangeType.distinct().skip(1);
PrefMapDefaultRangeType get mapDefaultRangeTypeValue =>
_mapDefaultRangeTypeController.value;
}
extension $SecurePrefControllerNpSubjectAccessor on SecurePrefController {

View file

@ -0,0 +1,15 @@
part of '../pref_controller.dart';
enum PrefMapDefaultRangeType {
thisMonth(0),
prevMonth(1),
thisYear(2),
;
const PrefMapDefaultRangeType(this.value);
static PrefMapDefaultRangeType fromValue(int value) =>
PrefMapDefaultRangeType.values[value];
final int value;
}

View file

@ -119,6 +119,12 @@ extension on Pref {
return provider.setInt(PrefKey.currentAccountIndex, value);
}
}
PrefMapDefaultRangeType? getMapDefaultRangeType() => provider
.getInt(PrefKey.mapDefaultRangeType)
?.let(PrefMapDefaultRangeType.fromValue);
Future<bool> setMapDefaultRangeType(PrefMapDefaultRangeType value) =>
provider.setInt(PrefKey.mapDefaultRangeType, value.value);
}
MapCoord? _tryMapCoordFromJson(dynamic json) {

View file

@ -115,6 +115,7 @@ enum PrefKey implements PrefKeyInterface {
dontShowVideoPreviewHint,
mapBrowserPrevPosition,
isNewHttpEngine,
mapDefaultRangeType,
;
@override
@ -205,6 +206,8 @@ enum PrefKey implements PrefKeyInterface {
return "mapBrowserPrevPosition";
case PrefKey.isNewHttpEngine:
return "isNewHttpEngine";
case PrefKey.mapDefaultRangeType:
return "mapDefaultRangeType";
}
}
}

View file

@ -1499,6 +1499,7 @@
"mapBrowserDateRangeThisYear": "This year",
"mapBrowserDateRangeCustom": "Custom",
"homeTabMapBrowser": "Map",
"mapBrowserSetDefaultDateRangeButton": "Set as default",
"errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues",
"@errorUnauthenticated": {

View file

@ -258,6 +258,7 @@
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton",
"errorUnauthenticated",
"errorDisconnected",
"errorLocked",
@ -302,7 +303,8 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"de": [
@ -345,7 +347,8 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"el": [
@ -491,7 +494,8 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"es": [
@ -528,7 +532,8 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"fi": [
@ -565,7 +570,8 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"fr": [
@ -602,7 +608,8 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"it": [
@ -644,7 +651,8 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"nl": [
@ -1023,6 +1031,7 @@
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton",
"errorUnauthenticated",
"errorDisconnected",
"errorLocked",
@ -1071,7 +1080,8 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"pt": [
@ -1128,7 +1138,8 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"ru": [
@ -1165,7 +1176,12 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"tr": [
"mapBrowserSetDefaultDateRangeButton"
],
"zh": [
@ -1233,7 +1249,8 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
],
"zh_Hant": [
@ -1395,6 +1412,7 @@
"mapBrowserDateRangePrevMonth",
"mapBrowserDateRangeThisYear",
"mapBrowserDateRangeCustom",
"homeTabMapBrowser"
"homeTabMapBrowser",
"mapBrowserSetDefaultDateRangeButton"
]
}

View file

@ -19,6 +19,7 @@ abstract class $_StateCopyWithWorker {
bool? isShowDataRangeControlPanel,
_DateRangeType? dateRangeType,
DateRange? localDateRange,
_DateRangeType? prefDateRangeType,
ExceptionEvent? error});
}
@ -32,6 +33,7 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
dynamic isShowDataRangeControlPanel,
dynamic dateRangeType,
dynamic localDateRange,
dynamic prefDateRangeType,
dynamic error = copyWithNull}) {
return _State(
data: data as List<_DataPoint>? ?? that.data,
@ -42,6 +44,8 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
that.isShowDataRangeControlPanel,
dateRangeType: dateRangeType as _DateRangeType? ?? that.dateRangeType,
localDateRange: localDateRange as DateRange? ?? that.localDateRange,
prefDateRangeType:
prefDateRangeType as _DateRangeType? ?? that.prefDateRangeType,
error: error == copyWithNull ? that.error : error as ExceptionEvent?);
}
@ -85,7 +89,7 @@ extension _$_GoogleMarkerBitmapBuilderNpLog on _GoogleMarkerBitmapBuilder {
extension _$_StateToString on _State {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "_State {data: [length: ${data.length}], initialPoint: $initialPoint, isShowDataRangeControlPanel: $isShowDataRangeControlPanel, dateRangeType: ${dateRangeType.name}, localDateRange: $localDateRange, error: $error}";
return "_State {data: [length: ${data.length}], initialPoint: $initialPoint, isShowDataRangeControlPanel: $isShowDataRangeControlPanel, dateRangeType: ${dateRangeType.name}, localDateRange: $localDateRange, prefDateRangeType: ${prefDateRangeType.name}, error: $error}";
}
}
@ -124,6 +128,20 @@ extension _$_SetLocalDateRangeToString on _SetLocalDateRange {
}
}
extension _$_SetPrefDateRangeTypeToString on _SetPrefDateRangeType {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "_SetPrefDateRangeType {value: ${value.name}}";
}
}
extension _$_SetAsDefaultRangeToString on _SetAsDefaultRange {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "_SetAsDefaultRange {}";
}
}
extension _$_SetErrorToString on _SetError {
String _$toString() {
// ignore: unnecessary_string_interpolations

View file

@ -7,16 +7,14 @@ class _Bloc extends Bloc<_Event, _State>
this._c, {
required this.account,
required this.prefController,
}) : super(_State.init(
dateRangeType: _DateRangeType.thisMonth,
localDateRange:
_calcDateRange(clock.now().toDate(), _DateRangeType.thisMonth),
)) {
}) : super(_Bloc._getInitialState(prefController)) {
on<_LoadData>(_onLoadData);
on<_OpenDataRangeControlPanel>(_onOpenDataRangeControlPanel);
on<_CloseControlPanel>(_onCloseControlPanel);
on<_SetDateRangeType>(_onSetDateRangeType);
on<_SetLocalDateRange>(_onSetDateRange);
on<_SetPrefDateRangeType>(_onSetPrefDateRangeType);
on<_SetAsDefaultRange>(_onSetAsDefaultRange);
on<_SetError>(_onSetError);
_subscriptions.add(stream
@ -24,6 +22,9 @@ class _Bloc extends Bloc<_Event, _State>
.listen((state) {
add(const _LoadData());
}));
_subscriptions.add(prefController.mapDefaultRangeTypeChange.listen((state) {
add(_SetPrefDateRangeType(_DateRangeType.fromPref(state)));
}));
}
@override
@ -50,6 +51,15 @@ class _Bloc extends Bloc<_Event, _State>
super.onError(error, stackTrace);
}
static _State _getInitialState(PrefController prefController) {
final dateRangeType =
_DateRangeType.fromPref(prefController.mapDefaultRangeTypeValue);
return _State.init(
dateRangeType: dateRangeType,
localDateRange: _calcDateRange(clock.now().toDate(), dateRangeType),
);
}
Future<void> _onLoadData(_LoadData ev, Emitter<_State> emit) async {
_log.info(ev);
// convert local DateRange to TimeRange in UTC
@ -110,6 +120,16 @@ class _Bloc extends Bloc<_Event, _State>
));
}
void _onSetPrefDateRangeType(_SetPrefDateRangeType ev, Emitter<_State> emit) {
_log.info(ev);
emit(state.copyWith(prefDateRangeType: ev.value));
}
void _onSetAsDefaultRange(_SetAsDefaultRange ev, Emitter<_State> emit) {
_log.info(ev);
prefController.setMapDefaultRangeType(state.dateRangeType.toPref());
}
void _onSetError(_SetError ev, Emitter<_State> emit) {
_log.info(ev);
emit(state.copyWith(error: ExceptionEvent(ev.error, ev.stackTrace)));

View file

@ -9,18 +9,21 @@ class _State {
required this.isShowDataRangeControlPanel,
required this.dateRangeType,
required this.localDateRange,
required this.prefDateRangeType,
this.error,
});
factory _State.init({
required _DateRangeType dateRangeType,
required DateRange localDateRange,
_DateRangeType? prefDateRangeType,
}) {
return _State(
data: const [],
isShowDataRangeControlPanel: false,
dateRangeType: dateRangeType,
localDateRange: localDateRange,
prefDateRangeType: prefDateRangeType ?? dateRangeType,
);
}
@ -33,6 +36,7 @@ class _State {
final bool isShowDataRangeControlPanel;
final _DateRangeType dateRangeType;
final DateRange localDateRange;
final _DateRangeType prefDateRangeType;
final ExceptionEvent? error;
}
@ -85,6 +89,24 @@ class _SetLocalDateRange implements _Event {
final DateRange value;
}
@toString
class _SetPrefDateRangeType implements _Event {
const _SetPrefDateRangeType(this.value);
@override
String toString() => _$toString();
final _DateRangeType value;
}
@toString
class _SetAsDefaultRange implements _Event {
const _SetAsDefaultRange();
@override
String toString() => _$toString();
}
@toString
class _SetError implements _Event {
const _SetError(this.error, [this.stackTrace]);

View file

@ -251,6 +251,17 @@ enum _DateRangeType {
custom,
;
static _DateRangeType fromPref(PrefMapDefaultRangeType value) {
switch (value) {
case PrefMapDefaultRangeType.thisMonth:
return thisMonth;
case PrefMapDefaultRangeType.prevMonth:
return prevMonth;
case PrefMapDefaultRangeType.thisYear:
return thisYear;
}
}
String toDisplayString() {
switch (this) {
case thisMonth:
@ -263,4 +274,17 @@ enum _DateRangeType {
return L10n.global().mapBrowserDateRangeCustom;
}
}
PrefMapDefaultRangeType toPref() {
switch (this) {
case thisMonth:
return PrefMapDefaultRangeType.thisMonth;
case prevMonth:
return PrefMapDefaultRangeType.prevMonth;
case thisYear:
return PrefMapDefaultRangeType.thisYear;
case custom:
throw ArgumentError("Value not supported");
}
}
}

View file

@ -246,6 +246,8 @@ class _DateRangeControlPanel extends StatelessWidget {
),
],
),
child: Material(
type: MaterialType.transparency,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
@ -313,9 +315,15 @@ class _DateRangeControlPanel extends StatelessWidget {
],
),
const SizedBox(height: 8),
const Align(
alignment: Alignment.centerRight,
child: _SetAsDefaultSwitch(),
),
const SizedBox(height: 8),
],
),
),
),
);
}
}
@ -384,3 +392,49 @@ class _DateFieldState extends State<_DateField> {
late final _controller = TextEditingController(text: _stringify(widget.date));
}
class _SetAsDefaultSwitch extends StatelessWidget {
const _SetAsDefaultSwitch();
@override
Widget build(BuildContext context) {
return _BlocBuilder(
buildWhen: (previous, current) =>
previous.dateRangeType != current.dateRangeType ||
previous.prefDateRangeType != current.prefDateRangeType,
builder: (context, state) {
final isChecked = state.dateRangeType == state.prefDateRangeType;
final isEnabled = state.dateRangeType != _DateRangeType.custom;
return InkWell(
customBorder:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(64)),
onTap: isEnabled && !isChecked
? () {
if (!isChecked) {
context.addEvent(const _SetAsDefaultRange());
}
}
: null,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(width: 16),
Text(
L10n.global().mapBrowserSetDefaultDateRangeButton,
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: isEnabled ? null : Theme.of(context).disabledColor,
),
),
IgnorePointer(
child: Checkbox(
value: isChecked,
onChanged: isEnabled ? (_) {} : null,
),
),
],
),
);
},
);
}
}