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

View file

@ -188,6 +188,15 @@ extension $PrefControllerNpSubjectAccessor on PrefController {
Stream<int> get lastVersionNew => lastVersion.skip(1); Stream<int> get lastVersionNew => lastVersion.skip(1);
Stream<int> get lastVersionChange => lastVersion.distinct().skip(1); Stream<int> get lastVersionChange => lastVersion.distinct().skip(1);
int get lastVersionValue => _lastVersionController.value; 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 { 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); 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) { MapCoord? _tryMapCoordFromJson(dynamic json) {

View file

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

View file

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

View file

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

View file

@ -19,6 +19,7 @@ abstract class $_StateCopyWithWorker {
bool? isShowDataRangeControlPanel, bool? isShowDataRangeControlPanel,
_DateRangeType? dateRangeType, _DateRangeType? dateRangeType,
DateRange? localDateRange, DateRange? localDateRange,
_DateRangeType? prefDateRangeType,
ExceptionEvent? error}); ExceptionEvent? error});
} }
@ -32,6 +33,7 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
dynamic isShowDataRangeControlPanel, dynamic isShowDataRangeControlPanel,
dynamic dateRangeType, dynamic dateRangeType,
dynamic localDateRange, dynamic localDateRange,
dynamic prefDateRangeType,
dynamic error = copyWithNull}) { dynamic error = copyWithNull}) {
return _State( return _State(
data: data as List<_DataPoint>? ?? that.data, data: data as List<_DataPoint>? ?? that.data,
@ -42,6 +44,8 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
that.isShowDataRangeControlPanel, that.isShowDataRangeControlPanel,
dateRangeType: dateRangeType as _DateRangeType? ?? that.dateRangeType, dateRangeType: dateRangeType as _DateRangeType? ?? that.dateRangeType,
localDateRange: localDateRange as DateRange? ?? that.localDateRange, localDateRange: localDateRange as DateRange? ?? that.localDateRange,
prefDateRangeType:
prefDateRangeType as _DateRangeType? ?? that.prefDateRangeType,
error: error == copyWithNull ? that.error : error as ExceptionEvent?); error: error == copyWithNull ? that.error : error as ExceptionEvent?);
} }
@ -85,7 +89,7 @@ extension _$_GoogleMarkerBitmapBuilderNpLog on _GoogleMarkerBitmapBuilder {
extension _$_StateToString on _State { extension _$_StateToString on _State {
String _$toString() { String _$toString() {
// ignore: unnecessary_string_interpolations // 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 { extension _$_SetErrorToString on _SetError {
String _$toString() { String _$toString() {
// ignore: unnecessary_string_interpolations // ignore: unnecessary_string_interpolations

View file

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

View file

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

View file

@ -251,6 +251,17 @@ enum _DateRangeType {
custom, 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() { String toDisplayString() {
switch (this) { switch (this) {
case thisMonth: case thisMonth:
@ -263,4 +274,17 @@ enum _DateRangeType {
return L10n.global().mapBrowserDateRangeCustom; 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( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column( child: Column(
@ -313,9 +315,15 @@ class _DateRangeControlPanel extends StatelessWidget {
], ],
), ),
const SizedBox(height: 8), 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)); 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,
),
),
],
),
);
},
);
}
}