refactor(device_management): migrate activity_meter to Riverpod
This commit is contained in:
@@ -1,48 +1,28 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:device_management/src/core/presentation/format_date.dart';
|
||||
import 'package:device_management/src/core/presentation/time_range.dart';
|
||||
import 'package:device_management/src/core/presentation/widgets/time_range_selector.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/providers/activity_meter_controller.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/providers/activity_meter_state.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/widgets/activity_footers.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/widgets/hourly_bar_chart.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/widgets/pedometer_toggle.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/widgets/section_header.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/widgets/steps_bar_chart.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/widgets/steps_history_section.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/widgets/steps_progress_ring.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:legacy_ui/legacy_ui.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
import '../../../core/presentation/format_date.dart';
|
||||
import '../../../core/presentation/time_range.dart';
|
||||
import '../../../core/presentation/widgets/time_range_selector.dart';
|
||||
import 'state/activity_meter_view_model.dart';
|
||||
import 'state/activity_meter_view_state.dart';
|
||||
import 'widgets/activity_footers.dart';
|
||||
import 'widgets/hourly_bar_chart.dart';
|
||||
import 'widgets/pedometer_toggle.dart';
|
||||
import 'widgets/section_header.dart';
|
||||
import 'widgets/steps_bar_chart.dart';
|
||||
import 'widgets/steps_history_section.dart';
|
||||
import 'widgets/steps_progress_ring.dart';
|
||||
|
||||
class ActivityMeterScreen extends ConsumerWidget {
|
||||
const ActivityMeterScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isLoading = ref.watch(
|
||||
activityMeterViewModelProvider.select((s) => s.isLoading),
|
||||
);
|
||||
|
||||
ref.listen(activityMeterViewModelProvider.select((s) => s.errorEvent), (
|
||||
_,
|
||||
next,
|
||||
) {
|
||||
if (next == null) return;
|
||||
final message = switch (next) {
|
||||
ActivityMeterErrorEvent.loadData ||
|
||||
ActivityMeterErrorEvent.loadMore => context.translate(
|
||||
I18n.errorActivityData,
|
||||
),
|
||||
ActivityMeterErrorEvent.pedometer => context.translate(
|
||||
I18n.errorPedometer,
|
||||
),
|
||||
};
|
||||
showTopSnackbar(context, message: message, type: MessageType.error);
|
||||
});
|
||||
final isLoading =
|
||||
ref.watch(activityMeterControllerProvider.select((s) => s.isLoading));
|
||||
|
||||
return LegacyPageLayout(
|
||||
title: context.translate(I18n.activityMeter),
|
||||
@@ -58,10 +38,9 @@ class _ActivityMeterBody extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final vm = ref.read(activityMeterViewModelProvider.notifier);
|
||||
final timeRange = ref.watch(
|
||||
activityMeterViewModelProvider.select((s) => s.timeRange),
|
||||
);
|
||||
final timeRange = ref
|
||||
.watch(activityMeterControllerProvider.select((s) => s.timeRange));
|
||||
final notifier = ref.read(activityMeterControllerProvider.notifier);
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
@@ -73,8 +52,8 @@ class _ActivityMeterBody extends ConsumerWidget {
|
||||
const _ActivityRangeHeader(),
|
||||
TimeRangeSelector(
|
||||
selected: timeRange,
|
||||
onSelected: vm.selectTimeRange,
|
||||
onCustomTap: () => _pickCustomRange(context, vm),
|
||||
onSelected: notifier.selectTimeRange,
|
||||
onCustomTap: () => _pickCustomRange(context, notifier),
|
||||
),
|
||||
const _ActivitySection(),
|
||||
if (timeRange != TimeRange.today) const _HistorySection(),
|
||||
@@ -86,7 +65,7 @@ class _ActivityMeterBody extends ConsumerWidget {
|
||||
|
||||
Future<void> _pickCustomRange(
|
||||
BuildContext context,
|
||||
ActivityMeterViewModel vm,
|
||||
ActivityMeterController notifier,
|
||||
) async {
|
||||
final now = DateTime.now();
|
||||
final picked = await showDateRangePicker(
|
||||
@@ -95,7 +74,7 @@ class _ActivityMeterBody extends ConsumerWidget {
|
||||
lastDate: now,
|
||||
);
|
||||
if (picked != null) {
|
||||
vm.selectCustomRange(picked.start, picked.end);
|
||||
notifier.selectCustomRange(picked.start, picked.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +85,7 @@ class _TodaySection extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final (todayTotal, dailyGoal) = ref.watch(
|
||||
activityMeterViewModelProvider.select(
|
||||
activityMeterControllerProvider.select(
|
||||
(s) => (s.todayTotal, s.dailyGoal),
|
||||
),
|
||||
);
|
||||
@@ -125,7 +104,9 @@ class _TodaySection extends ConsumerWidget {
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: SizeUtils.getByScreen(small: 13, big: 12),
|
||||
color: Theme.of(context).colorScheme.onSurface
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
@@ -141,7 +122,7 @@ class _ActivityRangeHeader extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final (start, end, timeRange) = ref.watch(
|
||||
activityMeterViewModelProvider.select(
|
||||
activityMeterControllerProvider.select(
|
||||
(s) => (s.rangeStart, s.rangeEnd, s.timeRange),
|
||||
),
|
||||
);
|
||||
@@ -174,7 +155,7 @@ class _ActivitySection extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final (timeRange, hourly, daily, stats, activeHours, hasData) = ref.watch(
|
||||
activityMeterViewModelProvider.select(
|
||||
activityMeterControllerProvider.select(
|
||||
(s) => (
|
||||
s.timeRange,
|
||||
s.hourlyData,
|
||||
@@ -199,7 +180,9 @@ class _ActivitySection extends ConsumerWidget {
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: SizeUtils.getByScreen(small: 13, big: 12),
|
||||
color: Theme.of(context).colorScheme.onSurface
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
@@ -228,9 +211,9 @@ class _HistorySection extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final vm = ref.read(activityMeterViewModelProvider.notifier);
|
||||
final notifier = ref.read(activityMeterControllerProvider.notifier);
|
||||
final (history, dailyGoal, hasMore, isLoadingMore) = ref.watch(
|
||||
activityMeterViewModelProvider.select(
|
||||
activityMeterControllerProvider.select(
|
||||
(s) => (s.historyData, s.dailyGoal, s.hasMoreHistory, s.isLoadingMore),
|
||||
),
|
||||
);
|
||||
@@ -248,7 +231,7 @@ class _HistorySection extends ConsumerWidget {
|
||||
dailyGoal: dailyGoal,
|
||||
hasMore: hasMore,
|
||||
isLoadingMore: isLoadingMore,
|
||||
onLoadMore: vm.loadMoreHistory,
|
||||
onLoadMore: notifier.loadMoreHistory,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import '../../../../core/domain/entities/steps_entity.dart';
|
||||
import '../../../../core/presentation/time_range.dart';
|
||||
import 'activity_meter_view_state.dart';
|
||||
import 'package:device_management/src/core/domain/entities/steps_entity.dart';
|
||||
import 'package:device_management/src/core/presentation/time_range.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/providers/activity_meter_state.dart';
|
||||
|
||||
List<DailySteps> groupByDay(List<StepsEntity> steps) {
|
||||
final Map<DateTime, int> groups = {};
|
||||
@@ -1,36 +1,26 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:legacy_device_state/legacy_device_state.dart';
|
||||
import 'package:device_management/src/core/data/datasources/health_query_builder.dart';
|
||||
import 'package:device_management/src/core/domain/entities/steps_entity.dart';
|
||||
import 'package:device_management/src/core/domain/repositories/steps_repository.dart';
|
||||
import 'package:device_management/src/core/presentation/time_range.dart';
|
||||
import 'package:device_management/src/core/providers/steps_repository_provider.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/providers/activity_meter_aggregator.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/providers/activity_meter_state.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:sf_shared/sf_shared.dart';
|
||||
import 'package:sf_tracking/sf_tracking.dart';
|
||||
|
||||
import '../../../../core/data/datasources/health_query_builder.dart';
|
||||
import '../../../../core/domain/entities/steps_entity.dart';
|
||||
import '../../../../core/domain/repositories/steps_repository.dart';
|
||||
import '../../../../core/presentation/time_range.dart';
|
||||
import '../../../../core/providers/steps_repository_provider.dart';
|
||||
import 'activity_meter_aggregator.dart';
|
||||
import 'activity_meter_view_state.dart';
|
||||
part 'activity_meter_controller.g.dart';
|
||||
|
||||
final activityMeterViewModelProvider =
|
||||
NotifierProvider.autoDispose<
|
||||
ActivityMeterViewModel,
|
||||
ActivityMeterViewState
|
||||
>(ActivityMeterViewModel.new);
|
||||
|
||||
class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
|
||||
late final StepsRepository _repository;
|
||||
late final SfTrackingRepository _tracking;
|
||||
|
||||
static const int _historyPageSize = 20;
|
||||
const int _historyPageSize = 20;
|
||||
|
||||
@riverpod
|
||||
class ActivityMeterController extends _$ActivityMeterController {
|
||||
@override
|
||||
ActivityMeterViewState build() {
|
||||
_repository = ref.read(stepsRepositoryProvider);
|
||||
_tracking = ref.read(sfTrackingProvider);
|
||||
ActivityMeterState build() {
|
||||
Future.microtask(_loadFilteredData);
|
||||
return const ActivityMeterViewState();
|
||||
return const ActivityMeterState();
|
||||
}
|
||||
|
||||
String? get _identificator =>
|
||||
@@ -40,9 +30,9 @@ class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
|
||||
if (range == state.timeRange) return;
|
||||
state = state.copyWith(timeRange: range, isLoading: true);
|
||||
unawaited(
|
||||
_tracking.legacyDeviceActivityMeterTimeRangeChanged(
|
||||
_timeRangeName(range),
|
||||
),
|
||||
ref
|
||||
.read(sfTrackingProvider)
|
||||
.legacyDeviceActivityMeterTimeRangeChanged(_timeRangeName(range)),
|
||||
);
|
||||
await _loadFilteredData();
|
||||
}
|
||||
@@ -54,22 +44,20 @@ class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
|
||||
customEnd: end,
|
||||
isLoading: true,
|
||||
);
|
||||
unawaited(_tracking.legacyDeviceActivityMeterTimeRangeChanged('custom'));
|
||||
unawaited(
|
||||
ref
|
||||
.read(sfTrackingProvider)
|
||||
.legacyDeviceActivityMeterTimeRangeChanged('custom'),
|
||||
);
|
||||
await _loadFilteredData();
|
||||
}
|
||||
|
||||
String _timeRangeName(TimeRange range) {
|
||||
switch (range) {
|
||||
case TimeRange.today:
|
||||
return 'today';
|
||||
case TimeRange.sevenDays:
|
||||
return 'seven_days';
|
||||
case TimeRange.thirtyDays:
|
||||
return 'thirty_days';
|
||||
case TimeRange.custom:
|
||||
return 'custom';
|
||||
}
|
||||
}
|
||||
String _timeRangeName(TimeRange range) => switch (range) {
|
||||
TimeRange.today => 'today',
|
||||
TimeRange.sevenDays => 'seven_days',
|
||||
TimeRange.thirtyDays => 'thirty_days',
|
||||
TimeRange.custom => 'custom',
|
||||
};
|
||||
|
||||
Future<void> loadMoreHistory() async {
|
||||
if (state.isLoadingMore || !state.hasMoreHistory) return;
|
||||
@@ -86,15 +74,16 @@ class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
|
||||
end: end,
|
||||
);
|
||||
|
||||
final steps = await _repository.getSteps(
|
||||
identificator: identificator,
|
||||
queryParameters: HealthQueryBuilder.build(
|
||||
orderDirection: OrderDirection.desc,
|
||||
page: nextPage,
|
||||
pageSize: _historyPageSize,
|
||||
filters: filters,
|
||||
),
|
||||
);
|
||||
final steps =
|
||||
await ref.read(stepsRepositoryProvider).getSteps(
|
||||
identificator: identificator,
|
||||
queryParameters: HealthQueryBuilder.build(
|
||||
orderDirection: OrderDirection.desc,
|
||||
page: nextPage,
|
||||
pageSize: _historyPageSize,
|
||||
filters: filters,
|
||||
),
|
||||
);
|
||||
if (!ref.mounted) return;
|
||||
|
||||
final newDaily = groupByDay(steps);
|
||||
@@ -108,10 +97,7 @@ class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
|
||||
);
|
||||
} catch (_) {
|
||||
if (!ref.mounted) return;
|
||||
state = state.copyWith(
|
||||
isLoadingMore: false,
|
||||
errorEvent: ActivityMeterErrorEvent.loadMore,
|
||||
);
|
||||
state = state.copyWith(isLoadingMore: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +108,7 @@ class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
|
||||
return;
|
||||
}
|
||||
|
||||
final repo = ref.read(stepsRepositoryProvider);
|
||||
try {
|
||||
final (start, end) = _resolveRange();
|
||||
final filters = HealthQueryBuilder.timeRangeFilters(
|
||||
@@ -130,14 +117,14 @@ class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
|
||||
);
|
||||
|
||||
final (chartSteps, histSteps, todaySteps) = await (
|
||||
_repository.getSteps(
|
||||
repo.getSteps(
|
||||
identificator: identificator,
|
||||
queryParameters: HealthQueryBuilder.build(
|
||||
orderDirection: OrderDirection.asc,
|
||||
filters: filters,
|
||||
),
|
||||
),
|
||||
_repository.getSteps(
|
||||
repo.getSteps(
|
||||
identificator: identificator,
|
||||
queryParameters: HealthQueryBuilder.build(
|
||||
orderDirection: OrderDirection.desc,
|
||||
@@ -146,7 +133,7 @@ class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
|
||||
filters: filters,
|
||||
),
|
||||
),
|
||||
_fetchTodaySteps(identificator),
|
||||
_fetchTodaySteps(repo, identificator),
|
||||
).wait;
|
||||
if (!ref.mounted) return;
|
||||
|
||||
@@ -174,21 +161,20 @@ class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
|
||||
rangeStart: start,
|
||||
rangeEnd: end,
|
||||
isLoading: false,
|
||||
errorEvent: null,
|
||||
);
|
||||
} catch (_) {
|
||||
if (!ref.mounted) return;
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
errorEvent: ActivityMeterErrorEvent.loadData,
|
||||
);
|
||||
state = state.copyWith(isLoading: false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<StepsEntity>> _fetchTodaySteps(String identificator) {
|
||||
Future<List<StepsEntity>> _fetchTodaySteps(
|
||||
StepsRepository repo,
|
||||
String identificator,
|
||||
) {
|
||||
final now = DateTime.now();
|
||||
final todayStart = DateTime(now.year, now.month, now.day);
|
||||
return _repository.getSteps(
|
||||
return repo.getSteps(
|
||||
identificator: identificator,
|
||||
queryParameters: HealthQueryBuilder.build(
|
||||
orderDirection: OrderDirection.asc,
|
||||
@@ -201,35 +187,9 @@ class ActivityMeterViewModel extends Notifier<ActivityMeterViewState> {
|
||||
}
|
||||
|
||||
(DateTime, DateTime) _resolveRange() => resolveRange(
|
||||
state.timeRange,
|
||||
now: DateTime.now(),
|
||||
customStart: state.customStart,
|
||||
customEnd: state.customEnd,
|
||||
);
|
||||
|
||||
Future<bool> togglePedometer({required bool enabled}) async {
|
||||
final device = ref.read(selectedDeviceProvider).value;
|
||||
if (device == null) return false;
|
||||
|
||||
state = state.copyWith(errorEvent: null);
|
||||
try {
|
||||
final updatedSettings = device.settings.copyWith(pedometer: enabled);
|
||||
await ref
|
||||
.read(deviceSettingsUpdateProvider)
|
||||
.updateDeviceSettings(
|
||||
device: device,
|
||||
updatedSettings: updatedSettings,
|
||||
);
|
||||
if (!ref.mounted) return false;
|
||||
ref.syncDeviceSettings(device, updatedSettings);
|
||||
|
||||
unawaited(_tracking.legacyDeviceActivityPedometerToggled(enabled));
|
||||
|
||||
return true;
|
||||
} catch (_) {
|
||||
if (!ref.mounted) return false;
|
||||
state = state.copyWith(errorEvent: ActivityMeterErrorEvent.pedometer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state.timeRange,
|
||||
now: DateTime.now(),
|
||||
customStart: state.customStart,
|
||||
customEnd: state.customEnd,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'activity_meter_controller.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(ActivityMeterController)
|
||||
const activityMeterControllerProvider = ActivityMeterControllerProvider._();
|
||||
|
||||
final class ActivityMeterControllerProvider
|
||||
extends $NotifierProvider<ActivityMeterController, ActivityMeterState> {
|
||||
const ActivityMeterControllerProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'activityMeterControllerProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$activityMeterControllerHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
ActivityMeterController create() => ActivityMeterController();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(ActivityMeterState value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<ActivityMeterState>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$activityMeterControllerHash() =>
|
||||
r'693b7f7a3d5f2aca66d69fcba538cd3e5f2d9498';
|
||||
|
||||
abstract class _$ActivityMeterController extends $Notifier<ActivityMeterState> {
|
||||
ActivityMeterState build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<ActivityMeterState, ActivityMeterState>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<ActivityMeterState, ActivityMeterState>,
|
||||
ActivityMeterState,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,22 @@
|
||||
import 'package:device_management/src/core/presentation/time_range.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import '../../../../core/presentation/time_range.dart';
|
||||
|
||||
part 'activity_meter_view_state.freezed.dart';
|
||||
|
||||
enum ActivityMeterErrorEvent { loadData, loadMore, pedometer }
|
||||
part 'activity_meter_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
abstract class DailySteps with _$DailySteps {
|
||||
const factory DailySteps({required DateTime date, required int totalSteps}) =
|
||||
_DailySteps;
|
||||
const factory DailySteps({
|
||||
required DateTime date,
|
||||
required int totalSteps,
|
||||
}) = _DailySteps;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class HourlySteps with _$HourlySteps {
|
||||
const factory HourlySteps({required int hour, required int totalSteps}) =
|
||||
_HourlySteps;
|
||||
const factory HourlySteps({
|
||||
required int hour,
|
||||
required int totalSteps,
|
||||
}) = _HourlySteps;
|
||||
}
|
||||
|
||||
@freezed
|
||||
@@ -30,8 +31,8 @@ abstract class StepsStats with _$StepsStats {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class ActivityMeterViewState with _$ActivityMeterViewState {
|
||||
const factory ActivityMeterViewState({
|
||||
abstract class ActivityMeterState with _$ActivityMeterState {
|
||||
const factory ActivityMeterState({
|
||||
@Default(0) int todayTotal,
|
||||
@Default(8000) int dailyGoal,
|
||||
@Default([]) List<DailySteps> chartData,
|
||||
@@ -48,11 +49,10 @@ abstract class ActivityMeterViewState with _$ActivityMeterViewState {
|
||||
DateTime? rangeEnd,
|
||||
@Default(true) bool isLoading,
|
||||
@Default(false) bool isLoadingMore,
|
||||
ActivityMeterErrorEvent? errorEvent,
|
||||
}) = _ActivityMeterViewState;
|
||||
}) = _ActivityMeterState;
|
||||
}
|
||||
|
||||
extension ActivityMeterViewStateX on ActivityMeterViewState {
|
||||
extension ActivityMeterStateX on ActivityMeterState {
|
||||
bool get hasActivityData => timeRange == TimeRange.today
|
||||
? hourlyData.any((h) => h.totalSteps > 0)
|
||||
: stats.total > 0;
|
||||
@@ -3,7 +3,7 @@
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'activity_meter_view_state.dart';
|
||||
part of 'activity_meter_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
@@ -825,40 +825,40 @@ $DailyStepsCopyWith<$Res>? get bestDay {
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ActivityMeterViewState {
|
||||
mixin _$ActivityMeterState {
|
||||
|
||||
int get todayTotal; int get dailyGoal; List<DailySteps> get chartData; List<HourlySteps> get hourlyData; int get activeHoursToday; List<DailySteps> get historyData; int get currentHistoryPage; bool get hasMoreHistory; StepsStats get stats; TimeRange get timeRange; DateTime? get customStart; DateTime? get customEnd; DateTime? get rangeStart; DateTime? get rangeEnd; bool get isLoading; bool get isLoadingMore; ActivityMeterErrorEvent? get errorEvent;
|
||||
/// Create a copy of ActivityMeterViewState
|
||||
int get todayTotal; int get dailyGoal; List<DailySteps> get chartData; List<HourlySteps> get hourlyData; int get activeHoursToday; List<DailySteps> get historyData; int get currentHistoryPage; bool get hasMoreHistory; StepsStats get stats; TimeRange get timeRange; DateTime? get customStart; DateTime? get customEnd; DateTime? get rangeStart; DateTime? get rangeEnd; bool get isLoading; bool get isLoadingMore;
|
||||
/// Create a copy of ActivityMeterState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ActivityMeterViewStateCopyWith<ActivityMeterViewState> get copyWith => _$ActivityMeterViewStateCopyWithImpl<ActivityMeterViewState>(this as ActivityMeterViewState, _$identity);
|
||||
$ActivityMeterStateCopyWith<ActivityMeterState> get copyWith => _$ActivityMeterStateCopyWithImpl<ActivityMeterState>(this as ActivityMeterState, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ActivityMeterViewState&&(identical(other.todayTotal, todayTotal) || other.todayTotal == todayTotal)&&(identical(other.dailyGoal, dailyGoal) || other.dailyGoal == dailyGoal)&&const DeepCollectionEquality().equals(other.chartData, chartData)&&const DeepCollectionEquality().equals(other.hourlyData, hourlyData)&&(identical(other.activeHoursToday, activeHoursToday) || other.activeHoursToday == activeHoursToday)&&const DeepCollectionEquality().equals(other.historyData, historyData)&&(identical(other.currentHistoryPage, currentHistoryPage) || other.currentHistoryPage == currentHistoryPage)&&(identical(other.hasMoreHistory, hasMoreHistory) || other.hasMoreHistory == hasMoreHistory)&&(identical(other.stats, stats) || other.stats == stats)&&(identical(other.timeRange, timeRange) || other.timeRange == timeRange)&&(identical(other.customStart, customStart) || other.customStart == customStart)&&(identical(other.customEnd, customEnd) || other.customEnd == customEnd)&&(identical(other.rangeStart, rangeStart) || other.rangeStart == rangeStart)&&(identical(other.rangeEnd, rangeEnd) || other.rangeEnd == rangeEnd)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isLoadingMore, isLoadingMore) || other.isLoadingMore == isLoadingMore)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ActivityMeterState&&(identical(other.todayTotal, todayTotal) || other.todayTotal == todayTotal)&&(identical(other.dailyGoal, dailyGoal) || other.dailyGoal == dailyGoal)&&const DeepCollectionEquality().equals(other.chartData, chartData)&&const DeepCollectionEquality().equals(other.hourlyData, hourlyData)&&(identical(other.activeHoursToday, activeHoursToday) || other.activeHoursToday == activeHoursToday)&&const DeepCollectionEquality().equals(other.historyData, historyData)&&(identical(other.currentHistoryPage, currentHistoryPage) || other.currentHistoryPage == currentHistoryPage)&&(identical(other.hasMoreHistory, hasMoreHistory) || other.hasMoreHistory == hasMoreHistory)&&(identical(other.stats, stats) || other.stats == stats)&&(identical(other.timeRange, timeRange) || other.timeRange == timeRange)&&(identical(other.customStart, customStart) || other.customStart == customStart)&&(identical(other.customEnd, customEnd) || other.customEnd == customEnd)&&(identical(other.rangeStart, rangeStart) || other.rangeStart == rangeStart)&&(identical(other.rangeEnd, rangeEnd) || other.rangeEnd == rangeEnd)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isLoadingMore, isLoadingMore) || other.isLoadingMore == isLoadingMore));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,todayTotal,dailyGoal,const DeepCollectionEquality().hash(chartData),const DeepCollectionEquality().hash(hourlyData),activeHoursToday,const DeepCollectionEquality().hash(historyData),currentHistoryPage,hasMoreHistory,stats,timeRange,customStart,customEnd,rangeStart,rangeEnd,isLoading,isLoadingMore,errorEvent);
|
||||
int get hashCode => Object.hash(runtimeType,todayTotal,dailyGoal,const DeepCollectionEquality().hash(chartData),const DeepCollectionEquality().hash(hourlyData),activeHoursToday,const DeepCollectionEquality().hash(historyData),currentHistoryPage,hasMoreHistory,stats,timeRange,customStart,customEnd,rangeStart,rangeEnd,isLoading,isLoadingMore);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ActivityMeterViewState(todayTotal: $todayTotal, dailyGoal: $dailyGoal, chartData: $chartData, hourlyData: $hourlyData, activeHoursToday: $activeHoursToday, historyData: $historyData, currentHistoryPage: $currentHistoryPage, hasMoreHistory: $hasMoreHistory, stats: $stats, timeRange: $timeRange, customStart: $customStart, customEnd: $customEnd, rangeStart: $rangeStart, rangeEnd: $rangeEnd, isLoading: $isLoading, isLoadingMore: $isLoadingMore, errorEvent: $errorEvent)';
|
||||
return 'ActivityMeterState(todayTotal: $todayTotal, dailyGoal: $dailyGoal, chartData: $chartData, hourlyData: $hourlyData, activeHoursToday: $activeHoursToday, historyData: $historyData, currentHistoryPage: $currentHistoryPage, hasMoreHistory: $hasMoreHistory, stats: $stats, timeRange: $timeRange, customStart: $customStart, customEnd: $customEnd, rangeStart: $rangeStart, rangeEnd: $rangeEnd, isLoading: $isLoading, isLoadingMore: $isLoadingMore)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ActivityMeterViewStateCopyWith<$Res> {
|
||||
factory $ActivityMeterViewStateCopyWith(ActivityMeterViewState value, $Res Function(ActivityMeterViewState) _then) = _$ActivityMeterViewStateCopyWithImpl;
|
||||
abstract mixin class $ActivityMeterStateCopyWith<$Res> {
|
||||
factory $ActivityMeterStateCopyWith(ActivityMeterState value, $Res Function(ActivityMeterState) _then) = _$ActivityMeterStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
int todayTotal, int dailyGoal, List<DailySteps> chartData, List<HourlySteps> hourlyData, int activeHoursToday, List<DailySteps> historyData, int currentHistoryPage, bool hasMoreHistory, StepsStats stats, TimeRange timeRange, DateTime? customStart, DateTime? customEnd, DateTime? rangeStart, DateTime? rangeEnd, bool isLoading, bool isLoadingMore, ActivityMeterErrorEvent? errorEvent
|
||||
int todayTotal, int dailyGoal, List<DailySteps> chartData, List<HourlySteps> hourlyData, int activeHoursToday, List<DailySteps> historyData, int currentHistoryPage, bool hasMoreHistory, StepsStats stats, TimeRange timeRange, DateTime? customStart, DateTime? customEnd, DateTime? rangeStart, DateTime? rangeEnd, bool isLoading, bool isLoadingMore
|
||||
});
|
||||
|
||||
|
||||
@@ -866,16 +866,16 @@ $StepsStatsCopyWith<$Res> get stats;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$ActivityMeterViewStateCopyWithImpl<$Res>
|
||||
implements $ActivityMeterViewStateCopyWith<$Res> {
|
||||
_$ActivityMeterViewStateCopyWithImpl(this._self, this._then);
|
||||
class _$ActivityMeterStateCopyWithImpl<$Res>
|
||||
implements $ActivityMeterStateCopyWith<$Res> {
|
||||
_$ActivityMeterStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final ActivityMeterViewState _self;
|
||||
final $Res Function(ActivityMeterViewState) _then;
|
||||
final ActivityMeterState _self;
|
||||
final $Res Function(ActivityMeterState) _then;
|
||||
|
||||
/// Create a copy of ActivityMeterViewState
|
||||
/// Create a copy of ActivityMeterState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? todayTotal = null,Object? dailyGoal = null,Object? chartData = null,Object? hourlyData = null,Object? activeHoursToday = null,Object? historyData = null,Object? currentHistoryPage = null,Object? hasMoreHistory = null,Object? stats = null,Object? timeRange = null,Object? customStart = freezed,Object? customEnd = freezed,Object? rangeStart = freezed,Object? rangeEnd = freezed,Object? isLoading = null,Object? isLoadingMore = null,Object? errorEvent = freezed,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? todayTotal = null,Object? dailyGoal = null,Object? chartData = null,Object? hourlyData = null,Object? activeHoursToday = null,Object? historyData = null,Object? currentHistoryPage = null,Object? hasMoreHistory = null,Object? stats = null,Object? timeRange = null,Object? customStart = freezed,Object? customEnd = freezed,Object? rangeStart = freezed,Object? rangeEnd = freezed,Object? isLoading = null,Object? isLoadingMore = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
todayTotal: null == todayTotal ? _self.todayTotal : todayTotal // ignore: cast_nullable_to_non_nullable
|
||||
as int,dailyGoal: null == dailyGoal ? _self.dailyGoal : dailyGoal // ignore: cast_nullable_to_non_nullable
|
||||
@@ -893,11 +893,10 @@ as DateTime?,rangeStart: freezed == rangeStart ? _self.rangeStart : rangeStart /
|
||||
as DateTime?,rangeEnd: freezed == rangeEnd ? _self.rangeEnd : rangeEnd // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isLoadingMore: null == isLoadingMore ? _self.isLoadingMore : isLoadingMore // ignore: cast_nullable_to_non_nullable
|
||||
as bool,errorEvent: freezed == errorEvent ? _self.errorEvent : errorEvent // ignore: cast_nullable_to_non_nullable
|
||||
as ActivityMeterErrorEvent?,
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
/// Create a copy of ActivityMeterViewState
|
||||
/// Create a copy of ActivityMeterState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
@@ -910,8 +909,8 @@ $StepsStatsCopyWith<$Res> get stats {
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [ActivityMeterViewState].
|
||||
extension ActivityMeterViewStatePatterns on ActivityMeterViewState {
|
||||
/// Adds pattern-matching-related methods to [ActivityMeterState].
|
||||
extension ActivityMeterStatePatterns on ActivityMeterState {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
@@ -924,10 +923,10 @@ extension ActivityMeterViewStatePatterns on ActivityMeterViewState {
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ActivityMeterViewState value)? $default,{required TResult orElse(),}){
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ActivityMeterState value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ActivityMeterViewState() when $default != null:
|
||||
case _ActivityMeterState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
@@ -946,10 +945,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ActivityMeterViewState value) $default,){
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ActivityMeterState value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ActivityMeterViewState():
|
||||
case _ActivityMeterState():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
@@ -967,10 +966,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ActivityMeterViewState value)? $default,){
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ActivityMeterState value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ActivityMeterViewState() when $default != null:
|
||||
case _ActivityMeterState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
@@ -988,10 +987,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int todayTotal, int dailyGoal, List<DailySteps> chartData, List<HourlySteps> hourlyData, int activeHoursToday, List<DailySteps> historyData, int currentHistoryPage, bool hasMoreHistory, StepsStats stats, TimeRange timeRange, DateTime? customStart, DateTime? customEnd, DateTime? rangeStart, DateTime? rangeEnd, bool isLoading, bool isLoadingMore, ActivityMeterErrorEvent? errorEvent)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int todayTotal, int dailyGoal, List<DailySteps> chartData, List<HourlySteps> hourlyData, int activeHoursToday, List<DailySteps> historyData, int currentHistoryPage, bool hasMoreHistory, StepsStats stats, TimeRange timeRange, DateTime? customStart, DateTime? customEnd, DateTime? rangeStart, DateTime? rangeEnd, bool isLoading, bool isLoadingMore)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ActivityMeterViewState() when $default != null:
|
||||
return $default(_that.todayTotal,_that.dailyGoal,_that.chartData,_that.hourlyData,_that.activeHoursToday,_that.historyData,_that.currentHistoryPage,_that.hasMoreHistory,_that.stats,_that.timeRange,_that.customStart,_that.customEnd,_that.rangeStart,_that.rangeEnd,_that.isLoading,_that.isLoadingMore,_that.errorEvent);case _:
|
||||
case _ActivityMeterState() when $default != null:
|
||||
return $default(_that.todayTotal,_that.dailyGoal,_that.chartData,_that.hourlyData,_that.activeHoursToday,_that.historyData,_that.currentHistoryPage,_that.hasMoreHistory,_that.stats,_that.timeRange,_that.customStart,_that.customEnd,_that.rangeStart,_that.rangeEnd,_that.isLoading,_that.isLoadingMore);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -1009,10 +1008,10 @@ return $default(_that.todayTotal,_that.dailyGoal,_that.chartData,_that.hourlyDat
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int todayTotal, int dailyGoal, List<DailySteps> chartData, List<HourlySteps> hourlyData, int activeHoursToday, List<DailySteps> historyData, int currentHistoryPage, bool hasMoreHistory, StepsStats stats, TimeRange timeRange, DateTime? customStart, DateTime? customEnd, DateTime? rangeStart, DateTime? rangeEnd, bool isLoading, bool isLoadingMore, ActivityMeterErrorEvent? errorEvent) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int todayTotal, int dailyGoal, List<DailySteps> chartData, List<HourlySteps> hourlyData, int activeHoursToday, List<DailySteps> historyData, int currentHistoryPage, bool hasMoreHistory, StepsStats stats, TimeRange timeRange, DateTime? customStart, DateTime? customEnd, DateTime? rangeStart, DateTime? rangeEnd, bool isLoading, bool isLoadingMore) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ActivityMeterViewState():
|
||||
return $default(_that.todayTotal,_that.dailyGoal,_that.chartData,_that.hourlyData,_that.activeHoursToday,_that.historyData,_that.currentHistoryPage,_that.hasMoreHistory,_that.stats,_that.timeRange,_that.customStart,_that.customEnd,_that.rangeStart,_that.rangeEnd,_that.isLoading,_that.isLoadingMore,_that.errorEvent);case _:
|
||||
case _ActivityMeterState():
|
||||
return $default(_that.todayTotal,_that.dailyGoal,_that.chartData,_that.hourlyData,_that.activeHoursToday,_that.historyData,_that.currentHistoryPage,_that.hasMoreHistory,_that.stats,_that.timeRange,_that.customStart,_that.customEnd,_that.rangeStart,_that.rangeEnd,_that.isLoading,_that.isLoadingMore);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -1029,10 +1028,10 @@ return $default(_that.todayTotal,_that.dailyGoal,_that.chartData,_that.hourlyDat
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int todayTotal, int dailyGoal, List<DailySteps> chartData, List<HourlySteps> hourlyData, int activeHoursToday, List<DailySteps> historyData, int currentHistoryPage, bool hasMoreHistory, StepsStats stats, TimeRange timeRange, DateTime? customStart, DateTime? customEnd, DateTime? rangeStart, DateTime? rangeEnd, bool isLoading, bool isLoadingMore, ActivityMeterErrorEvent? errorEvent)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int todayTotal, int dailyGoal, List<DailySteps> chartData, List<HourlySteps> hourlyData, int activeHoursToday, List<DailySteps> historyData, int currentHistoryPage, bool hasMoreHistory, StepsStats stats, TimeRange timeRange, DateTime? customStart, DateTime? customEnd, DateTime? rangeStart, DateTime? rangeEnd, bool isLoading, bool isLoadingMore)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ActivityMeterViewState() when $default != null:
|
||||
return $default(_that.todayTotal,_that.dailyGoal,_that.chartData,_that.hourlyData,_that.activeHoursToday,_that.historyData,_that.currentHistoryPage,_that.hasMoreHistory,_that.stats,_that.timeRange,_that.customStart,_that.customEnd,_that.rangeStart,_that.rangeEnd,_that.isLoading,_that.isLoadingMore,_that.errorEvent);case _:
|
||||
case _ActivityMeterState() when $default != null:
|
||||
return $default(_that.todayTotal,_that.dailyGoal,_that.chartData,_that.hourlyData,_that.activeHoursToday,_that.historyData,_that.currentHistoryPage,_that.hasMoreHistory,_that.stats,_that.timeRange,_that.customStart,_that.customEnd,_that.rangeStart,_that.rangeEnd,_that.isLoading,_that.isLoadingMore);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -1043,8 +1042,8 @@ return $default(_that.todayTotal,_that.dailyGoal,_that.chartData,_that.hourlyDat
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _ActivityMeterViewState implements ActivityMeterViewState {
|
||||
const _ActivityMeterViewState({this.todayTotal = 0, this.dailyGoal = 8000, final List<DailySteps> chartData = const [], final List<HourlySteps> hourlyData = const [], this.activeHoursToday = 0, final List<DailySteps> historyData = const [], this.currentHistoryPage = 1, this.hasMoreHistory = false, this.stats = const StepsStats(), this.timeRange = TimeRange.today, this.customStart, this.customEnd, this.rangeStart, this.rangeEnd, this.isLoading = true, this.isLoadingMore = false, this.errorEvent}): _chartData = chartData,_hourlyData = hourlyData,_historyData = historyData;
|
||||
class _ActivityMeterState implements ActivityMeterState {
|
||||
const _ActivityMeterState({this.todayTotal = 0, this.dailyGoal = 8000, final List<DailySteps> chartData = const [], final List<HourlySteps> hourlyData = const [], this.activeHoursToday = 0, final List<DailySteps> historyData = const [], this.currentHistoryPage = 1, this.hasMoreHistory = false, this.stats = const StepsStats(), this.timeRange = TimeRange.today, this.customStart, this.customEnd, this.rangeStart, this.rangeEnd, this.isLoading = true, this.isLoadingMore = false}): _chartData = chartData,_hourlyData = hourlyData,_historyData = historyData;
|
||||
|
||||
|
||||
@override@JsonKey() final int todayTotal;
|
||||
@@ -1081,39 +1080,38 @@ class _ActivityMeterViewState implements ActivityMeterViewState {
|
||||
@override final DateTime? rangeEnd;
|
||||
@override@JsonKey() final bool isLoading;
|
||||
@override@JsonKey() final bool isLoadingMore;
|
||||
@override final ActivityMeterErrorEvent? errorEvent;
|
||||
|
||||
/// Create a copy of ActivityMeterViewState
|
||||
/// Create a copy of ActivityMeterState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ActivityMeterViewStateCopyWith<_ActivityMeterViewState> get copyWith => __$ActivityMeterViewStateCopyWithImpl<_ActivityMeterViewState>(this, _$identity);
|
||||
_$ActivityMeterStateCopyWith<_ActivityMeterState> get copyWith => __$ActivityMeterStateCopyWithImpl<_ActivityMeterState>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ActivityMeterViewState&&(identical(other.todayTotal, todayTotal) || other.todayTotal == todayTotal)&&(identical(other.dailyGoal, dailyGoal) || other.dailyGoal == dailyGoal)&&const DeepCollectionEquality().equals(other._chartData, _chartData)&&const DeepCollectionEquality().equals(other._hourlyData, _hourlyData)&&(identical(other.activeHoursToday, activeHoursToday) || other.activeHoursToday == activeHoursToday)&&const DeepCollectionEquality().equals(other._historyData, _historyData)&&(identical(other.currentHistoryPage, currentHistoryPage) || other.currentHistoryPage == currentHistoryPage)&&(identical(other.hasMoreHistory, hasMoreHistory) || other.hasMoreHistory == hasMoreHistory)&&(identical(other.stats, stats) || other.stats == stats)&&(identical(other.timeRange, timeRange) || other.timeRange == timeRange)&&(identical(other.customStart, customStart) || other.customStart == customStart)&&(identical(other.customEnd, customEnd) || other.customEnd == customEnd)&&(identical(other.rangeStart, rangeStart) || other.rangeStart == rangeStart)&&(identical(other.rangeEnd, rangeEnd) || other.rangeEnd == rangeEnd)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isLoadingMore, isLoadingMore) || other.isLoadingMore == isLoadingMore)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ActivityMeterState&&(identical(other.todayTotal, todayTotal) || other.todayTotal == todayTotal)&&(identical(other.dailyGoal, dailyGoal) || other.dailyGoal == dailyGoal)&&const DeepCollectionEquality().equals(other._chartData, _chartData)&&const DeepCollectionEquality().equals(other._hourlyData, _hourlyData)&&(identical(other.activeHoursToday, activeHoursToday) || other.activeHoursToday == activeHoursToday)&&const DeepCollectionEquality().equals(other._historyData, _historyData)&&(identical(other.currentHistoryPage, currentHistoryPage) || other.currentHistoryPage == currentHistoryPage)&&(identical(other.hasMoreHistory, hasMoreHistory) || other.hasMoreHistory == hasMoreHistory)&&(identical(other.stats, stats) || other.stats == stats)&&(identical(other.timeRange, timeRange) || other.timeRange == timeRange)&&(identical(other.customStart, customStart) || other.customStart == customStart)&&(identical(other.customEnd, customEnd) || other.customEnd == customEnd)&&(identical(other.rangeStart, rangeStart) || other.rangeStart == rangeStart)&&(identical(other.rangeEnd, rangeEnd) || other.rangeEnd == rangeEnd)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isLoadingMore, isLoadingMore) || other.isLoadingMore == isLoadingMore));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,todayTotal,dailyGoal,const DeepCollectionEquality().hash(_chartData),const DeepCollectionEquality().hash(_hourlyData),activeHoursToday,const DeepCollectionEquality().hash(_historyData),currentHistoryPage,hasMoreHistory,stats,timeRange,customStart,customEnd,rangeStart,rangeEnd,isLoading,isLoadingMore,errorEvent);
|
||||
int get hashCode => Object.hash(runtimeType,todayTotal,dailyGoal,const DeepCollectionEquality().hash(_chartData),const DeepCollectionEquality().hash(_hourlyData),activeHoursToday,const DeepCollectionEquality().hash(_historyData),currentHistoryPage,hasMoreHistory,stats,timeRange,customStart,customEnd,rangeStart,rangeEnd,isLoading,isLoadingMore);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ActivityMeterViewState(todayTotal: $todayTotal, dailyGoal: $dailyGoal, chartData: $chartData, hourlyData: $hourlyData, activeHoursToday: $activeHoursToday, historyData: $historyData, currentHistoryPage: $currentHistoryPage, hasMoreHistory: $hasMoreHistory, stats: $stats, timeRange: $timeRange, customStart: $customStart, customEnd: $customEnd, rangeStart: $rangeStart, rangeEnd: $rangeEnd, isLoading: $isLoading, isLoadingMore: $isLoadingMore, errorEvent: $errorEvent)';
|
||||
return 'ActivityMeterState(todayTotal: $todayTotal, dailyGoal: $dailyGoal, chartData: $chartData, hourlyData: $hourlyData, activeHoursToday: $activeHoursToday, historyData: $historyData, currentHistoryPage: $currentHistoryPage, hasMoreHistory: $hasMoreHistory, stats: $stats, timeRange: $timeRange, customStart: $customStart, customEnd: $customEnd, rangeStart: $rangeStart, rangeEnd: $rangeEnd, isLoading: $isLoading, isLoadingMore: $isLoadingMore)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ActivityMeterViewStateCopyWith<$Res> implements $ActivityMeterViewStateCopyWith<$Res> {
|
||||
factory _$ActivityMeterViewStateCopyWith(_ActivityMeterViewState value, $Res Function(_ActivityMeterViewState) _then) = __$ActivityMeterViewStateCopyWithImpl;
|
||||
abstract mixin class _$ActivityMeterStateCopyWith<$Res> implements $ActivityMeterStateCopyWith<$Res> {
|
||||
factory _$ActivityMeterStateCopyWith(_ActivityMeterState value, $Res Function(_ActivityMeterState) _then) = __$ActivityMeterStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
int todayTotal, int dailyGoal, List<DailySteps> chartData, List<HourlySteps> hourlyData, int activeHoursToday, List<DailySteps> historyData, int currentHistoryPage, bool hasMoreHistory, StepsStats stats, TimeRange timeRange, DateTime? customStart, DateTime? customEnd, DateTime? rangeStart, DateTime? rangeEnd, bool isLoading, bool isLoadingMore, ActivityMeterErrorEvent? errorEvent
|
||||
int todayTotal, int dailyGoal, List<DailySteps> chartData, List<HourlySteps> hourlyData, int activeHoursToday, List<DailySteps> historyData, int currentHistoryPage, bool hasMoreHistory, StepsStats stats, TimeRange timeRange, DateTime? customStart, DateTime? customEnd, DateTime? rangeStart, DateTime? rangeEnd, bool isLoading, bool isLoadingMore
|
||||
});
|
||||
|
||||
|
||||
@@ -1121,17 +1119,17 @@ $Res call({
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$ActivityMeterViewStateCopyWithImpl<$Res>
|
||||
implements _$ActivityMeterViewStateCopyWith<$Res> {
|
||||
__$ActivityMeterViewStateCopyWithImpl(this._self, this._then);
|
||||
class __$ActivityMeterStateCopyWithImpl<$Res>
|
||||
implements _$ActivityMeterStateCopyWith<$Res> {
|
||||
__$ActivityMeterStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _ActivityMeterViewState _self;
|
||||
final $Res Function(_ActivityMeterViewState) _then;
|
||||
final _ActivityMeterState _self;
|
||||
final $Res Function(_ActivityMeterState) _then;
|
||||
|
||||
/// Create a copy of ActivityMeterViewState
|
||||
/// Create a copy of ActivityMeterState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? todayTotal = null,Object? dailyGoal = null,Object? chartData = null,Object? hourlyData = null,Object? activeHoursToday = null,Object? historyData = null,Object? currentHistoryPage = null,Object? hasMoreHistory = null,Object? stats = null,Object? timeRange = null,Object? customStart = freezed,Object? customEnd = freezed,Object? rangeStart = freezed,Object? rangeEnd = freezed,Object? isLoading = null,Object? isLoadingMore = null,Object? errorEvent = freezed,}) {
|
||||
return _then(_ActivityMeterViewState(
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? todayTotal = null,Object? dailyGoal = null,Object? chartData = null,Object? hourlyData = null,Object? activeHoursToday = null,Object? historyData = null,Object? currentHistoryPage = null,Object? hasMoreHistory = null,Object? stats = null,Object? timeRange = null,Object? customStart = freezed,Object? customEnd = freezed,Object? rangeStart = freezed,Object? rangeEnd = freezed,Object? isLoading = null,Object? isLoadingMore = null,}) {
|
||||
return _then(_ActivityMeterState(
|
||||
todayTotal: null == todayTotal ? _self.todayTotal : todayTotal // ignore: cast_nullable_to_non_nullable
|
||||
as int,dailyGoal: null == dailyGoal ? _self.dailyGoal : dailyGoal // ignore: cast_nullable_to_non_nullable
|
||||
as int,chartData: null == chartData ? _self._chartData : chartData // ignore: cast_nullable_to_non_nullable
|
||||
@@ -1148,12 +1146,11 @@ as DateTime?,rangeStart: freezed == rangeStart ? _self.rangeStart : rangeStart /
|
||||
as DateTime?,rangeEnd: freezed == rangeEnd ? _self.rangeEnd : rangeEnd // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isLoadingMore: null == isLoadingMore ? _self.isLoadingMore : isLoadingMore // ignore: cast_nullable_to_non_nullable
|
||||
as bool,errorEvent: freezed == errorEvent ? _self.errorEvent : errorEvent // ignore: cast_nullable_to_non_nullable
|
||||
as ActivityMeterErrorEvent?,
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of ActivityMeterViewState
|
||||
/// Create a copy of ActivityMeterState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:legacy_device_state/legacy_device_state.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:sf_shared/sf_shared.dart';
|
||||
import 'package:sf_tracking/sf_tracking.dart';
|
||||
|
||||
part 'pedometer_controller.g.dart';
|
||||
|
||||
@riverpod
|
||||
class PedometerController extends _$PedometerController {
|
||||
bool _lastValue = false;
|
||||
|
||||
bool get lastValue => _lastValue;
|
||||
|
||||
@override
|
||||
FutureOr<void> build() {}
|
||||
|
||||
Future<void> toggle({
|
||||
required DeviceEntity device,
|
||||
required bool enabled,
|
||||
}) async {
|
||||
_lastValue = enabled;
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
final updated = device.settings.copyWith(pedometer: enabled);
|
||||
await ref
|
||||
.read(deviceSettingsUpdateProvider)
|
||||
.updateDeviceSettings(device: device, updatedSettings: updated);
|
||||
ref.syncDeviceSettings(device, updated);
|
||||
unawaited(
|
||||
ref.read(sfTrackingProvider).legacyDeviceActivityPedometerToggled(
|
||||
enabled,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'pedometer_controller.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(PedometerController)
|
||||
const pedometerControllerProvider = PedometerControllerProvider._();
|
||||
|
||||
final class PedometerControllerProvider
|
||||
extends $AsyncNotifierProvider<PedometerController, void> {
|
||||
const PedometerControllerProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'pedometerControllerProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$pedometerControllerHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
PedometerController create() => PedometerController();
|
||||
}
|
||||
|
||||
String _$pedometerControllerHash() =>
|
||||
r'd6df6753b2713d7feee4164ba8b2d0f595c67290';
|
||||
|
||||
abstract class _$PedometerController extends $AsyncNotifier<void> {
|
||||
FutureOr<void> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
build();
|
||||
final ref = this.ref as $Ref<AsyncValue<void>, void>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<void>, void>,
|
||||
AsyncValue<void>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, null);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import 'package:utils/utils.dart';
|
||||
|
||||
import '../../../../core/presentation/format_date.dart';
|
||||
import '../format_steps.dart';
|
||||
import '../state/activity_meter_view_state.dart';
|
||||
import '../providers/activity_meter_state.dart';
|
||||
import 'period_stats_cards.dart';
|
||||
|
||||
class TodayActivityFooter extends ConsumerWidget {
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
import '../state/activity_meter_view_state.dart';
|
||||
import '../providers/activity_meter_state.dart';
|
||||
import 'activity_bar_chart_base.dart';
|
||||
|
||||
class HourlyBarChart extends ConsumerWidget {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:legacy_theme/legacy_theme.dart';
|
||||
import 'package:device_management/src/features/activity_meter/presentation/providers/pedometer_controller.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:legacy_device_state/legacy_device_state.dart';
|
||||
import 'package:sf_shared/sf_shared.dart';
|
||||
import 'package:legacy_theme/legacy_theme.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
import 'package:sf_shared/sf_shared.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
import '../state/activity_meter_view_model.dart';
|
||||
|
||||
class PedometerToggle extends ConsumerWidget {
|
||||
const PedometerToggle({super.key});
|
||||
|
||||
@@ -20,6 +18,22 @@ class PedometerToggle extends ConsumerWidget {
|
||||
),
|
||||
);
|
||||
|
||||
ref.listen(pedometerControllerProvider, (prev, next) async {
|
||||
if (prev == null || !prev.isLoading || next.isLoading) return;
|
||||
if (next.hasError) {
|
||||
await showErrorDialog(context, I18n.errorPedometer);
|
||||
return;
|
||||
}
|
||||
final lastValue =
|
||||
ref.read(pedometerControllerProvider.notifier).lastValue;
|
||||
await showSuccessDialog(
|
||||
context,
|
||||
lastValue
|
||||
? I18n.activityMeterPedometerEnabled
|
||||
: I18n.activityMeterPedometerDisabled,
|
||||
);
|
||||
});
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: SizeUtils.getByScreen(small: 16, big: 14),
|
||||
@@ -40,21 +54,11 @@ class PedometerToggle extends ConsumerWidget {
|
||||
activeTrackColor: context.sfColors.legacyPrimary,
|
||||
onChanged: (value) async {
|
||||
if (!await guardDeviceCommand(context, ref)) return;
|
||||
final success = await ref
|
||||
.read(activityMeterViewModelProvider.notifier)
|
||||
.togglePedometer(enabled: value);
|
||||
if (!context.mounted) return;
|
||||
if (success) {
|
||||
showTopSnackbar(
|
||||
context,
|
||||
message: context.translate(
|
||||
value
|
||||
? I18n.activityMeterPedometerEnabled
|
||||
: I18n.activityMeterPedometerDisabled,
|
||||
),
|
||||
type: MessageType.success,
|
||||
);
|
||||
}
|
||||
final device = ref.read(selectedDeviceProvider).value;
|
||||
if (device == null) return;
|
||||
ref
|
||||
.read(pedometerControllerProvider.notifier)
|
||||
.toggle(device: device, enabled: value);
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:sf_localizations/sf_localizations.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
import '../format_steps.dart';
|
||||
import '../state/activity_meter_view_state.dart';
|
||||
import '../providers/activity_meter_state.dart';
|
||||
|
||||
class PeriodStatsCards extends StatelessWidget {
|
||||
final StepsStats stats;
|
||||
|
||||
@@ -5,7 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
import '../state/activity_meter_view_state.dart';
|
||||
import '../providers/activity_meter_state.dart';
|
||||
import 'activity_bar_chart_base.dart';
|
||||
|
||||
class StepsBarChart extends ConsumerWidget {
|
||||
|
||||
@@ -5,7 +5,7 @@ import 'package:utils/utils.dart';
|
||||
|
||||
import '../../../../core/presentation/format_date.dart';
|
||||
import '../format_steps.dart';
|
||||
import '../state/activity_meter_view_state.dart';
|
||||
import '../providers/activity_meter_state.dart';
|
||||
|
||||
class StepsHistorySection extends StatelessWidget {
|
||||
final List<DailySteps> items;
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'package:device_management/src/features/activity_meter/presentation/providers/pedometer_controller.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:legacy_device_state/legacy_device_state.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:sf_infrastructure/sf_infrastructure.dart';
|
||||
import 'package:sf_shared/sf_shared.dart';
|
||||
import 'package:sf_shared/testing.dart';
|
||||
import 'package:sf_tracking/sf_tracking.dart';
|
||||
|
||||
class MockDeviceSettingsUpdateDatasource extends Mock
|
||||
implements DeviceSettingsUpdateDatasource {}
|
||||
|
||||
const _device = DeviceEntity(
|
||||
id: 'device-1',
|
||||
identificator: 'imei-1',
|
||||
carrierName: 'Watch',
|
||||
settings: DeviceSettingsEntity(pedometer: false),
|
||||
);
|
||||
|
||||
void main() {
|
||||
setUpAll(() {
|
||||
registerFallbackValue(_device);
|
||||
registerFallbackValue(const DeviceSettingsEntity());
|
||||
});
|
||||
|
||||
ProviderContainer buildContainer(DeviceSettingsUpdateDatasource ds) {
|
||||
return makeContainer(
|
||||
overrides: [
|
||||
deviceSettingsUpdateProvider.overrideWithValue(ds),
|
||||
sfTrackingProvider.overrideWithValue(
|
||||
SfTrackingRepository(clients: const []),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
group('PedometerController.toggle', () {
|
||||
test('persists pedometer=true and transitions to AsyncData', () async {
|
||||
final ds = MockDeviceSettingsUpdateDatasource();
|
||||
when(
|
||||
() => ds.updateDeviceSettings(
|
||||
device: any(named: 'device'),
|
||||
updatedSettings: any(named: 'updatedSettings'),
|
||||
),
|
||||
).thenAnswer((_) async {});
|
||||
|
||||
final container = buildContainer(ds);
|
||||
addTearDown(container.dispose);
|
||||
|
||||
await container
|
||||
.read(pedometerControllerProvider.notifier)
|
||||
.toggle(device: _device, enabled: true);
|
||||
|
||||
expect(
|
||||
container.read(pedometerControllerProvider),
|
||||
isA<AsyncData<void>>(),
|
||||
);
|
||||
final captured = verify(
|
||||
() => ds.updateDeviceSettings(
|
||||
device: _device,
|
||||
updatedSettings: captureAny(named: 'updatedSettings'),
|
||||
),
|
||||
).captured.single as DeviceSettingsEntity;
|
||||
expect(captured.pedometer, isTrue);
|
||||
});
|
||||
|
||||
test('exposes AsyncError when datasource fails', () async {
|
||||
final ds = MockDeviceSettingsUpdateDatasource();
|
||||
when(
|
||||
() => ds.updateDeviceSettings(
|
||||
device: any(named: 'device'),
|
||||
updatedSettings: any(named: 'updatedSettings'),
|
||||
),
|
||||
).thenThrow(const ApiException(message: 'boom', isNetworkError: true));
|
||||
|
||||
final container = buildContainer(ds);
|
||||
addTearDown(container.dispose);
|
||||
|
||||
await container
|
||||
.read(pedometerControllerProvider.notifier)
|
||||
.toggle(device: _device, enabled: true);
|
||||
|
||||
expect(
|
||||
container.read(pedometerControllerProvider),
|
||||
isA<AsyncError<void>>(),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user