Compare commits

...

5 Commits

51 changed files with 1092 additions and 1351 deletions

View File

@@ -1,4 +1,2 @@
export 'src/features/notifications/notifications_builder.dart'
show DeviceNotificationsBuilder;
export 'src/features/control_panel/control_panel_builder.dart';
export 'src/shared/widgets/device_map.dart';

View File

@@ -1,9 +0,0 @@
import '../../domain/entities/alert_entity.dart';
abstract class AlertsRemoteDatasource {
Future<(List<AlertEntity>, int totalPages)> getAlerts({
required int page,
int pageSize,
String? type,
});
}

View File

@@ -1,30 +0,0 @@
import 'package:dio/dio.dart';
import 'package:sf_infrastructure/sf_infrastructure.dart';
import '../../domain/entities/alert_entity.dart';
import '../../domain/repositories/alerts_repository.dart';
import '../datasource/alerts_remote_datasource.dart';
class AlertsRepositoryImpl implements AlertsRepository {
AlertsRepositoryImpl(this._datasource);
final AlertsRemoteDatasource _datasource;
@override
Future<(List<AlertEntity>, int totalPages)> getAlerts({
required int page,
int pageSize = 20,
String? type,
}) async {
try {
return await _datasource.getAlerts(
page: page,
pageSize: pageSize,
type: type,
);
} on DioException catch (error) {
if (error.response?.statusCode == 404) return (<AlertEntity>[], 1);
throw mapDioError(error, defaultMessage: 'Error getting alerts');
}
}
}

View File

@@ -1,9 +0,0 @@
import '../entities/alert_entity.dart';
abstract class AlertsRepository {
Future<(List<AlertEntity>, int totalPages)> getAlerts({
required int page,
int pageSize,
String? type,
});
}

View File

@@ -1,16 +0,0 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get_it/get_it.dart';
import 'package:sf_infrastructure/sf_infrastructure.dart';
import '../data/datasource/alerts_remote_datasource.dart';
import '../data/datasource/alerts_remote_datasource_impl.dart';
import '../data/repositories/alerts_repository_impl.dart';
import '../domain/repositories/alerts_repository.dart';
final alertsRemoteDatasourceProvider = Provider<AlertsRemoteDatasource>(
(_) => AlertsRemoteDatasourceImpl(GetIt.I<SaveFamilyRepository>()),
);
final alertsRepositoryProvider = Provider<AlertsRepository>(
(ref) => AlertsRepositoryImpl(ref.read(alertsRemoteDatasourceProvider)),
);

View File

@@ -1,7 +1,7 @@
import 'package:design_system/design_system.dart';
import 'package:legacy_theme/legacy_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_theme/legacy_theme.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:utils/utils.dart';
@@ -18,28 +18,38 @@ class EditPeriodSheet extends ConsumerStatefulWidget {
}
class _EditPeriodSheetState extends ConsumerState<EditPeriodSheet> {
late TimeOfDay _start;
late TimeOfDay _end;
late List<bool> _weekDays;
late final ValueNotifier<TimeOfDay> _start;
late final ValueNotifier<TimeOfDay> _end;
late final ValueNotifier<List<bool>> _weekDays;
@override
void initState() {
super.initState();
if (widget.initial != null) {
_start = _parseTime(widget.initial!.start);
_end = _parseTime(widget.initial!.end);
_weekDays = widget.initial!.week
.padRight(7, '0')
.split('')
.map((c) => c == '1')
.toList();
_start = ValueNotifier(_parseTime(widget.initial!.start));
_end = ValueNotifier(_parseTime(widget.initial!.end));
_weekDays = ValueNotifier(
widget.initial!.week
.padRight(7, '0')
.split('')
.map((c) => c == '1')
.toList(),
);
} else {
_start = const TimeOfDay(hour: 22, minute: 0);
_end = const TimeOfDay(hour: 7, minute: 0);
_weekDays = [true, true, true, true, true, true, true];
_start = ValueNotifier(const TimeOfDay(hour: 22, minute: 0));
_end = ValueNotifier(const TimeOfDay(hour: 7, minute: 0));
_weekDays = ValueNotifier([true, true, true, true, true, true, true]);
}
}
@override
void dispose() {
_start.dispose();
_end.dispose();
_weekDays.dispose();
super.dispose();
}
TimeOfDay _parseTime(String time) {
final parts = time.split(':');
return TimeOfDay(
@@ -54,13 +64,13 @@ class _EditPeriodSheetState extends ConsumerState<EditPeriodSheet> {
String _formatForDisplay(TimeOfDay t) =>
'${t.hour.toString().padLeft(2, '0')}:${t.minute.toString().padLeft(2, '0')}';
String _weekToString() => _weekDays.map((d) => d ? '1' : '0').join();
String _weekToString(List<bool> days) =>
days.map((d) => d ? '1' : '0').join();
@override
Widget build(BuildContext context) {
final primaryColor = context.sfColors.legacyPrimary;
final isEditing = widget.initial != null;
final hasSelectedDays = _weekDays.any((d) => d);
return Padding(
padding: EdgeInsets.only(
@@ -89,32 +99,38 @@ class _EditPeriodSheetState extends ConsumerState<EditPeriodSheet> {
Row(
children: [
Expanded(
child: _TimePickerTile(
label: context.translate(I18n.doNotDisturbStart),
value: _formatForDisplay(_start),
color: primaryColor,
onTap: () async {
final picked = await showTimePicker(
context: context,
initialTime: _start,
);
if (picked != null) setState(() => _start = picked);
},
child: ValueListenableBuilder<TimeOfDay>(
valueListenable: _start,
builder: (context, start, _) => _TimePickerTile(
label: context.translate(I18n.doNotDisturbStart),
value: _formatForDisplay(start),
color: primaryColor,
onTap: () async {
final picked = await showTimePicker(
context: context,
initialTime: start,
);
if (picked != null) _start.value = picked;
},
),
),
),
SizedBox(width: SizeUtils.getByScreen(small: 12, big: 10)),
Expanded(
child: _TimePickerTile(
label: context.translate(I18n.doNotDisturbEnd),
value: _formatForDisplay(_end),
color: primaryColor,
onTap: () async {
final picked = await showTimePicker(
context: context,
initialTime: _end,
);
if (picked != null) setState(() => _end = picked);
},
child: ValueListenableBuilder<TimeOfDay>(
valueListenable: _end,
builder: (context, end, _) => _TimePickerTile(
label: context.translate(I18n.doNotDisturbEnd),
value: _formatForDisplay(end),
color: primaryColor,
onTap: () async {
final picked = await showTimePicker(
context: context,
initialTime: end,
);
if (picked != null) _end.value = picked;
},
),
),
),
],
@@ -129,29 +145,41 @@ class _EditPeriodSheetState extends ConsumerState<EditPeriodSheet> {
),
),
SizedBox(height: SizeUtils.getByScreen(small: 10, big: 8)),
WeekDayRow(
week: _weekToString(),
activeColor: primaryColor,
readOnly: false,
onToggle: (index) =>
setState(() => _weekDays[index] = !_weekDays[index]),
ValueListenableBuilder<List<bool>>(
valueListenable: _weekDays,
builder: (context, days, _) => WeekDayRow(
week: _weekToString(days),
activeColor: primaryColor,
readOnly: false,
onToggle: (index) {
final updated = List<bool>.from(days);
updated[index] = !updated[index];
_weekDays.value = updated;
},
),
),
SizedBox(height: SizeUtils.getByScreen(small: 24, big: 20)),
PrimaryButton(
onPressed: hasSelectedDays
? () {
Navigator.pop(
context,
DoNotDisturbPeriod(
start: _formatForApi(_start),
end: _formatForApi(_end),
week: _weekToString(),
),
);
}
: null,
text: context.translate(I18n.doNotDisturbConfirm),
color: primaryColor,
ValueListenableBuilder<List<bool>>(
valueListenable: _weekDays,
builder: (context, days, _) {
final hasSelectedDays = days.any((d) => d);
return PrimaryButton(
onPressed: hasSelectedDays
? () {
Navigator.pop(
context,
DoNotDisturbPeriod(
start: _formatForApi(_start.value),
end: _formatForApi(_end.value),
week: _weekToString(days),
),
);
}
: null,
text: context.translate(I18n.doNotDisturbConfirm),
color: primaryColor,
);
},
),
SizedBox(height: SizeUtils.getByScreen(small: 12, big: 10)),
],

View File

@@ -44,20 +44,14 @@ class _ActivityFormSheetState extends ConsumerState<ActivityFormSheet> {
void initState() {
super.initState();
_nameController = TextEditingController(text: widget.activity?.name ?? '');
_nameController.addListener(_onNameChanged);
}
@override
void dispose() {
_nameController.removeListener(_onNameChanged);
_nameController.dispose();
super.dispose();
}
void _onNameChanged() {
if (mounted) setState(() {});
}
Future<void> _submit({
required ActivityFormState formState,
required List<ScheduledActivityEntity> currentActivities,
@@ -110,9 +104,6 @@ class _ActivityFormSheetState extends ConsumerState<ActivityFormSheet> {
: (ref.watch(scheduledActivitiesProvider(device.id)).value ??
const []);
final canSubmit = _nameController.text.trim().isNotEmpty &&
formState.isTimeValid;
final bottomInset = MediaQuery.of(context).viewInsets.bottom;
return Padding(
@@ -209,30 +200,39 @@ class _ActivityFormSheetState extends ConsumerState<ActivityFormSheet> {
SizedBox(height: SizeUtils.getByScreen(small: 24, big: 22)),
SizedBox(
height: SizeUtils.getByScreen(small: 48, big: 46),
child: ElevatedButton(
onPressed: canSubmit
? () => _submit(
formState: formState,
currentActivities: currentActivities,
)
: null,
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
disabledBackgroundColor: Colors.grey[300],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
SizeUtils.getByScreen(small: 12, big: 10),
child: AnimatedBuilder(
animation: _nameController,
builder: (context, _) {
final canSubmit =
_nameController.text.trim().isNotEmpty &&
formState.isTimeValid;
return ElevatedButton(
onPressed: canSubmit
? () => _submit(
formState: formState,
currentActivities: currentActivities,
)
: null,
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
disabledBackgroundColor: Colors.grey[300],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
SizeUtils.getByScreen(small: 12, big: 10),
),
),
),
),
),
child: Text(
context.translate(I18n.save),
style: TextStyle(
color: canSubmit ? Colors.white : Colors.grey,
fontSize: SizeUtils.getByScreen(small: 16, big: 15),
fontWeight: FontWeight.w600,
),
),
child: Text(
context.translate(I18n.save),
style: TextStyle(
color: canSubmit ? Colors.white : Colors.grey,
fontSize:
SizeUtils.getByScreen(small: 16, big: 15),
fontWeight: FontWeight.w600,
),
),
);
},
),
),
],

View File

@@ -85,7 +85,6 @@ class _LegacyOtpCodeFieldsState extends State<LegacyOtpCodeFields> {
_focusNodes[nextIndex].requestFocus();
_emit();
setState(() {});
}
void _onChanged(int index, String value) {
@@ -101,7 +100,6 @@ class _LegacyOtpCodeFieldsState extends State<LegacyOtpCodeFields> {
}
_emit();
setState(() {});
}
KeyEventResult _onKey(int index, KeyEvent event) {
@@ -114,7 +112,6 @@ class _LegacyOtpCodeFieldsState extends State<LegacyOtpCodeFields> {
_controllers[index - 1].text = '';
_focusNodes[index - 1].requestFocus();
_emit();
setState(() {});
return KeyEventResult.handled;
}
}

View File

@@ -14,9 +14,6 @@ dependencies:
flutter:
sdk: flutter
#modules dependencies go here
control_panel:
path: ../../modules/control_panel
#packages dependencies go here
legacy_theme:
path: ../../packages/legacy_theme

View File

@@ -1,12 +1,12 @@
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:legacy_ui/legacy_ui.dart';
import 'package:location/src/features/location/presentation/state/location_view_model.dart';
import 'package:location/src/features/location/presentation/state/location_view_state.dart';
import 'package:location/src/features/location/presentation/providers/location_controller.dart';
import 'package:location/src/features/location/presentation/providers/location_state.dart';
import 'package:location/src/features/location/presentation/widgets/location_map.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_shared/sf_shared.dart';
class LocationScreen extends ConsumerWidget {
const LocationScreen({super.key});
@@ -14,100 +14,35 @@ class LocationScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final asyncDeviceState = ref.watch(legacyDeviceViewModelProvider);
final asyncLocationState = ref.watch(locationViewModelProvider);
final asyncLocationState = ref.watch(locationControllerProvider);
ref.listen(
locationViewModelProvider.select((s) => s.value?.errorEvent),
(previous, next) {
if (next != null) {
final message = switch (next) {
LocationErrorEvent.geofenceCreate => context.translate(
I18n.errorGeofenceCreate,
),
LocationErrorEvent.geofenceUpdate => context.translate(
I18n.errorGeofenceUpdate,
),
LocationErrorEvent.geofenceDelete => context.translate(
I18n.errorGeofenceDelete,
),
LocationErrorEvent.frequentPlaceCreate => context.translate(
I18n.errorFrequentPlaceCreate,
),
LocationErrorEvent.frequentPlaceUpdate => context.translate(
I18n.errorFrequentPlaceUpdate,
),
LocationErrorEvent.frequentPlaceDelete => context.translate(
I18n.errorFrequentPlaceDelete,
),
LocationErrorEvent.positionHistory => context.translate(
I18n.errorPositionHistory,
),
LocationErrorEvent.locationFrequency => context.translate(
I18n.errorLocationFrequency,
),
};
showTopSnackbar(context, message: message, type: MessageType.error);
}
locationControllerProvider.select((s) => s.value?.displayErrorKey),
(previous, next) async {
if (next == null || next == previous) return;
await showErrorDialog(context, next);
ref.read(locationControllerProvider.notifier).clearErrorEvent();
},
);
ref.listen(
locationViewModelProvider.select((s) => s.value?.successMessage),
(previous, next) {
if (next != null) {
final message = switch (next) {
LocationSuccessEvent.geofenceCreated => context.translate(
I18n.geofenceCreated,
),
LocationSuccessEvent.geofenceUpdated => context.translate(
I18n.geofenceUpdated,
),
LocationSuccessEvent.geofenceDeleted => context.translate(
I18n.geofenceDeleted,
),
LocationSuccessEvent.frequentPlaceCreated => context.translate(
I18n.frequentPlaceCreated,
),
LocationSuccessEvent.frequentPlaceUpdated => context.translate(
I18n.frequentPlaceUpdated,
),
LocationSuccessEvent.frequentPlaceDeleted => context.translate(
I18n.frequentPlaceDeleted,
),
};
showTopSnackbar(
context,
message: message,
type: MessageType.success,
);
}
locationControllerProvider.select((s) => s.value?.displaySuccessKey),
(previous, next) async {
if (next == null || next == previous) return;
await showSuccessDialog(context, next);
ref.read(locationControllerProvider.notifier).clearSuccessEvent();
},
);
ref.listen(legacyDeviceViewModelProvider, (previous, next) {
ref.listen(locationControllerProvider, (previous, next) async {
if (next.hasError && previous != null && !previous.hasError) {
showTopSnackbar(
context,
message: context.translate(I18n.errorGeneric),
type: MessageType.error,
);
}
});
ref.listen(locationViewModelProvider, (previous, next) {
if (next.hasError && previous != null && !previous.hasError) {
showTopSnackbar(
context,
message: context.translate(I18n.errorGeneric),
type: MessageType.error,
);
await showErrorDialog(context, I18n.errorGeneric);
}
});
final deviceState = asyncDeviceState.value;
final locationState = asyncLocationState.value;
final isLoading = asyncDeviceState.isLoading &&
deviceState == null;
final isLoading = asyncDeviceState.isLoading && deviceState == null;
return LegacyPageLayout(
title: context.translate(I18n.mapTitle),
@@ -118,7 +53,7 @@ class LocationScreen extends ConsumerWidget {
? RefreshableErrorState(
onRefresh: () async {
ref.invalidate(legacyDeviceViewModelProvider);
ref.invalidate(locationViewModelProvider);
ref.invalidate(locationControllerProvider);
await ref.read(legacyDeviceViewModelProvider.future);
},
)
@@ -146,4 +81,3 @@ class LocationScreen extends ConsumerWidget {
);
}
}

View File

@@ -1,43 +1,36 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:location/src/core/data/models/create_frequent_place_request_dto.dart';
import 'package:location/src/core/data/models/create_geofence_request_dto.dart';
import 'package:location/src/core/data/models/frequent_places_response_dto.dart';
import 'package:location/src/core/data/models/update_frequent_place_request_dto.dart';
import 'package:location/src/core/data/models/update_geofence_request_dto.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:location/src/core/domain/entities/frequent_place_entity.dart';
import 'package:location/src/core/domain/repositories/location_repository.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:location/src/core/providers/location_repository_provider.dart';
import 'package:location/src/features/location/presentation/state/location_view_state.dart';
import 'package:location/src/features/location/presentation/providers/location_state.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import 'package:uuid/uuid.dart';
final locationViewModelProvider = AsyncNotifierProvider.autoDispose<
LocationViewModel,
LocationViewState>(LocationViewModel.new);
class LocationViewModel extends AsyncNotifier<LocationViewState> {
late LocationRepository _locationRepository;
late SfTrackingRepository _tracking;
part 'location_controller.g.dart';
@Riverpod(keepAlive: true)
class LocationController extends _$LocationController {
@override
Future<LocationViewState> build() async {
_locationRepository = ref.read(locationRepositoryProvider);
_tracking = ref.read(sfTrackingProvider);
Future<LocationState> build() async {
final repo = ref.read(locationRepositoryProvider);
final device = ref.watch(selectedDeviceProvider).value;
if (device == null) return const LocationViewState();
if (device == null) return const LocationState();
final results = await Future.wait([
_locationRepository.getGeofences(deviceId: device.id),
_locationRepository.getFrequentPlaces(deviceId: device.id),
repo.getGeofences(deviceId: device.id),
repo.getFrequentPlaces(deviceId: device.id),
]);
return LocationViewState(
return LocationState(
geofences: results[0] as List<GeofenceEntity>,
frequentPlaces: results[1] as List<FrequentPlaceEntity>,
);
@@ -57,7 +50,7 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
current.copyWith(
isSubmitting: true,
errorEvent: null,
successMessage: null,
successEvent: null,
),
);
try {
@@ -75,18 +68,17 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
groupId: device?.groupId,
deviceId: device?.id,
);
final created = await _locationRepository.createGeofence(
request: request,
);
if (!ref.mounted) return false;
final created = await ref
.read(locationRepositoryProvider)
.createGeofence(request: request);
unawaited(_tracking.legacyLocationGeofenceCreated());
unawaited(ref.read(sfTrackingProvider).legacyLocationGeofenceCreated());
state = AsyncData(
current.copyWith(
geofences: [...current.geofences, created],
isSubmitting: false,
successMessage: LocationSuccessEvent.geofenceCreated,
successEvent: LocationSuccessEvent.geofenceCreated,
),
);
return true;
@@ -110,7 +102,7 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
current.copyWith(
isSubmitting: true,
errorEvent: null,
successMessage: null,
successEvent: null,
),
);
try {
@@ -122,12 +114,11 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
longitude: longitude,
radius: radius,
);
final updated = await _locationRepository.updateGeofence(
request: request,
);
if (!ref.mounted) return false;
final updated = await ref
.read(locationRepositoryProvider)
.updateGeofence(request: request);
unawaited(_tracking.legacyLocationGeofenceUpdated());
unawaited(ref.read(sfTrackingProvider).legacyLocationGeofenceUpdated());
state = AsyncData(
current.copyWith(
@@ -135,7 +126,7 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
.map((g) => g.id == id ? updated : g)
.toList(),
isSubmitting: false,
successMessage: LocationSuccessEvent.geofenceUpdated,
successEvent: LocationSuccessEvent.geofenceUpdated,
),
);
return true;
@@ -149,18 +140,17 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
if (current == null) return false;
state = AsyncData(
current.copyWith(errorEvent: null, successMessage: null),
current.copyWith(errorEvent: null, successEvent: null),
);
try {
await _locationRepository.deleteGeofence(geofenceId: id);
if (!ref.mounted) return false;
await ref.read(locationRepositoryProvider).deleteGeofence(geofenceId: id);
unawaited(_tracking.legacyLocationGeofenceDeleted());
unawaited(ref.read(sfTrackingProvider).legacyLocationGeofenceDeleted());
state = AsyncData(
current.copyWith(
geofences: current.geofences.where((g) => g.id != id).toList(),
successMessage: LocationSuccessEvent.geofenceDeleted,
successEvent: LocationSuccessEvent.geofenceDeleted,
),
);
return true;
@@ -182,7 +172,7 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
current.copyWith(
isSubmitting: true,
errorEvent: null,
successMessage: null,
successEvent: null,
),
);
try {
@@ -207,18 +197,19 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
groupId: device?.groupId,
deviceId: device?.id,
);
final created = await _locationRepository.createFrequentPlace(
request: request,
);
if (!ref.mounted) return false;
final created = await ref
.read(locationRepositoryProvider)
.createFrequentPlace(request: request);
unawaited(_tracking.legacyLocationFrequentPlaceCreated());
unawaited(
ref.read(sfTrackingProvider).legacyLocationFrequentPlaceCreated(),
);
state = AsyncData(
current.copyWith(
frequentPlaces: [...current.frequentPlaces, created],
isSubmitting: false,
successMessage: LocationSuccessEvent.frequentPlaceCreated,
successEvent: LocationSuccessEvent.frequentPlaceCreated,
),
);
return true;
@@ -241,7 +232,7 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
current.copyWith(
isSubmitting: true,
errorEvent: null,
successMessage: null,
successEvent: null,
),
);
try {
@@ -260,12 +251,13 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
)
.toList(),
);
final updated = await _locationRepository.updateFrequentPlace(
request: request,
);
if (!ref.mounted) return false;
final updated = await ref
.read(locationRepositoryProvider)
.updateFrequentPlace(request: request);
unawaited(_tracking.legacyLocationFrequentPlaceUpdated());
unawaited(
ref.read(sfTrackingProvider).legacyLocationFrequentPlaceUpdated(),
);
state = AsyncData(
current.copyWith(
@@ -273,7 +265,7 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
.map((f) => f.id == id ? updated : f)
.toList(),
isSubmitting: false,
successMessage: LocationSuccessEvent.frequentPlaceUpdated,
successEvent: LocationSuccessEvent.frequentPlaceUpdated,
),
);
return true;
@@ -287,19 +279,23 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
if (current == null) return false;
state = AsyncData(
current.copyWith(errorEvent: null, successMessage: null),
current.copyWith(errorEvent: null, successEvent: null),
);
try {
await _locationRepository.deleteFrequentPlace(frequentPlaceId: id);
if (!ref.mounted) return false;
await ref
.read(locationRepositoryProvider)
.deleteFrequentPlace(frequentPlaceId: id);
unawaited(_tracking.legacyLocationFrequentPlaceDeleted());
unawaited(
ref.read(sfTrackingProvider).legacyLocationFrequentPlaceDeleted(),
);
state = AsyncData(
current.copyWith(
frequentPlaces:
current.frequentPlaces.where((f) => f.id != id).toList(),
successMessage: LocationSuccessEvent.frequentPlaceDeleted,
frequentPlaces: current.frequentPlaces
.where((f) => f.id != id)
.toList(),
successEvent: LocationSuccessEvent.frequentPlaceDeleted,
),
);
return true;
@@ -321,14 +317,15 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
current.copyWith(isLoadingHistory: true, errorEvent: null),
);
try {
final positions = await _locationRepository.getPositionHistory(
deviceIdentificator: device.identificator,
from: from,
to: to,
);
if (!ref.mounted) return;
final positions = await ref
.read(locationRepositoryProvider)
.getPositionHistory(
deviceIdentificator: device.identificator,
from: from,
to: to,
);
unawaited(_tracking.legacyLocationHistoryLoaded());
unawaited(ref.read(sfTrackingProvider).legacyLocationHistoryLoaded());
state = AsyncData(
current.copyWith(
@@ -338,7 +335,6 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
),
);
} catch (e) {
if (!ref.mounted) return;
state = AsyncData(
current.copyWith(
isLoadingHistory: false,
@@ -353,7 +349,7 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
if (current == null) return;
if (current.positionHistory.isNotEmpty) {
unawaited(_tracking.legacyLocationHistoryCleared());
unawaited(ref.read(sfTrackingProvider).legacyLocationHistoryCleared());
}
state = AsyncData(
current.copyWith(positionHistory: [], showRouteTrail: false),
@@ -365,7 +361,11 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
if (current == null) return;
final newVisible = !current.showRouteTrail;
unawaited(_tracking.legacyLocationMapRouteTrailToggled(newVisible));
unawaited(
ref.read(sfTrackingProvider).legacyLocationMapRouteTrailToggled(
newVisible,
),
);
state = AsyncData(current.copyWith(showRouteTrail: newVisible));
}
@@ -388,10 +388,11 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
updatedSettings: updatedSettings,
);
if (!ref.mounted) return false;
ref.syncDeviceSettings(device, updatedSettings);
unawaited(_tracking.legacyLocationFrequencyUpdated(frequency));
unawaited(
ref.read(sfTrackingProvider).legacyLocationFrequencyUpdated(frequency),
);
state = AsyncData(current.copyWith(isSubmitting: false));
return true;
@@ -400,8 +401,19 @@ class LocationViewModel extends AsyncNotifier<LocationViewState> {
}
}
void clearErrorEvent() {
final current = state.value;
if (current == null) return;
state = AsyncData(current.copyWith(errorEvent: null));
}
void clearSuccessEvent() {
final current = state.value;
if (current == null) return;
state = AsyncData(current.copyWith(successEvent: null));
}
bool _handleErrorEvent(LocationErrorEvent event) {
if (!ref.mounted) return false;
final current = state.value;
if (current == null) return false;
state = AsyncData(

View File

@@ -0,0 +1,56 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'location_controller.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(LocationController)
const locationControllerProvider = LocationControllerProvider._();
final class LocationControllerProvider
extends $AsyncNotifierProvider<LocationController, LocationState> {
const LocationControllerProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'locationControllerProvider',
isAutoDispose: false,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$locationControllerHash();
@$internal
@override
LocationController create() => LocationController();
}
String _$locationControllerHash() =>
r'43534cd92b74ec5fabc9a43c6ef8398846855cf4';
abstract class _$LocationController extends $AsyncNotifier<LocationState> {
FutureOr<LocationState> build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<AsyncValue<LocationState>, LocationState>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<AsyncValue<LocationState>, LocationState>,
AsyncValue<LocationState>,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}

View File

@@ -0,0 +1,11 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'location_list_filter_controller.g.dart';
@riverpod
class LocationListFilter extends _$LocationListFilter {
@override
String? build() => null;
void select(String? type) => state = type;
}

View File

@@ -0,0 +1,64 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'location_list_filter_controller.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(LocationListFilter)
const locationListFilterProvider = LocationListFilterProvider._();
final class LocationListFilterProvider
extends $NotifierProvider<LocationListFilter, String?> {
const LocationListFilterProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'locationListFilterProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$locationListFilterHash();
@$internal
@override
LocationListFilter create() => LocationListFilter();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(String? value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<String?>(value),
);
}
}
String _$locationListFilterHash() =>
r'c55f4584aa74592c51b88d3a05cee95d8337466f';
abstract class _$LocationListFilter extends $Notifier<String?> {
String? build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<String?, String?>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<String?, String?>,
String?,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}

View File

@@ -1,29 +1,27 @@
import 'dart:async';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:latlong2/latlong.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:location/src/core/domain/entities/frequent_place_entity.dart';
import 'package:location/src/features/location/presentation/state/location_map_view_state.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:location/src/features/location/presentation/providers/location_map_state.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:sf_tracking/sf_tracking.dart';
final locationMapViewModelProvider =
NotifierProvider.autoDispose<LocationMapViewModel, LocationMapViewState>(
LocationMapViewModel.new,
);
part 'location_map_controller.g.dart';
class LocationMapViewModel extends Notifier<LocationMapViewState> {
@riverpod
class LocationMapController extends _$LocationMapController {
late final SfTrackingRepository _tracking;
Timer? _zoomDebounce;
static const Duration _zoomDebounceDelay = Duration(seconds: 1);
@override
LocationMapViewState build() {
LocationMapState build() {
_tracking = ref.read(sfTrackingProvider);
ref.onDispose(() => _zoomDebounce?.cancel());
return const LocationMapViewState();
return const LocationMapState();
}
void toggleGeofences() {

View File

@@ -0,0 +1,64 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'location_map_controller.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(LocationMapController)
const locationMapControllerProvider = LocationMapControllerProvider._();
final class LocationMapControllerProvider
extends $NotifierProvider<LocationMapController, LocationMapState> {
const LocationMapControllerProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'locationMapControllerProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$locationMapControllerHash();
@$internal
@override
LocationMapController create() => LocationMapController();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(LocationMapState value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<LocationMapState>(value),
);
}
}
String _$locationMapControllerHash() =>
r'c6eea4cec7a9a66546e9b66baf384edbb6e320f2';
abstract class _$LocationMapController extends $Notifier<LocationMapState> {
LocationMapState build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<LocationMapState, LocationMapState>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<LocationMapState, LocationMapState>,
LocationMapState,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}

View File

@@ -1,18 +1,18 @@
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:latlong2/latlong.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:location/src/core/domain/entities/frequent_place_entity.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
part 'location_map_view_state.freezed.dart';
part 'location_map_state.freezed.dart';
const _defaultZoom = 17.0;
enum PlacingMode { none, geofence, frequentPlace }
@freezed
abstract class LocationMapViewState with _$LocationMapViewState {
const factory LocationMapViewState({
abstract class LocationMapState with _$LocationMapState {
const factory LocationMapState({
@Default(true) bool showGeofences,
@Default(true) bool showFrequentPlaces,
@Default(PlacingMode.none) PlacingMode placingMode,
@@ -27,5 +27,5 @@ abstract class LocationMapViewState with _$LocationMapViewState {
@Default(false) bool actionsExpanded,
@Default(false) bool frequencyExpanded,
@Default(_defaultZoom) double mapZoom,
}) = _LocationMapViewState;
}) = _LocationMapState;
}

View File

@@ -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 'location_map_view_state.dart';
part of 'location_map_state.dart';
// **************************************************************************
// FreezedGenerator
@@ -12,20 +12,20 @@ part of 'location_map_view_state.dart';
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$LocationMapViewState {
mixin _$LocationMapState {
bool get showGeofences; bool get showFrequentPlaces; PlacingMode get placingMode; bool get adjustingRadius; double get previewRadius; LatLng? get previewPoint; GeofenceEntity? get selectedGeofence; GeofenceEntity? get editingGeofence; FrequentPlaceEntity? get selectedFrequentPlace; PositionEntity? get selectedHistoryPosition; bool get isFollowing; bool get actionsExpanded; bool get frequencyExpanded; double get mapZoom;
/// Create a copy of LocationMapViewState
/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$LocationMapViewStateCopyWith<LocationMapViewState> get copyWith => _$LocationMapViewStateCopyWithImpl<LocationMapViewState>(this as LocationMapViewState, _$identity);
$LocationMapStateCopyWith<LocationMapState> get copyWith => _$LocationMapStateCopyWithImpl<LocationMapState>(this as LocationMapState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is LocationMapViewState&&(identical(other.showGeofences, showGeofences) || other.showGeofences == showGeofences)&&(identical(other.showFrequentPlaces, showFrequentPlaces) || other.showFrequentPlaces == showFrequentPlaces)&&(identical(other.placingMode, placingMode) || other.placingMode == placingMode)&&(identical(other.adjustingRadius, adjustingRadius) || other.adjustingRadius == adjustingRadius)&&(identical(other.previewRadius, previewRadius) || other.previewRadius == previewRadius)&&(identical(other.previewPoint, previewPoint) || other.previewPoint == previewPoint)&&(identical(other.selectedGeofence, selectedGeofence) || other.selectedGeofence == selectedGeofence)&&(identical(other.editingGeofence, editingGeofence) || other.editingGeofence == editingGeofence)&&(identical(other.selectedFrequentPlace, selectedFrequentPlace) || other.selectedFrequentPlace == selectedFrequentPlace)&&(identical(other.selectedHistoryPosition, selectedHistoryPosition) || other.selectedHistoryPosition == selectedHistoryPosition)&&(identical(other.isFollowing, isFollowing) || other.isFollowing == isFollowing)&&(identical(other.actionsExpanded, actionsExpanded) || other.actionsExpanded == actionsExpanded)&&(identical(other.frequencyExpanded, frequencyExpanded) || other.frequencyExpanded == frequencyExpanded)&&(identical(other.mapZoom, mapZoom) || other.mapZoom == mapZoom));
return identical(this, other) || (other.runtimeType == runtimeType&&other is LocationMapState&&(identical(other.showGeofences, showGeofences) || other.showGeofences == showGeofences)&&(identical(other.showFrequentPlaces, showFrequentPlaces) || other.showFrequentPlaces == showFrequentPlaces)&&(identical(other.placingMode, placingMode) || other.placingMode == placingMode)&&(identical(other.adjustingRadius, adjustingRadius) || other.adjustingRadius == adjustingRadius)&&(identical(other.previewRadius, previewRadius) || other.previewRadius == previewRadius)&&(identical(other.previewPoint, previewPoint) || other.previewPoint == previewPoint)&&(identical(other.selectedGeofence, selectedGeofence) || other.selectedGeofence == selectedGeofence)&&(identical(other.editingGeofence, editingGeofence) || other.editingGeofence == editingGeofence)&&(identical(other.selectedFrequentPlace, selectedFrequentPlace) || other.selectedFrequentPlace == selectedFrequentPlace)&&(identical(other.selectedHistoryPosition, selectedHistoryPosition) || other.selectedHistoryPosition == selectedHistoryPosition)&&(identical(other.isFollowing, isFollowing) || other.isFollowing == isFollowing)&&(identical(other.actionsExpanded, actionsExpanded) || other.actionsExpanded == actionsExpanded)&&(identical(other.frequencyExpanded, frequencyExpanded) || other.frequencyExpanded == frequencyExpanded)&&(identical(other.mapZoom, mapZoom) || other.mapZoom == mapZoom));
}
@@ -34,15 +34,15 @@ int get hashCode => Object.hash(runtimeType,showGeofences,showFrequentPlaces,pla
@override
String toString() {
return 'LocationMapViewState(showGeofences: $showGeofences, showFrequentPlaces: $showFrequentPlaces, placingMode: $placingMode, adjustingRadius: $adjustingRadius, previewRadius: $previewRadius, previewPoint: $previewPoint, selectedGeofence: $selectedGeofence, editingGeofence: $editingGeofence, selectedFrequentPlace: $selectedFrequentPlace, selectedHistoryPosition: $selectedHistoryPosition, isFollowing: $isFollowing, actionsExpanded: $actionsExpanded, frequencyExpanded: $frequencyExpanded, mapZoom: $mapZoom)';
return 'LocationMapState(showGeofences: $showGeofences, showFrequentPlaces: $showFrequentPlaces, placingMode: $placingMode, adjustingRadius: $adjustingRadius, previewRadius: $previewRadius, previewPoint: $previewPoint, selectedGeofence: $selectedGeofence, editingGeofence: $editingGeofence, selectedFrequentPlace: $selectedFrequentPlace, selectedHistoryPosition: $selectedHistoryPosition, isFollowing: $isFollowing, actionsExpanded: $actionsExpanded, frequencyExpanded: $frequencyExpanded, mapZoom: $mapZoom)';
}
}
/// @nodoc
abstract mixin class $LocationMapViewStateCopyWith<$Res> {
factory $LocationMapViewStateCopyWith(LocationMapViewState value, $Res Function(LocationMapViewState) _then) = _$LocationMapViewStateCopyWithImpl;
abstract mixin class $LocationMapStateCopyWith<$Res> {
factory $LocationMapStateCopyWith(LocationMapState value, $Res Function(LocationMapState) _then) = _$LocationMapStateCopyWithImpl;
@useResult
$Res call({
bool showGeofences, bool showFrequentPlaces, PlacingMode placingMode, bool adjustingRadius, double previewRadius, LatLng? previewPoint, GeofenceEntity? selectedGeofence, GeofenceEntity? editingGeofence, FrequentPlaceEntity? selectedFrequentPlace, PositionEntity? selectedHistoryPosition, bool isFollowing, bool actionsExpanded, bool frequencyExpanded, double mapZoom
@@ -53,14 +53,14 @@ $GeofenceEntityCopyWith<$Res>? get selectedGeofence;$GeofenceEntityCopyWith<$Res
}
/// @nodoc
class _$LocationMapViewStateCopyWithImpl<$Res>
implements $LocationMapViewStateCopyWith<$Res> {
_$LocationMapViewStateCopyWithImpl(this._self, this._then);
class _$LocationMapStateCopyWithImpl<$Res>
implements $LocationMapStateCopyWith<$Res> {
_$LocationMapStateCopyWithImpl(this._self, this._then);
final LocationMapViewState _self;
final $Res Function(LocationMapViewState) _then;
final LocationMapState _self;
final $Res Function(LocationMapState) _then;
/// Create a copy of LocationMapViewState
/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? showGeofences = null,Object? showFrequentPlaces = null,Object? placingMode = null,Object? adjustingRadius = null,Object? previewRadius = null,Object? previewPoint = freezed,Object? selectedGeofence = freezed,Object? editingGeofence = freezed,Object? selectedFrequentPlace = freezed,Object? selectedHistoryPosition = freezed,Object? isFollowing = null,Object? actionsExpanded = null,Object? frequencyExpanded = null,Object? mapZoom = null,}) {
return _then(_self.copyWith(
@@ -81,7 +81,7 @@ as bool,mapZoom: null == mapZoom ? _self.mapZoom : mapZoom // ignore: cast_nulla
as double,
));
}
/// Create a copy of LocationMapViewState
/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
@@ -93,7 +93,7 @@ $GeofenceEntityCopyWith<$Res>? get selectedGeofence {
return $GeofenceEntityCopyWith<$Res>(_self.selectedGeofence!, (value) {
return _then(_self.copyWith(selectedGeofence: value));
});
}/// Create a copy of LocationMapViewState
}/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
@@ -105,7 +105,7 @@ $GeofenceEntityCopyWith<$Res>? get editingGeofence {
return $GeofenceEntityCopyWith<$Res>(_self.editingGeofence!, (value) {
return _then(_self.copyWith(editingGeofence: value));
});
}/// Create a copy of LocationMapViewState
}/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
@@ -117,7 +117,7 @@ $FrequentPlaceEntityCopyWith<$Res>? get selectedFrequentPlace {
return $FrequentPlaceEntityCopyWith<$Res>(_self.selectedFrequentPlace!, (value) {
return _then(_self.copyWith(selectedFrequentPlace: value));
});
}/// Create a copy of LocationMapViewState
}/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
@@ -133,8 +133,8 @@ $PositionEntityCopyWith<$Res>? get selectedHistoryPosition {
}
/// Adds pattern-matching-related methods to [LocationMapViewState].
extension LocationMapViewStatePatterns on LocationMapViewState {
/// Adds pattern-matching-related methods to [LocationMapState].
extension LocationMapStatePatterns on LocationMapState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
@@ -147,10 +147,10 @@ extension LocationMapViewStatePatterns on LocationMapViewState {
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _LocationMapViewState value)? $default,{required TResult orElse(),}){
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _LocationMapState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _LocationMapViewState() when $default != null:
case _LocationMapState() when $default != null:
return $default(_that);case _:
return orElse();
@@ -169,10 +169,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _LocationMapViewState value) $default,){
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _LocationMapState value) $default,){
final _that = this;
switch (_that) {
case _LocationMapViewState():
case _LocationMapState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
@@ -190,10 +190,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _LocationMapViewState value)? $default,){
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _LocationMapState value)? $default,){
final _that = this;
switch (_that) {
case _LocationMapViewState() when $default != null:
case _LocationMapState() when $default != null:
return $default(_that);case _:
return null;
@@ -213,7 +213,7 @@ return $default(_that);case _:
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool showGeofences, bool showFrequentPlaces, PlacingMode placingMode, bool adjustingRadius, double previewRadius, LatLng? previewPoint, GeofenceEntity? selectedGeofence, GeofenceEntity? editingGeofence, FrequentPlaceEntity? selectedFrequentPlace, PositionEntity? selectedHistoryPosition, bool isFollowing, bool actionsExpanded, bool frequencyExpanded, double mapZoom)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _LocationMapViewState() when $default != null:
case _LocationMapState() when $default != null:
return $default(_that.showGeofences,_that.showFrequentPlaces,_that.placingMode,_that.adjustingRadius,_that.previewRadius,_that.previewPoint,_that.selectedGeofence,_that.editingGeofence,_that.selectedFrequentPlace,_that.selectedHistoryPosition,_that.isFollowing,_that.actionsExpanded,_that.frequencyExpanded,_that.mapZoom);case _:
return orElse();
@@ -234,7 +234,7 @@ return $default(_that.showGeofences,_that.showFrequentPlaces,_that.placingMode,_
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool showGeofences, bool showFrequentPlaces, PlacingMode placingMode, bool adjustingRadius, double previewRadius, LatLng? previewPoint, GeofenceEntity? selectedGeofence, GeofenceEntity? editingGeofence, FrequentPlaceEntity? selectedFrequentPlace, PositionEntity? selectedHistoryPosition, bool isFollowing, bool actionsExpanded, bool frequencyExpanded, double mapZoom) $default,) {final _that = this;
switch (_that) {
case _LocationMapViewState():
case _LocationMapState():
return $default(_that.showGeofences,_that.showFrequentPlaces,_that.placingMode,_that.adjustingRadius,_that.previewRadius,_that.previewPoint,_that.selectedGeofence,_that.editingGeofence,_that.selectedFrequentPlace,_that.selectedHistoryPosition,_that.isFollowing,_that.actionsExpanded,_that.frequencyExpanded,_that.mapZoom);case _:
throw StateError('Unexpected subclass');
@@ -254,7 +254,7 @@ return $default(_that.showGeofences,_that.showFrequentPlaces,_that.placingMode,_
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool showGeofences, bool showFrequentPlaces, PlacingMode placingMode, bool adjustingRadius, double previewRadius, LatLng? previewPoint, GeofenceEntity? selectedGeofence, GeofenceEntity? editingGeofence, FrequentPlaceEntity? selectedFrequentPlace, PositionEntity? selectedHistoryPosition, bool isFollowing, bool actionsExpanded, bool frequencyExpanded, double mapZoom)? $default,) {final _that = this;
switch (_that) {
case _LocationMapViewState() when $default != null:
case _LocationMapState() when $default != null:
return $default(_that.showGeofences,_that.showFrequentPlaces,_that.placingMode,_that.adjustingRadius,_that.previewRadius,_that.previewPoint,_that.selectedGeofence,_that.editingGeofence,_that.selectedFrequentPlace,_that.selectedHistoryPosition,_that.isFollowing,_that.actionsExpanded,_that.frequencyExpanded,_that.mapZoom);case _:
return null;
@@ -266,8 +266,8 @@ return $default(_that.showGeofences,_that.showFrequentPlaces,_that.placingMode,_
/// @nodoc
class _LocationMapViewState implements LocationMapViewState {
const _LocationMapViewState({this.showGeofences = true, this.showFrequentPlaces = true, this.placingMode = PlacingMode.none, this.adjustingRadius = false, this.previewRadius = 200.0, this.previewPoint, this.selectedGeofence, this.editingGeofence, this.selectedFrequentPlace, this.selectedHistoryPosition, this.isFollowing = false, this.actionsExpanded = false, this.frequencyExpanded = false, this.mapZoom = _defaultZoom});
class _LocationMapState implements LocationMapState {
const _LocationMapState({this.showGeofences = true, this.showFrequentPlaces = true, this.placingMode = PlacingMode.none, this.adjustingRadius = false, this.previewRadius = 200.0, this.previewPoint, this.selectedGeofence, this.editingGeofence, this.selectedFrequentPlace, this.selectedHistoryPosition, this.isFollowing = false, this.actionsExpanded = false, this.frequencyExpanded = false, this.mapZoom = _defaultZoom});
@override@JsonKey() final bool showGeofences;
@@ -285,17 +285,17 @@ class _LocationMapViewState implements LocationMapViewState {
@override@JsonKey() final bool frequencyExpanded;
@override@JsonKey() final double mapZoom;
/// Create a copy of LocationMapViewState
/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$LocationMapViewStateCopyWith<_LocationMapViewState> get copyWith => __$LocationMapViewStateCopyWithImpl<_LocationMapViewState>(this, _$identity);
_$LocationMapStateCopyWith<_LocationMapState> get copyWith => __$LocationMapStateCopyWithImpl<_LocationMapState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LocationMapViewState&&(identical(other.showGeofences, showGeofences) || other.showGeofences == showGeofences)&&(identical(other.showFrequentPlaces, showFrequentPlaces) || other.showFrequentPlaces == showFrequentPlaces)&&(identical(other.placingMode, placingMode) || other.placingMode == placingMode)&&(identical(other.adjustingRadius, adjustingRadius) || other.adjustingRadius == adjustingRadius)&&(identical(other.previewRadius, previewRadius) || other.previewRadius == previewRadius)&&(identical(other.previewPoint, previewPoint) || other.previewPoint == previewPoint)&&(identical(other.selectedGeofence, selectedGeofence) || other.selectedGeofence == selectedGeofence)&&(identical(other.editingGeofence, editingGeofence) || other.editingGeofence == editingGeofence)&&(identical(other.selectedFrequentPlace, selectedFrequentPlace) || other.selectedFrequentPlace == selectedFrequentPlace)&&(identical(other.selectedHistoryPosition, selectedHistoryPosition) || other.selectedHistoryPosition == selectedHistoryPosition)&&(identical(other.isFollowing, isFollowing) || other.isFollowing == isFollowing)&&(identical(other.actionsExpanded, actionsExpanded) || other.actionsExpanded == actionsExpanded)&&(identical(other.frequencyExpanded, frequencyExpanded) || other.frequencyExpanded == frequencyExpanded)&&(identical(other.mapZoom, mapZoom) || other.mapZoom == mapZoom));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LocationMapState&&(identical(other.showGeofences, showGeofences) || other.showGeofences == showGeofences)&&(identical(other.showFrequentPlaces, showFrequentPlaces) || other.showFrequentPlaces == showFrequentPlaces)&&(identical(other.placingMode, placingMode) || other.placingMode == placingMode)&&(identical(other.adjustingRadius, adjustingRadius) || other.adjustingRadius == adjustingRadius)&&(identical(other.previewRadius, previewRadius) || other.previewRadius == previewRadius)&&(identical(other.previewPoint, previewPoint) || other.previewPoint == previewPoint)&&(identical(other.selectedGeofence, selectedGeofence) || other.selectedGeofence == selectedGeofence)&&(identical(other.editingGeofence, editingGeofence) || other.editingGeofence == editingGeofence)&&(identical(other.selectedFrequentPlace, selectedFrequentPlace) || other.selectedFrequentPlace == selectedFrequentPlace)&&(identical(other.selectedHistoryPosition, selectedHistoryPosition) || other.selectedHistoryPosition == selectedHistoryPosition)&&(identical(other.isFollowing, isFollowing) || other.isFollowing == isFollowing)&&(identical(other.actionsExpanded, actionsExpanded) || other.actionsExpanded == actionsExpanded)&&(identical(other.frequencyExpanded, frequencyExpanded) || other.frequencyExpanded == frequencyExpanded)&&(identical(other.mapZoom, mapZoom) || other.mapZoom == mapZoom));
}
@@ -304,15 +304,15 @@ int get hashCode => Object.hash(runtimeType,showGeofences,showFrequentPlaces,pla
@override
String toString() {
return 'LocationMapViewState(showGeofences: $showGeofences, showFrequentPlaces: $showFrequentPlaces, placingMode: $placingMode, adjustingRadius: $adjustingRadius, previewRadius: $previewRadius, previewPoint: $previewPoint, selectedGeofence: $selectedGeofence, editingGeofence: $editingGeofence, selectedFrequentPlace: $selectedFrequentPlace, selectedHistoryPosition: $selectedHistoryPosition, isFollowing: $isFollowing, actionsExpanded: $actionsExpanded, frequencyExpanded: $frequencyExpanded, mapZoom: $mapZoom)';
return 'LocationMapState(showGeofences: $showGeofences, showFrequentPlaces: $showFrequentPlaces, placingMode: $placingMode, adjustingRadius: $adjustingRadius, previewRadius: $previewRadius, previewPoint: $previewPoint, selectedGeofence: $selectedGeofence, editingGeofence: $editingGeofence, selectedFrequentPlace: $selectedFrequentPlace, selectedHistoryPosition: $selectedHistoryPosition, isFollowing: $isFollowing, actionsExpanded: $actionsExpanded, frequencyExpanded: $frequencyExpanded, mapZoom: $mapZoom)';
}
}
/// @nodoc
abstract mixin class _$LocationMapViewStateCopyWith<$Res> implements $LocationMapViewStateCopyWith<$Res> {
factory _$LocationMapViewStateCopyWith(_LocationMapViewState value, $Res Function(_LocationMapViewState) _then) = __$LocationMapViewStateCopyWithImpl;
abstract mixin class _$LocationMapStateCopyWith<$Res> implements $LocationMapStateCopyWith<$Res> {
factory _$LocationMapStateCopyWith(_LocationMapState value, $Res Function(_LocationMapState) _then) = __$LocationMapStateCopyWithImpl;
@override @useResult
$Res call({
bool showGeofences, bool showFrequentPlaces, PlacingMode placingMode, bool adjustingRadius, double previewRadius, LatLng? previewPoint, GeofenceEntity? selectedGeofence, GeofenceEntity? editingGeofence, FrequentPlaceEntity? selectedFrequentPlace, PositionEntity? selectedHistoryPosition, bool isFollowing, bool actionsExpanded, bool frequencyExpanded, double mapZoom
@@ -323,17 +323,17 @@ $Res call({
}
/// @nodoc
class __$LocationMapViewStateCopyWithImpl<$Res>
implements _$LocationMapViewStateCopyWith<$Res> {
__$LocationMapViewStateCopyWithImpl(this._self, this._then);
class __$LocationMapStateCopyWithImpl<$Res>
implements _$LocationMapStateCopyWith<$Res> {
__$LocationMapStateCopyWithImpl(this._self, this._then);
final _LocationMapViewState _self;
final $Res Function(_LocationMapViewState) _then;
final _LocationMapState _self;
final $Res Function(_LocationMapState) _then;
/// Create a copy of LocationMapViewState
/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? showGeofences = null,Object? showFrequentPlaces = null,Object? placingMode = null,Object? adjustingRadius = null,Object? previewRadius = null,Object? previewPoint = freezed,Object? selectedGeofence = freezed,Object? editingGeofence = freezed,Object? selectedFrequentPlace = freezed,Object? selectedHistoryPosition = freezed,Object? isFollowing = null,Object? actionsExpanded = null,Object? frequencyExpanded = null,Object? mapZoom = null,}) {
return _then(_LocationMapViewState(
return _then(_LocationMapState(
showGeofences: null == showGeofences ? _self.showGeofences : showGeofences // ignore: cast_nullable_to_non_nullable
as bool,showFrequentPlaces: null == showFrequentPlaces ? _self.showFrequentPlaces : showFrequentPlaces // ignore: cast_nullable_to_non_nullable
as bool,placingMode: null == placingMode ? _self.placingMode : placingMode // ignore: cast_nullable_to_non_nullable
@@ -352,7 +352,7 @@ as double,
));
}
/// Create a copy of LocationMapViewState
/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
@@ -364,7 +364,7 @@ $GeofenceEntityCopyWith<$Res>? get selectedGeofence {
return $GeofenceEntityCopyWith<$Res>(_self.selectedGeofence!, (value) {
return _then(_self.copyWith(selectedGeofence: value));
});
}/// Create a copy of LocationMapViewState
}/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
@@ -376,7 +376,7 @@ $GeofenceEntityCopyWith<$Res>? get editingGeofence {
return $GeofenceEntityCopyWith<$Res>(_self.editingGeofence!, (value) {
return _then(_self.copyWith(editingGeofence: value));
});
}/// Create a copy of LocationMapViewState
}/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
@@ -388,7 +388,7 @@ $FrequentPlaceEntityCopyWith<$Res>? get selectedFrequentPlace {
return $FrequentPlaceEntityCopyWith<$Res>(_self.selectedFrequentPlace!, (value) {
return _then(_self.copyWith(selectedFrequentPlace: value));
});
}/// Create a copy of LocationMapViewState
}/// Create a copy of LocationMapState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')

View File

@@ -0,0 +1,65 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:location/src/core/domain/entities/frequent_place_entity.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:sf_localizations/sf_localizations.dart';
part 'location_state.freezed.dart';
enum LocationSuccessEvent {
geofenceCreated,
geofenceUpdated,
geofenceDeleted,
frequentPlaceCreated,
frequentPlaceUpdated,
frequentPlaceDeleted,
}
enum LocationErrorEvent {
geofenceCreate,
geofenceUpdate,
geofenceDelete,
frequentPlaceCreate,
frequentPlaceUpdate,
frequentPlaceDelete,
positionHistory,
locationFrequency,
}
@freezed
abstract class LocationState with _$LocationState {
const factory LocationState({
@Default([]) List<GeofenceEntity> geofences,
@Default([]) List<FrequentPlaceEntity> frequentPlaces,
@Default([]) List<PositionEntity> positionHistory,
@Default(false) bool isLoadingHistory,
@Default(false) bool isSubmitting,
@Default(false) bool showRouteTrail,
LocationErrorEvent? errorEvent,
LocationSuccessEvent? successEvent,
}) = _LocationState;
}
extension LocationStateDisplay on LocationState {
String? get displayErrorKey => switch (errorEvent) {
null => null,
LocationErrorEvent.geofenceCreate => I18n.errorGeofenceCreate,
LocationErrorEvent.geofenceUpdate => I18n.errorGeofenceUpdate,
LocationErrorEvent.geofenceDelete => I18n.errorGeofenceDelete,
LocationErrorEvent.frequentPlaceCreate => I18n.errorFrequentPlaceCreate,
LocationErrorEvent.frequentPlaceUpdate => I18n.errorFrequentPlaceUpdate,
LocationErrorEvent.frequentPlaceDelete => I18n.errorFrequentPlaceDelete,
LocationErrorEvent.positionHistory => I18n.errorPositionHistory,
LocationErrorEvent.locationFrequency => I18n.errorLocationFrequency,
};
String? get displaySuccessKey => switch (successEvent) {
null => null,
LocationSuccessEvent.geofenceCreated => I18n.geofenceCreated,
LocationSuccessEvent.geofenceUpdated => I18n.geofenceUpdated,
LocationSuccessEvent.geofenceDeleted => I18n.geofenceDeleted,
LocationSuccessEvent.frequentPlaceCreated => I18n.frequentPlaceCreated,
LocationSuccessEvent.frequentPlaceUpdated => I18n.frequentPlaceUpdated,
LocationSuccessEvent.frequentPlaceDeleted => I18n.frequentPlaceDeleted,
};
}

View File

@@ -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 'location_view_state.dart';
part of 'location_state.dart';
// **************************************************************************
// FreezedGenerator
@@ -12,40 +12,40 @@ part of 'location_view_state.dart';
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$LocationViewState {
mixin _$LocationState {
List<GeofenceEntity> get geofences; List<FrequentPlaceEntity> get frequentPlaces; List<PositionEntity> get positionHistory; bool get isLoadingHistory; bool get isSubmitting; bool get showRouteTrail; LocationErrorEvent? get errorEvent; LocationSuccessEvent? get successMessage;
/// Create a copy of LocationViewState
List<GeofenceEntity> get geofences; List<FrequentPlaceEntity> get frequentPlaces; List<PositionEntity> get positionHistory; bool get isLoadingHistory; bool get isSubmitting; bool get showRouteTrail; LocationErrorEvent? get errorEvent; LocationSuccessEvent? get successEvent;
/// Create a copy of LocationState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$LocationViewStateCopyWith<LocationViewState> get copyWith => _$LocationViewStateCopyWithImpl<LocationViewState>(this as LocationViewState, _$identity);
$LocationStateCopyWith<LocationState> get copyWith => _$LocationStateCopyWithImpl<LocationState>(this as LocationState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is LocationViewState&&const DeepCollectionEquality().equals(other.geofences, geofences)&&const DeepCollectionEquality().equals(other.frequentPlaces, frequentPlaces)&&const DeepCollectionEquality().equals(other.positionHistory, positionHistory)&&(identical(other.isLoadingHistory, isLoadingHistory) || other.isLoadingHistory == isLoadingHistory)&&(identical(other.isSubmitting, isSubmitting) || other.isSubmitting == isSubmitting)&&(identical(other.showRouteTrail, showRouteTrail) || other.showRouteTrail == showRouteTrail)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successMessage, successMessage) || other.successMessage == successMessage));
return identical(this, other) || (other.runtimeType == runtimeType&&other is LocationState&&const DeepCollectionEquality().equals(other.geofences, geofences)&&const DeepCollectionEquality().equals(other.frequentPlaces, frequentPlaces)&&const DeepCollectionEquality().equals(other.positionHistory, positionHistory)&&(identical(other.isLoadingHistory, isLoadingHistory) || other.isLoadingHistory == isLoadingHistory)&&(identical(other.isSubmitting, isSubmitting) || other.isSubmitting == isSubmitting)&&(identical(other.showRouteTrail, showRouteTrail) || other.showRouteTrail == showRouteTrail)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successEvent, successEvent) || other.successEvent == successEvent));
}
@override
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(geofences),const DeepCollectionEquality().hash(frequentPlaces),const DeepCollectionEquality().hash(positionHistory),isLoadingHistory,isSubmitting,showRouteTrail,errorEvent,successMessage);
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(geofences),const DeepCollectionEquality().hash(frequentPlaces),const DeepCollectionEquality().hash(positionHistory),isLoadingHistory,isSubmitting,showRouteTrail,errorEvent,successEvent);
@override
String toString() {
return 'LocationViewState(geofences: $geofences, frequentPlaces: $frequentPlaces, positionHistory: $positionHistory, isLoadingHistory: $isLoadingHistory, isSubmitting: $isSubmitting, showRouteTrail: $showRouteTrail, errorEvent: $errorEvent, successMessage: $successMessage)';
return 'LocationState(geofences: $geofences, frequentPlaces: $frequentPlaces, positionHistory: $positionHistory, isLoadingHistory: $isLoadingHistory, isSubmitting: $isSubmitting, showRouteTrail: $showRouteTrail, errorEvent: $errorEvent, successEvent: $successEvent)';
}
}
/// @nodoc
abstract mixin class $LocationViewStateCopyWith<$Res> {
factory $LocationViewStateCopyWith(LocationViewState value, $Res Function(LocationViewState) _then) = _$LocationViewStateCopyWithImpl;
abstract mixin class $LocationStateCopyWith<$Res> {
factory $LocationStateCopyWith(LocationState value, $Res Function(LocationState) _then) = _$LocationStateCopyWithImpl;
@useResult
$Res call({
List<GeofenceEntity> geofences, List<FrequentPlaceEntity> frequentPlaces, List<PositionEntity> positionHistory, bool isLoadingHistory, bool isSubmitting, bool showRouteTrail, LocationErrorEvent? errorEvent, LocationSuccessEvent? successMessage
List<GeofenceEntity> geofences, List<FrequentPlaceEntity> frequentPlaces, List<PositionEntity> positionHistory, bool isLoadingHistory, bool isSubmitting, bool showRouteTrail, LocationErrorEvent? errorEvent, LocationSuccessEvent? successEvent
});
@@ -53,16 +53,16 @@ $Res call({
}
/// @nodoc
class _$LocationViewStateCopyWithImpl<$Res>
implements $LocationViewStateCopyWith<$Res> {
_$LocationViewStateCopyWithImpl(this._self, this._then);
class _$LocationStateCopyWithImpl<$Res>
implements $LocationStateCopyWith<$Res> {
_$LocationStateCopyWithImpl(this._self, this._then);
final LocationViewState _self;
final $Res Function(LocationViewState) _then;
final LocationState _self;
final $Res Function(LocationState) _then;
/// Create a copy of LocationViewState
/// Create a copy of LocationState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? geofences = null,Object? frequentPlaces = null,Object? positionHistory = null,Object? isLoadingHistory = null,Object? isSubmitting = null,Object? showRouteTrail = null,Object? errorEvent = freezed,Object? successMessage = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? geofences = null,Object? frequentPlaces = null,Object? positionHistory = null,Object? isLoadingHistory = null,Object? isSubmitting = null,Object? showRouteTrail = null,Object? errorEvent = freezed,Object? successEvent = freezed,}) {
return _then(_self.copyWith(
geofences: null == geofences ? _self.geofences : geofences // ignore: cast_nullable_to_non_nullable
as List<GeofenceEntity>,frequentPlaces: null == frequentPlaces ? _self.frequentPlaces : frequentPlaces // ignore: cast_nullable_to_non_nullable
@@ -71,7 +71,7 @@ as List<PositionEntity>,isLoadingHistory: null == isLoadingHistory ? _self.isLoa
as bool,isSubmitting: null == isSubmitting ? _self.isSubmitting : isSubmitting // ignore: cast_nullable_to_non_nullable
as bool,showRouteTrail: null == showRouteTrail ? _self.showRouteTrail : showRouteTrail // ignore: cast_nullable_to_non_nullable
as bool,errorEvent: freezed == errorEvent ? _self.errorEvent : errorEvent // ignore: cast_nullable_to_non_nullable
as LocationErrorEvent?,successMessage: freezed == successMessage ? _self.successMessage : successMessage // ignore: cast_nullable_to_non_nullable
as LocationErrorEvent?,successEvent: freezed == successEvent ? _self.successEvent : successEvent // ignore: cast_nullable_to_non_nullable
as LocationSuccessEvent?,
));
}
@@ -79,8 +79,8 @@ as LocationSuccessEvent?,
}
/// Adds pattern-matching-related methods to [LocationViewState].
extension LocationViewStatePatterns on LocationViewState {
/// Adds pattern-matching-related methods to [LocationState].
extension LocationStatePatterns on LocationState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
@@ -93,10 +93,10 @@ extension LocationViewStatePatterns on LocationViewState {
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _LocationViewState value)? $default,{required TResult orElse(),}){
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _LocationState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _LocationViewState() when $default != null:
case _LocationState() when $default != null:
return $default(_that);case _:
return orElse();
@@ -115,10 +115,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _LocationViewState value) $default,){
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _LocationState value) $default,){
final _that = this;
switch (_that) {
case _LocationViewState():
case _LocationState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
@@ -136,10 +136,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _LocationViewState value)? $default,){
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _LocationState value)? $default,){
final _that = this;
switch (_that) {
case _LocationViewState() when $default != null:
case _LocationState() when $default != null:
return $default(_that);case _:
return null;
@@ -157,10 +157,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<GeofenceEntity> geofences, List<FrequentPlaceEntity> frequentPlaces, List<PositionEntity> positionHistory, bool isLoadingHistory, bool isSubmitting, bool showRouteTrail, LocationErrorEvent? errorEvent, LocationSuccessEvent? successMessage)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<GeofenceEntity> geofences, List<FrequentPlaceEntity> frequentPlaces, List<PositionEntity> positionHistory, bool isLoadingHistory, bool isSubmitting, bool showRouteTrail, LocationErrorEvent? errorEvent, LocationSuccessEvent? successEvent)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _LocationViewState() when $default != null:
return $default(_that.geofences,_that.frequentPlaces,_that.positionHistory,_that.isLoadingHistory,_that.isSubmitting,_that.showRouteTrail,_that.errorEvent,_that.successMessage);case _:
case _LocationState() when $default != null:
return $default(_that.geofences,_that.frequentPlaces,_that.positionHistory,_that.isLoadingHistory,_that.isSubmitting,_that.showRouteTrail,_that.errorEvent,_that.successEvent);case _:
return orElse();
}
@@ -178,10 +178,10 @@ return $default(_that.geofences,_that.frequentPlaces,_that.positionHistory,_that
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<GeofenceEntity> geofences, List<FrequentPlaceEntity> frequentPlaces, List<PositionEntity> positionHistory, bool isLoadingHistory, bool isSubmitting, bool showRouteTrail, LocationErrorEvent? errorEvent, LocationSuccessEvent? successMessage) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<GeofenceEntity> geofences, List<FrequentPlaceEntity> frequentPlaces, List<PositionEntity> positionHistory, bool isLoadingHistory, bool isSubmitting, bool showRouteTrail, LocationErrorEvent? errorEvent, LocationSuccessEvent? successEvent) $default,) {final _that = this;
switch (_that) {
case _LocationViewState():
return $default(_that.geofences,_that.frequentPlaces,_that.positionHistory,_that.isLoadingHistory,_that.isSubmitting,_that.showRouteTrail,_that.errorEvent,_that.successMessage);case _:
case _LocationState():
return $default(_that.geofences,_that.frequentPlaces,_that.positionHistory,_that.isLoadingHistory,_that.isSubmitting,_that.showRouteTrail,_that.errorEvent,_that.successEvent);case _:
throw StateError('Unexpected subclass');
}
@@ -198,10 +198,10 @@ return $default(_that.geofences,_that.frequentPlaces,_that.positionHistory,_that
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<GeofenceEntity> geofences, List<FrequentPlaceEntity> frequentPlaces, List<PositionEntity> positionHistory, bool isLoadingHistory, bool isSubmitting, bool showRouteTrail, LocationErrorEvent? errorEvent, LocationSuccessEvent? successMessage)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<GeofenceEntity> geofences, List<FrequentPlaceEntity> frequentPlaces, List<PositionEntity> positionHistory, bool isLoadingHistory, bool isSubmitting, bool showRouteTrail, LocationErrorEvent? errorEvent, LocationSuccessEvent? successEvent)? $default,) {final _that = this;
switch (_that) {
case _LocationViewState() when $default != null:
return $default(_that.geofences,_that.frequentPlaces,_that.positionHistory,_that.isLoadingHistory,_that.isSubmitting,_that.showRouteTrail,_that.errorEvent,_that.successMessage);case _:
case _LocationState() when $default != null:
return $default(_that.geofences,_that.frequentPlaces,_that.positionHistory,_that.isLoadingHistory,_that.isSubmitting,_that.showRouteTrail,_that.errorEvent,_that.successEvent);case _:
return null;
}
@@ -212,8 +212,8 @@ return $default(_that.geofences,_that.frequentPlaces,_that.positionHistory,_that
/// @nodoc
class _LocationViewState implements LocationViewState {
const _LocationViewState({final List<GeofenceEntity> geofences = const [], final List<FrequentPlaceEntity> frequentPlaces = const [], final List<PositionEntity> positionHistory = const [], this.isLoadingHistory = false, this.isSubmitting = false, this.showRouteTrail = false, this.errorEvent, this.successMessage}): _geofences = geofences,_frequentPlaces = frequentPlaces,_positionHistory = positionHistory;
class _LocationState implements LocationState {
const _LocationState({final List<GeofenceEntity> geofences = const [], final List<FrequentPlaceEntity> frequentPlaces = const [], final List<PositionEntity> positionHistory = const [], this.isLoadingHistory = false, this.isSubmitting = false, this.showRouteTrail = false, this.errorEvent, this.successEvent}): _geofences = geofences,_frequentPlaces = frequentPlaces,_positionHistory = positionHistory;
final List<GeofenceEntity> _geofences;
@@ -241,39 +241,39 @@ class _LocationViewState implements LocationViewState {
@override@JsonKey() final bool isSubmitting;
@override@JsonKey() final bool showRouteTrail;
@override final LocationErrorEvent? errorEvent;
@override final LocationSuccessEvent? successMessage;
@override final LocationSuccessEvent? successEvent;
/// Create a copy of LocationViewState
/// Create a copy of LocationState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$LocationViewStateCopyWith<_LocationViewState> get copyWith => __$LocationViewStateCopyWithImpl<_LocationViewState>(this, _$identity);
_$LocationStateCopyWith<_LocationState> get copyWith => __$LocationStateCopyWithImpl<_LocationState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LocationViewState&&const DeepCollectionEquality().equals(other._geofences, _geofences)&&const DeepCollectionEquality().equals(other._frequentPlaces, _frequentPlaces)&&const DeepCollectionEquality().equals(other._positionHistory, _positionHistory)&&(identical(other.isLoadingHistory, isLoadingHistory) || other.isLoadingHistory == isLoadingHistory)&&(identical(other.isSubmitting, isSubmitting) || other.isSubmitting == isSubmitting)&&(identical(other.showRouteTrail, showRouteTrail) || other.showRouteTrail == showRouteTrail)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successMessage, successMessage) || other.successMessage == successMessage));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LocationState&&const DeepCollectionEquality().equals(other._geofences, _geofences)&&const DeepCollectionEquality().equals(other._frequentPlaces, _frequentPlaces)&&const DeepCollectionEquality().equals(other._positionHistory, _positionHistory)&&(identical(other.isLoadingHistory, isLoadingHistory) || other.isLoadingHistory == isLoadingHistory)&&(identical(other.isSubmitting, isSubmitting) || other.isSubmitting == isSubmitting)&&(identical(other.showRouteTrail, showRouteTrail) || other.showRouteTrail == showRouteTrail)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successEvent, successEvent) || other.successEvent == successEvent));
}
@override
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_geofences),const DeepCollectionEquality().hash(_frequentPlaces),const DeepCollectionEquality().hash(_positionHistory),isLoadingHistory,isSubmitting,showRouteTrail,errorEvent,successMessage);
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_geofences),const DeepCollectionEquality().hash(_frequentPlaces),const DeepCollectionEquality().hash(_positionHistory),isLoadingHistory,isSubmitting,showRouteTrail,errorEvent,successEvent);
@override
String toString() {
return 'LocationViewState(geofences: $geofences, frequentPlaces: $frequentPlaces, positionHistory: $positionHistory, isLoadingHistory: $isLoadingHistory, isSubmitting: $isSubmitting, showRouteTrail: $showRouteTrail, errorEvent: $errorEvent, successMessage: $successMessage)';
return 'LocationState(geofences: $geofences, frequentPlaces: $frequentPlaces, positionHistory: $positionHistory, isLoadingHistory: $isLoadingHistory, isSubmitting: $isSubmitting, showRouteTrail: $showRouteTrail, errorEvent: $errorEvent, successEvent: $successEvent)';
}
}
/// @nodoc
abstract mixin class _$LocationViewStateCopyWith<$Res> implements $LocationViewStateCopyWith<$Res> {
factory _$LocationViewStateCopyWith(_LocationViewState value, $Res Function(_LocationViewState) _then) = __$LocationViewStateCopyWithImpl;
abstract mixin class _$LocationStateCopyWith<$Res> implements $LocationStateCopyWith<$Res> {
factory _$LocationStateCopyWith(_LocationState value, $Res Function(_LocationState) _then) = __$LocationStateCopyWithImpl;
@override @useResult
$Res call({
List<GeofenceEntity> geofences, List<FrequentPlaceEntity> frequentPlaces, List<PositionEntity> positionHistory, bool isLoadingHistory, bool isSubmitting, bool showRouteTrail, LocationErrorEvent? errorEvent, LocationSuccessEvent? successMessage
List<GeofenceEntity> geofences, List<FrequentPlaceEntity> frequentPlaces, List<PositionEntity> positionHistory, bool isLoadingHistory, bool isSubmitting, bool showRouteTrail, LocationErrorEvent? errorEvent, LocationSuccessEvent? successEvent
});
@@ -281,17 +281,17 @@ $Res call({
}
/// @nodoc
class __$LocationViewStateCopyWithImpl<$Res>
implements _$LocationViewStateCopyWith<$Res> {
__$LocationViewStateCopyWithImpl(this._self, this._then);
class __$LocationStateCopyWithImpl<$Res>
implements _$LocationStateCopyWith<$Res> {
__$LocationStateCopyWithImpl(this._self, this._then);
final _LocationViewState _self;
final $Res Function(_LocationViewState) _then;
final _LocationState _self;
final $Res Function(_LocationState) _then;
/// Create a copy of LocationViewState
/// Create a copy of LocationState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? geofences = null,Object? frequentPlaces = null,Object? positionHistory = null,Object? isLoadingHistory = null,Object? isSubmitting = null,Object? showRouteTrail = null,Object? errorEvent = freezed,Object? successMessage = freezed,}) {
return _then(_LocationViewState(
@override @pragma('vm:prefer-inline') $Res call({Object? geofences = null,Object? frequentPlaces = null,Object? positionHistory = null,Object? isLoadingHistory = null,Object? isSubmitting = null,Object? showRouteTrail = null,Object? errorEvent = freezed,Object? successEvent = freezed,}) {
return _then(_LocationState(
geofences: null == geofences ? _self._geofences : geofences // ignore: cast_nullable_to_non_nullable
as List<GeofenceEntity>,frequentPlaces: null == frequentPlaces ? _self._frequentPlaces : frequentPlaces // ignore: cast_nullable_to_non_nullable
as List<FrequentPlaceEntity>,positionHistory: null == positionHistory ? _self._positionHistory : positionHistory // ignore: cast_nullable_to_non_nullable
@@ -299,7 +299,7 @@ as List<PositionEntity>,isLoadingHistory: null == isLoadingHistory ? _self.isLoa
as bool,isSubmitting: null == isSubmitting ? _self.isSubmitting : isSubmitting // ignore: cast_nullable_to_non_nullable
as bool,showRouteTrail: null == showRouteTrail ? _self.showRouteTrail : showRouteTrail // ignore: cast_nullable_to_non_nullable
as bool,errorEvent: freezed == errorEvent ? _self.errorEvent : errorEvent // ignore: cast_nullable_to_non_nullable
as LocationErrorEvent?,successMessage: freezed == successMessage ? _self.successMessage : successMessage // ignore: cast_nullable_to_non_nullable
as LocationErrorEvent?,successEvent: freezed == successEvent ? _self.successEvent : successEvent // ignore: cast_nullable_to_non_nullable
as LocationSuccessEvent?,
));
}

View File

@@ -0,0 +1,11 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'map_style_selector_controller.g.dart';
@riverpod
class MapStyleSelectorExpanded extends _$MapStyleSelectorExpanded {
@override
bool build() => false;
void set(bool value) => state = value;
}

View File

@@ -0,0 +1,64 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'map_style_selector_controller.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(MapStyleSelectorExpanded)
const mapStyleSelectorExpandedProvider = MapStyleSelectorExpandedProvider._();
final class MapStyleSelectorExpandedProvider
extends $NotifierProvider<MapStyleSelectorExpanded, bool> {
const MapStyleSelectorExpandedProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'mapStyleSelectorExpandedProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$mapStyleSelectorExpandedHash();
@$internal
@override
MapStyleSelectorExpanded create() => MapStyleSelectorExpanded();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(bool value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<bool>(value),
);
}
}
String _$mapStyleSelectorExpandedHash() =>
r'319f7a0ce2dc9bce1025bb52a0ead0a457eaf455';
abstract class _$MapStyleSelectorExpanded extends $Notifier<bool> {
bool build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<bool, bool>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<bool, bool>,
bool,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}

View File

@@ -1,40 +0,0 @@
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:location/src/core/domain/entities/frequent_place_entity.dart';
part 'location_view_state.freezed.dart';
enum LocationSuccessEvent {
geofenceCreated,
geofenceUpdated,
geofenceDeleted,
frequentPlaceCreated,
frequentPlaceUpdated,
frequentPlaceDeleted,
}
enum LocationErrorEvent {
geofenceCreate,
geofenceUpdate,
geofenceDelete,
frequentPlaceCreate,
frequentPlaceUpdate,
frequentPlaceDelete,
positionHistory,
locationFrequency,
}
@freezed
abstract class LocationViewState with _$LocationViewState {
const factory LocationViewState({
@Default([]) List<GeofenceEntity> geofences,
@Default([]) List<FrequentPlaceEntity> frequentPlaces,
@Default([]) List<PositionEntity> positionHistory,
@Default(false) bool isLoadingHistory,
@Default(false) bool isSubmitting,
@Default(false) bool showRouteTrail,
LocationErrorEvent? errorEvent,
LocationSuccessEvent? successMessage,
}) = _LocationViewState;
}

View File

@@ -1,287 +0,0 @@
import 'package:legacy_theme/legacy_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:latlong2/latlong.dart';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:location/src/core/domain/entities/frequent_place_entity.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:utils/utils.dart';
import '../state/location_view_model.dart';
import 'location_input_decoration.dart';
Future<void> showCreateFrequentPlaceSheet(
BuildContext context, {
required LatLng point,
}) {
return showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (_) => _FrequentPlaceSheet(point: point),
);
}
Future<void> showEditFrequentPlaceSheet(
BuildContext context, {
required FrequentPlaceEntity frequentPlace,
}) {
return showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (_) => _FrequentPlaceSheet(
point: LatLng(frequentPlace.lat, frequentPlace.lng),
editingPlace: frequentPlace,
),
);
}
class _FrequentPlaceSheet extends ConsumerStatefulWidget {
final LatLng point;
final FrequentPlaceEntity? editingPlace;
const _FrequentPlaceSheet({required this.point, this.editingPlace});
@override
ConsumerState<_FrequentPlaceSheet> createState() =>
_FrequentPlaceSheetState();
}
class _FrequentPlaceSheetState extends ConsumerState<_FrequentPlaceSheet> {
final _nameController = TextEditingController();
late List<WifiInfoEntity> _wifiList;
bool get _isEditing => widget.editingPlace != null;
@override
void initState() {
super.initState();
if (_isEditing) {
_nameController.text = widget.editingPlace!.name;
_wifiList = List.of(widget.editingPlace!.wifiList);
} else {
_wifiList = [];
}
}
@override
void dispose() {
_nameController.dispose();
super.dispose();
}
bool get _canSave => _nameController.text.trim().isNotEmpty;
Future<void> _submit() async {
if (!_canSave) return;
if (!await guardDeviceCommand(context, ref)) return;
final vm = ref.read(locationViewModelProvider.notifier);
final bool success;
if (_isEditing) {
success = await vm.updateFrequentPlace(
id: widget.editingPlace!.id,
name: _nameController.text.trim(),
lat: widget.point.latitude,
lng: widget.point.longitude,
wifiList: _wifiList,
);
} else {
success = await vm.createFrequentPlace(
name: _nameController.text.trim(),
lat: widget.point.latitude,
lng: widget.point.longitude,
wifiList: _wifiList,
);
}
if (success && mounted) {
Navigator.pop(context);
}
}
void _addWifi() {
setState(() {
_wifiList.add(WifiInfoEntity(ssid: '', bssid: '', signal: ''));
});
}
void _removeWifi(int index) {
setState(() => _wifiList.removeAt(index));
}
void _updateWifi(int index, WifiInfoEntity updated) {
setState(() => _wifiList[index] = updated);
}
@override
Widget build(BuildContext context) {
final primaryColor = context.sfColors.legacyPrimary;
final isSubmitting = ref.watch(
locationViewModelProvider.select((s) => s.value?.isSubmitting ?? false),
);
final errorEvent = ref.watch(
locationViewModelProvider.select((s) => s.value?.errorEvent),
);
return DraggableScrollableSheet(
initialChildSize: 0.25,
minChildSize: 0.15,
maxChildSize: 0.7,
builder: (context, scrollController) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: ListView(
controller: scrollController,
padding: EdgeInsets.symmetric(
horizontal: SizeUtils.getByScreen(small: 22, big: 24),
vertical: SizeUtils.getByScreen(small: 12, big: 14),
),
children: [
Center(
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.outline,
borderRadius: BorderRadius.circular(2),
),
),
),
SizedBox(height: SizeUtils.getByScreen(small: 10, big: 12)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
_isEditing
? context.translate(I18n.locationEditFrequentPlace)
: context.translate(I18n.locationNewFrequentPlace),
style: TextStyle(
fontSize: SizeUtils.getByScreen(small: 18, big: 19),
fontWeight: FontWeight.w600,
color: primaryColor,
),
),
),
TextButton(
onPressed: _canSave && !isSubmitting ? _submit : null,
child: isSubmitting
? SizedBox(
width: SizeUtils.getByScreen(small: 20, big: 22),
height: SizeUtils.getByScreen(small: 20, big: 22),
child: CircularProgressIndicator(
strokeWidth: 2,
color: primaryColor,
),
)
: Text(
_isEditing
? context.translate(I18n.locationSave)
: context.translate(I18n.locationCreate),
style: TextStyle(
color: _canSave ? primaryColor : Colors.grey,
fontWeight: FontWeight.w600,
fontSize: SizeUtils.getByScreen(
small: 16,
big: 17,
),
),
),
),
],
),
const SizedBox(height: 8),
Text(
context.translate(I18n.name),
style: TextStyle(
fontSize: SizeUtils.getByScreen(small: 15, big: 16),
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
TextField(
controller: _nameController,
onChanged: (_) => setState(() {}),
decoration: locationInputDecoration(
hintText: context.translate(I18n.locationHintFrequentPlace),
primaryColor: primaryColor,
),
),
if (_isEditing) ...[
SizedBox(height: SizeUtils.getByScreen(small: 14, big: 16)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
context.translate(I18n.locationWifiNetworksOptional),
style: TextStyle(
fontSize: SizeUtils.getByScreen(small: 15, big: 16),
fontWeight: FontWeight.w500,
),
),
GestureDetector(
onTap: _addWifi,
child: Icon(
Icons.add_circle_outline,
color: primaryColor,
size: 24,
),
),
],
),
const SizedBox(height: 8),
..._wifiList.asMap().entries.map((entry) {
final i = entry.key;
final wifi = entry.value;
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: [
Expanded(
child: TextFormField(
initialValue: wifi.ssid,
onChanged: (v) =>
_updateWifi(i, wifi.copyWith(ssid: v)),
decoration: locationInputDecoration(
hintText: 'SSID',
primaryColor: primaryColor,
),
style: const TextStyle(fontSize: 13),
),
),
SizedBox(width: 8),
GestureDetector(
onTap: () => _removeWifi(i),
child: Icon(
Icons.remove_circle_outline,
color: Theme.of(context).colorScheme.onSurfaceVariant,
size: 22,
),
),
],
),
);
}),
],
if (errorEvent != null)
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
context.translate(I18n.errorGeneric),
style: TextStyle(color: Theme.of(context).colorScheme.error, fontSize: 13),
),
),
SizedBox(height: SizeUtils.getByScreen(small: 8, big: 10)),
],
),
);
},
);
}
}

View File

@@ -1,267 +0,0 @@
import 'package:legacy_theme/legacy_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:latlong2/latlong.dart';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:utils/utils.dart';
import '../state/location_view_model.dart';
import 'location_input_decoration.dart';
Future<void> showCreateGeofenceSheet(
BuildContext context, {
required LatLng point,
required ValueNotifier<double> previewRadius,
}) {
return showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (_) => _GeofenceSheet(point: point, previewRadius: previewRadius),
);
}
Future<void> showEditGeofenceSheet(
BuildContext context, {
required GeofenceEntity geofence,
required ValueNotifier<double> previewRadius,
}) {
previewRadius.value = geofence.radius;
return showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (_) => _GeofenceSheet(
point: LatLng(geofence.latitude, geofence.longitude),
previewRadius: previewRadius,
editingGeofence: geofence,
),
);
}
class _GeofenceSheet extends ConsumerStatefulWidget {
final LatLng point;
final ValueNotifier<double> previewRadius;
final GeofenceEntity? editingGeofence;
const _GeofenceSheet({
required this.point,
required this.previewRadius,
this.editingGeofence,
});
@override
ConsumerState<_GeofenceSheet> createState() => _GeofenceSheetState();
}
class _GeofenceSheetState extends ConsumerState<_GeofenceSheet> {
final _nameController = TextEditingController();
final _descriptionController = TextEditingController();
late double _radius;
bool get _isEditing => widget.editingGeofence != null;
@override
void initState() {
super.initState();
if (_isEditing) {
_nameController.text = widget.editingGeofence!.name;
_descriptionController.text = widget.editingGeofence!.description ?? '';
_radius = widget.editingGeofence!.radius;
} else {
_radius = 200;
}
}
@override
void dispose() {
_nameController.dispose();
_descriptionController.dispose();
super.dispose();
}
bool get _canSave => _nameController.text.trim().isNotEmpty;
void _onRadiusChanged(double value) {
setState(() => _radius = value);
widget.previewRadius.value = value;
}
Future<void> _submit() async {
if (!_canSave) return;
if (!await guardDeviceCommand(context, ref)) return;
final vm = ref.read(locationViewModelProvider.notifier);
final description = _descriptionController.text.trim();
final bool success;
if (_isEditing) {
success = await vm.updateGeofence(
id: widget.editingGeofence!.id,
name: _nameController.text.trim(),
description: description.isNotEmpty ? description : null,
latitude: widget.point.latitude,
longitude: widget.point.longitude,
radius: _radius,
);
} else {
success = await vm.createGeofence(
name: _nameController.text.trim(),
description: description.isNotEmpty ? description : null,
latitude: widget.point.latitude,
longitude: widget.point.longitude,
radius: _radius,
);
}
if (success && mounted) {
Navigator.pop(context);
}
}
@override
Widget build(BuildContext context) {
final primaryColor = context.sfColors.legacyPrimary;
final isSubmitting = ref.watch(
locationViewModelProvider.select((s) => s.value?.isSubmitting ?? false),
);
final errorEvent = ref.watch(
locationViewModelProvider.select((s) => s.value?.errorEvent),
);
return DraggableScrollableSheet(
initialChildSize: 0.35,
minChildSize: 0.15,
maxChildSize: 0.7,
builder: (context, scrollController) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: ListView(
controller: scrollController,
padding: EdgeInsets.symmetric(
horizontal: SizeUtils.getByScreen(small: 22, big: 24),
vertical: SizeUtils.getByScreen(small: 12, big: 14),
),
children: [
Center(
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.outline,
borderRadius: BorderRadius.circular(2),
),
),
),
SizedBox(height: SizeUtils.getByScreen(small: 10, big: 12)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
_isEditing
? context.translate(I18n.locationEditGeofence)
: context.translate(I18n.locationNewGeofence),
style: TextStyle(
fontSize: SizeUtils.getByScreen(small: 18, big: 19),
fontWeight: FontWeight.w600,
color: primaryColor,
),
),
TextButton(
onPressed: _canSave && !isSubmitting ? _submit : null,
child: isSubmitting
? SizedBox(
width: SizeUtils.getByScreen(small: 20, big: 22),
height: SizeUtils.getByScreen(small: 20, big: 22),
child: CircularProgressIndicator(
strokeWidth: 2,
color: primaryColor,
),
)
: Text(
_isEditing
? context.translate(I18n.locationSave)
: context.translate(I18n.locationCreate),
style: TextStyle(
color: _canSave ? primaryColor : Colors.grey,
fontWeight: FontWeight.w600,
fontSize: SizeUtils.getByScreen(
small: 16,
big: 17,
),
),
),
),
],
),
const SizedBox(height: 8),
Text(
'${context.translate(I18n.locationRadius)}: ${context.translate(I18n.locationRadiusMeters, args: {'radius': '${_radius.round()}'})}',
style: TextStyle(
fontSize: SizeUtils.getByScreen(small: 15, big: 16),
fontWeight: FontWeight.w500,
),
),
Slider(
value: _radius,
min: 50,
max: 2000,
divisions: 39,
activeColor: primaryColor,
label: '${_radius.round()} m',
onChanged: _onRadiusChanged,
),
const SizedBox(height: 8),
Text(
context.translate(I18n.name),
style: TextStyle(
fontSize: SizeUtils.getByScreen(small: 15, big: 16),
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
TextField(
controller: _nameController,
onChanged: (_) => setState(() {}),
decoration: locationInputDecoration(
hintText: context.translate(I18n.locationHintGeofence),
primaryColor: primaryColor,
),
),
SizedBox(height: SizeUtils.getByScreen(small: 14, big: 16)),
Text(
context.translate(I18n.locationHintDescription),
style: TextStyle(
fontSize: SizeUtils.getByScreen(small: 15, big: 16),
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
TextField(
controller: _descriptionController,
decoration: locationInputDecoration(
hintText: context.translate(I18n.locationHintDescription),
primaryColor: primaryColor,
),
),
if (errorEvent != null)
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
context.translate(I18n.errorGeneric),
style: TextStyle(color: Theme.of(context).colorScheme.error, fontSize: 13),
),
),
SizedBox(height: SizeUtils.getByScreen(small: 8, big: 10)),
],
),
);
},
);
}
}

View File

@@ -11,6 +11,7 @@ class DeviceBanner extends ConsumerStatefulWidget {
final List<DeviceEntity> devices;
final List<PositionEntity> positions;
final ValueChanged<DeviceEntity> onDeviceChanged;
final VoidCallback? onTap;
const DeviceBanner({
super.key,
@@ -18,6 +19,7 @@ class DeviceBanner extends ConsumerStatefulWidget {
required this.devices,
required this.positions,
required this.onDeviceChanged,
this.onTap,
});
@override
@@ -26,24 +28,27 @@ class DeviceBanner extends ConsumerStatefulWidget {
class _DeviceBannerState extends ConsumerState<DeviceBanner> {
late final PageController _pageController;
int _currentPage = 0;
int get _currentPage {
final idx = widget.devices.indexWhere((d) => d.id == widget.device.id);
return idx < 0 ? 0 : idx;
}
@override
void initState() {
super.initState();
_currentPage = widget.devices.indexWhere((d) => d.id == widget.device.id);
if (_currentPage < 0) _currentPage = 0;
_pageController = PageController(initialPage: _currentPage);
}
@override
void didUpdateWidget(DeviceBanner oldWidget) {
super.didUpdateWidget(oldWidget);
final newIndex = widget.devices.indexWhere((d) => d.id == widget.device.id);
if (newIndex >= 0 && newIndex != _currentPage) {
_currentPage = newIndex;
final page = _pageController.hasClients
? _pageController.page?.round() ?? _currentPage
: _currentPage;
if (page != _currentPage) {
_pageController.animateToPage(
newIndex,
_currentPage,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
@@ -84,19 +89,21 @@ class _DeviceBannerState extends ConsumerState<DeviceBanner> {
child: PageView.builder(
controller: _pageController,
itemCount: widget.devices.length,
onPageChanged: (index) {
setState(() => _currentPage = index);
widget.onDeviceChanged(widget.devices[index]);
},
onPageChanged: (index) =>
widget.onDeviceChanged(widget.devices[index]),
itemBuilder: (context, index) {
final dev = widget.devices[index];
final pos = widget.positions
.where((p) => p.deviceIdentificator == dev.identificator)
.firstOrNull;
return _DeviceCard(
device: dev,
position: pos,
primaryColor: primaryColor,
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: widget.onTap,
child: _DeviceCard(
device: dev,
position: pos,
primaryColor: primaryColor,
),
);
},
),

View File

@@ -3,8 +3,9 @@ import 'dart:async';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:location/src/core/domain/entities/frequent_place_entity.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:location/src/features/location/presentation/providers/location_list_filter_controller.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_tracking/sf_tracking.dart';
@@ -33,12 +34,10 @@ class LocationListSheet extends ConsumerStatefulWidget {
}
class _LocationListSheetState extends ConsumerState<LocationListSheet> {
String? _selectedType;
List<PositionEntity> get _filteredHistory {
if (_selectedType == null) return widget.positionHistory;
List<PositionEntity> _filterHistory(String? selectedType) {
if (selectedType == null) return widget.positionHistory;
return widget.positionHistory
.where((p) => p.type == _selectedType)
.where((p) => p.type == selectedType)
.toList();
}
@@ -48,7 +47,8 @@ class _LocationListSheetState extends ConsumerState<LocationListSheet> {
@override
Widget build(BuildContext context) {
final filtered = _filteredHistory;
final selectedType = ref.watch(locationListFilterProvider);
final filtered = _filterHistory(selectedType);
return DraggableScrollableSheet(
initialChildSize: 0.45,
@@ -125,7 +125,7 @@ class _LocationListSheetState extends ConsumerState<LocationListSheet> {
count: filtered.length,
),
if (_availableTypes.length > 1)
_buildTypeFilters(context),
_buildTypeFilters(context, selectedType),
...filtered.map(_buildHistoryTile),
const SizedBox(height: 16),
],
@@ -154,7 +154,7 @@ class _LocationListSheetState extends ConsumerState<LocationListSheet> {
);
}
Widget _buildTypeFilters(BuildContext context) {
Widget _buildTypeFilters(BuildContext context, String? selectedType) {
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Wrap(
@@ -163,16 +163,25 @@ class _LocationListSheetState extends ConsumerState<LocationListSheet> {
_buildFilterChip(
label: context.translate(I18n.locationListAll),
value: null,
selectedType: selectedType,
),
for (final type in _availableTypes.toList()..sort())
_buildFilterChip(label: type, value: type),
_buildFilterChip(
label: type,
value: type,
selectedType: selectedType,
),
],
),
);
}
Widget _buildFilterChip({required String label, required String? value}) {
final isSelected = _selectedType == value;
Widget _buildFilterChip({
required String label,
required String? value,
required String? selectedType,
}) {
final isSelected = selectedType == value;
return GestureDetector(
onTap: () {
unawaited(
@@ -180,7 +189,7 @@ class _LocationListSheetState extends ConsumerState<LocationListSheet> {
.read(sfTrackingProvider)
.legacyLocationHistoryTypeFilterChanged(value ?? 'all'),
);
setState(() => _selectedType = value);
ref.read(locationListFilterProvider.notifier).select(value);
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),

View File

@@ -1,7 +1,6 @@
import 'dart:async';
import 'package:share_plus/share_plus.dart';
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -10,9 +9,9 @@ import 'package:legacy_ui/legacy_ui.dart';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:location/src/core/domain/entities/geofence_entity.dart';
import 'package:location/src/core/domain/entities/frequent_place_entity.dart';
import 'package:location/src/features/location/presentation/state/location_map_view_model.dart';
import 'package:location/src/features/location/presentation/state/location_map_view_state.dart';
import 'package:location/src/features/location/presentation/state/location_view_model.dart';
import 'package:location/src/features/location/presentation/providers/location_map_controller.dart';
import 'package:location/src/features/location/presentation/providers/location_map_state.dart';
import 'package:location/src/features/location/presentation/providers/location_controller.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
@@ -75,8 +74,8 @@ class _LocationMapState extends ConsumerState<LocationMap>
AnimationController? _moveAnimation;
Timer? _followTimer;
LocationMapViewModel get _vm =>
ref.read(locationMapViewModelProvider.notifier);
LocationMapController get _vm =>
ref.read(locationMapControllerProvider.notifier);
Color get _primaryColor =>
context.sfColors.legacyPrimary;
@@ -123,7 +122,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
} else if (widget.selectedPosition != null &&
widget.selectedPosition != oldWidget.selectedPosition) {
final firstFix = oldWidget.selectedPosition == null;
final isFollowing = ref.read(locationMapViewModelProvider).isFollowing;
final isFollowing = ref.read(locationMapControllerProvider).isFollowing;
if (firstFix || isFollowing) _centerOnDevice();
}
@@ -249,7 +248,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
Future<void> _updateFrequency(int frequency) async {
if (!await guardDeviceCommand(context, ref)) return;
final success = await ref
.read(locationViewModelProvider.notifier)
.read(locationControllerProvider.notifier)
.updateLocationFrequency(frequency: frequency);
if (!mounted) return;
if (success) {
@@ -258,19 +257,10 @@ class _LocationMapState extends ConsumerState<LocationMap>
_followTimer = Timer.periodic(Duration(seconds: safeFrequency), (_) {
widget.onRefreshPosition();
});
showTopSnackbar(
await showSuccessDialog(
context,
message: context.translate(
I18n.locationFrequencyUpdated,
args: {'minutes': '${frequency ~/ 60}'},
),
type: MessageType.success,
);
} else {
showTopSnackbar(
context,
message: context.translate(I18n.errorLocationFrequency),
type: MessageType.error,
I18n.locationFrequencyUpdated,
args: {'minutes': '${frequency ~/ 60}'},
);
}
}
@@ -279,7 +269,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
if (!await guardDeviceCommand(context, ref)) return;
if (!mounted) return;
final center = _mapController.camera.center;
final mapState = ref.read(locationMapViewModelProvider);
final mapState = ref.read(locationMapControllerProvider);
if (mapState.placingMode == PlacingMode.geofence) {
_vm.confirmGeofencePlacement(center);
@@ -291,7 +281,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
title: context.translate(I18n.locationNewFrequentPlace),
hintText: context.translate(I18n.locationHintFrequentPlace),
onSubmit: (name, _) => ref
.read(locationViewModelProvider.notifier)
.read(locationControllerProvider.notifier)
.createFrequentPlace(
name: name,
lat: center.latitude,
@@ -304,7 +294,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
Future<void> _confirmRadius() async {
if (!await guardDeviceCommand(context, ref)) return;
if (!mounted) return;
final mapState = ref.read(locationMapViewModelProvider);
final mapState = ref.read(locationMapControllerProvider);
final point = mapState.previewPoint!;
final radius = mapState.previewRadius;
final editing = mapState.editingGeofence;
@@ -326,7 +316,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
onSubmit: (name, description) {
if (editing != null) {
return ref
.read(locationViewModelProvider.notifier)
.read(locationControllerProvider.notifier)
.updateGeofence(
id: editing.id,
name: name,
@@ -337,7 +327,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
);
}
return ref
.read(locationViewModelProvider.notifier)
.read(locationControllerProvider.notifier)
.createGeofence(
name: name,
description: description,
@@ -351,9 +341,9 @@ class _LocationMapState extends ConsumerState<LocationMap>
void _showListSheet() {
unawaited(ref.read(sfTrackingProvider).legacyLocationListSheetOpened());
final locationState = ref.read(locationViewModelProvider).value;
final locationState = ref.read(locationControllerProvider).value;
if (locationState == null) return;
final mapState = ref.read(locationMapViewModelProvider);
final mapState = ref.read(locationMapControllerProvider);
showModalBottomSheet(
context: context,
isScrollControlled: true,
@@ -389,7 +379,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
if (widget.positionHistory.isEmpty) {
_openDateRangePicker();
} else {
ref.read(locationViewModelProvider.notifier).toggleRouteTrail();
ref.read(locationControllerProvider.notifier).toggleRouteTrail();
}
}
@@ -422,7 +412,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
59,
);
ref
.read(locationViewModelProvider.notifier)
.read(locationControllerProvider.notifier)
.loadPositionHistory(from: picked.start, to: to);
}
}
@@ -439,7 +429,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
initialName: fp.name,
submitLabel: context.translate(I18n.locationSave),
onSubmit: (name, _) => ref
.read(locationViewModelProvider.notifier)
.read(locationControllerProvider.notifier)
.updateFrequentPlace(
id: fp.id,
name: name,
@@ -450,7 +440,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
);
}
List<Widget> _buildMapLayers(LocationMapViewState mapState) {
List<Widget> _buildMapLayers(LocationMapState mapState) {
final historyLayer =
widget.showRouteTrail && widget.positionHistory.isNotEmpty
? RouteHistoryLayer(
@@ -506,13 +496,14 @@ class _LocationMapState extends ConsumerState<LocationMap>
devices: widget.devices,
positions: widget.positions,
onDeviceChanged: widget.onDeviceChanged,
onTap: _centerOnDevice,
),
),
];
}
List<Marker> _buildMarkers(
LocationMapViewState mapState,
LocationMapState mapState,
RouteHistoryLayer? historyLayer,
) {
return [
@@ -599,7 +590,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
];
}
List<Widget> _buildControls(LocationMapViewState mapState) {
List<Widget> _buildControls(LocationMapState mapState) {
if (mapState.placingMode != PlacingMode.none) {
return [
Center(
@@ -696,11 +687,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
);
widget.onRefreshPosition();
if (!mounted) return;
showTopSnackbar(
context,
message: context.translate(I18n.locationMapRefreshRequested),
type: MessageType.info,
);
await showInfoDialog(context, I18n.locationMapRefreshRequested);
},
onCenterTap: _centerOnDevice,
onToggleFollow: () async {
@@ -716,14 +703,11 @@ class _LocationMapState extends ConsumerState<LocationMap>
_centerOnDevice();
}
if (!mounted) return;
showTopSnackbar(
await showSuccessDialog(
context,
message: context.translate(
willActivate
? I18n.locationMapFollowEnabled
: I18n.locationMapFollowDisabled,
),
type: MessageType.success,
willActivate
? I18n.locationMapFollowEnabled
: I18n.locationMapFollowDisabled,
);
},
),
@@ -731,7 +715,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
];
}
List<Widget> _buildInfoCards(LocationMapViewState mapState) {
List<Widget> _buildInfoCards(LocationMapState mapState) {
return [
if (mapState.selectedGeofence != null)
ModalOverlay(
@@ -748,7 +732,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
final id = mapState.selectedGeofence!.id;
_vm.clearSelectedGeofence();
ref
.read(locationViewModelProvider.notifier)
.read(locationControllerProvider.notifier)
.deleteGeofence(id: id);
},
),
@@ -765,7 +749,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
final id = mapState.selectedFrequentPlace!.id;
_vm.clearSelectedFrequentPlace();
ref
.read(locationViewModelProvider.notifier)
.read(locationControllerProvider.notifier)
.deleteFrequentPlace(id: id);
},
),
@@ -783,7 +767,7 @@ class _LocationMapState extends ConsumerState<LocationMap>
@override
Widget build(BuildContext context) {
final mapState = ref.watch(locationMapViewModelProvider);
final mapState = ref.watch(locationMapControllerProvider);
final hasPosition = widget.selectedPosition != null;
final initialCenter = hasPosition
? LatLng(

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:location/src/features/location/presentation/state/location_map_view_model.dart';
import 'package:location/src/features/location/presentation/providers/location_map_controller.dart';
import 'package:utils/utils.dart';
import 'map_action_button.dart';
@@ -101,9 +101,9 @@ class FrequencySelector extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final expanded = ref.watch(
locationMapViewModelProvider.select((s) => s.frequencyExpanded),
locationMapControllerProvider.select((s) => s.frequencyExpanded),
);
final vm = ref.read(locationMapViewModelProvider.notifier);
final vm = ref.read(locationMapControllerProvider.notifier);
return AnimatedSize(
duration: const Duration(milliseconds: 200),
@@ -118,7 +118,7 @@ class FrequencySelector extends ConsumerWidget {
);
}
Widget _buildSegmented(BuildContext context, LocationMapViewModel vm) {
Widget _buildSegmented(BuildContext context, LocationMapController vm) {
return Material(
elevation: 2,
borderRadius: BorderRadius.circular(8),

View File

@@ -1,9 +1,10 @@
import 'dart:async';
import 'package:legacy_theme/legacy_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_theme/legacy_theme.dart';
import 'package:legacy_ui/legacy_ui.dart';
import 'package:location/src/features/location/presentation/providers/map_style_selector_controller.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_tracking/sf_tracking.dart';
@@ -15,28 +16,23 @@ const _labelKeys = {
MapStyle.satellite: I18n.locationMapStyleSatellite,
};
class MapStyleSelector extends ConsumerStatefulWidget {
class MapStyleSelector extends ConsumerWidget {
const MapStyleSelector({super.key});
@override
ConsumerState<MapStyleSelector> createState() => _MapStyleSelectorState();
}
class _MapStyleSelectorState extends ConsumerState<MapStyleSelector> {
bool _expanded = false;
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
final currentStyle = ref.watch(mapStyleProvider);
final expanded = ref.watch(mapStyleSelectorExpandedProvider);
final primaryColor = context.sfColors.legacyPrimary;
if (!_expanded) {
if (!expanded) {
return Material(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(8),
elevation: 2,
child: InkWell(
onTap: () => setState(() => _expanded = true),
onTap: () =>
ref.read(mapStyleSelectorExpandedProvider.notifier).set(true),
borderRadius: BorderRadius.circular(8),
child: const SizedBox(
width: 40,
@@ -72,7 +68,7 @@ class _MapStyleSelectorState extends ConsumerState<MapStyleSelector> {
.read(sfTrackingProvider)
.legacyLocationMapStyleChanged(style.name),
);
setState(() => _expanded = false);
ref.read(mapStyleSelectorExpandedProvider.notifier).set(false);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
@@ -84,7 +80,9 @@ class _MapStyleSelectorState extends ConsumerState<MapStyleSelector> {
? Icons.satellite_alt
: Icons.map,
size: 16,
color: isSelected ? primaryColor : Theme.of(context).colorScheme.onSurfaceVariant,
color: isSelected
? primaryColor
: Theme.of(context).colorScheme.onSurfaceVariant,
),
const SizedBox(width: 8),
Text(
@@ -94,7 +92,9 @@ class _MapStyleSelectorState extends ConsumerState<MapStyleSelector> {
fontWeight: isSelected
? FontWeight.w600
: FontWeight.w400,
color: isSelected ? primaryColor : Theme.of(context).colorScheme.onSurface,
color: isSelected
? primaryColor
: Theme.of(context).colorScheme.onSurface,
),
),
],

View File

@@ -118,47 +118,56 @@ class _NameInputSheetContentState extends State<_NameInputSheetContent> {
),
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.title,
style: TextStyle(
fontSize: SizeUtils.getByScreen(small: 18, big: 19),
fontWeight: FontWeight.w600,
color: widget.primaryColor,
),
),
TextButton(
onPressed: _canSave
? () async {
Navigator.pop(context);
final name = _nameController.text.trim();
final desc = _descController.text.trim();
await widget.onSubmit(
name,
widget.showDescription && desc.isNotEmpty
? desc
: null,
);
}
: null,
child: Text(
widget.submitLabel,
style: TextStyle(
color: _canSave ? widget.primaryColor : Colors.grey,
fontWeight: FontWeight.w600,
fontSize: SizeUtils.getByScreen(small: 16, big: 17),
AnimatedBuilder(
animation: _nameController,
builder: (context, _) {
final canSave = _canSave;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.title,
style: TextStyle(
fontSize:
SizeUtils.getByScreen(small: 18, big: 19),
fontWeight: FontWeight.w600,
color: widget.primaryColor,
),
),
),
),
],
TextButton(
onPressed: canSave
? () async {
Navigator.pop(context);
final name = _nameController.text.trim();
final desc = _descController.text.trim();
await widget.onSubmit(
name,
widget.showDescription && desc.isNotEmpty
? desc
: null,
);
}
: null,
child: Text(
widget.submitLabel,
style: TextStyle(
color: canSave
? widget.primaryColor
: Colors.grey,
fontWeight: FontWeight.w600,
fontSize:
SizeUtils.getByScreen(small: 16, big: 17),
),
),
),
],
);
},
),
const SizedBox(height: 12),
TextField(
controller: _nameController,
autofocus: true,
onChanged: (_) => setState(() {}),
decoration: locationInputDecoration(
hintText: widget.hintText,
primaryColor: widget.primaryColor,

View File

@@ -31,6 +31,7 @@ dependencies:
path: ../../../../packages/utils
get_it: ^9.0.5
flutter_riverpod: ^3.0.3
riverpod_annotation: ^3.0.3
go_router: ^17.0.0
freezed_annotation: ^3.1.0
json_annotation: ^4.9.0
@@ -49,6 +50,7 @@ dev_dependencies:
build_runner: ^2.7.1
freezed: ^3.2.3
json_serializable: ^6.11.2
riverpod_generator: ^3.0.3
flutter:
uses-material-design: true

View File

@@ -9,6 +9,8 @@ export 'src/features/language/language_builder.dart';
export 'src/features/remote_management/remote_management_builder.dart';
export 'src/features/remote_on_off/remote_on_off_builder.dart';
export 'src/features/alerts/alerts_builder.dart';
export 'src/features/notifications/notifications_builder.dart'
show DeviceNotificationsBuilder;
export 'src/features/sos_contacts/sos_contacts_builder.dart';
export 'src/features/sound/sound_builder.dart';
export 'src/features/sync_clock/sync_clock_builder.dart';

View File

@@ -0,0 +1,9 @@
import '../../domain/entities/notification_entity.dart';
abstract class NotificationsRemoteDatasource {
Future<(List<NotificationEntity>, int totalPages)> getNotifications({
required int page,
int pageSize,
String? type,
});
}

View File

@@ -1,17 +1,17 @@
import 'package:sf_infrastructure/sf_infrastructure.dart';
import 'package:utils/utils.dart';
import '../../domain/entities/alert_entity.dart';
import '../models/alerts_response_dto.dart';
import 'alerts_remote_datasource.dart';
import '../../domain/entities/notification_entity.dart';
import '../models/notifications_response_dto.dart';
import 'notifications_remote_datasource.dart';
class AlertsRemoteDatasourceImpl implements AlertsRemoteDatasource {
AlertsRemoteDatasourceImpl(this._repository);
class NotificationsRemoteDatasourceImpl implements NotificationsRemoteDatasource {
NotificationsRemoteDatasourceImpl(this._repository);
final SaveFamilyRepository _repository;
@override
Future<(List<AlertEntity>, int totalPages)> getAlerts({
Future<(List<NotificationEntity>, int totalPages)> getNotifications({
required int page,
int pageSize = 20,
String? type,
@@ -36,9 +36,9 @@ class AlertsRemoteDatasourceImpl implements AlertsRemoteDatasource {
);
final data = response.data;
if (data == null || data.isEmpty) return (<AlertEntity>[], 1);
if (data == null || data.isEmpty) return (<NotificationEntity>[], 1);
final model = AlertsResponseDto.fromJson(data);
final model = NotificationsResponseDto.fromJson(data);
return (model.toEntities(), model.pages);
}
}

View File

@@ -1,56 +1,56 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/entities/alert_entity.dart';
import '../../domain/entities/notification_entity.dart';
part 'alerts_response_dto.freezed.dart';
part 'alerts_response_dto.g.dart';
part 'notifications_response_dto.freezed.dart';
part 'notifications_response_dto.g.dart';
@freezed
abstract class AlertsResponseDto with _$AlertsResponseDto {
const factory AlertsResponseDto({
abstract class NotificationsResponseDto with _$NotificationsResponseDto {
const factory NotificationsResponseDto({
@Default(0) int total,
@Default([]) List<AlertItemDto> items,
@Default([]) List<NotificationItemDto> items,
@Default(1) int page,
@Default(1) int pages,
}) = _AlertsResponseDto;
factory AlertsResponseDto.fromJson(Map<String, dynamic> json) =>
factory NotificationsResponseDto.fromJson(Map<String, dynamic> json) =>
_$AlertsResponseDtoFromJson(json);
}
@freezed
abstract class AlertItemDto with _$AlertItemDto {
const factory AlertItemDto({
abstract class NotificationItemDto with _$NotificationItemDto {
const factory NotificationItemDto({
required String id,
@Default('') String deviceIdentificator,
@Default('') String deviceName,
@Default('') String type,
AlertGeofenceDto? geofenceAlert,
NotificationGeofenceDto? geofenceAlert,
String? delegationId,
String? userId,
@Default(0) int createdAt,
}) = _AlertItemDto;
factory AlertItemDto.fromJson(Map<String, dynamic> json) =>
factory NotificationItemDto.fromJson(Map<String, dynamic> json) =>
_$AlertItemDtoFromJson(json);
}
@freezed
abstract class AlertGeofenceDto with _$AlertGeofenceDto {
const factory AlertGeofenceDto({
abstract class NotificationGeofenceDto with _$NotificationGeofenceDto {
const factory NotificationGeofenceDto({
required String id,
required String name,
}) = _AlertGeofenceDto;
factory AlertGeofenceDto.fromJson(Map<String, dynamic> json) =>
factory NotificationGeofenceDto.fromJson(Map<String, dynamic> json) =>
_$AlertGeofenceDtoFromJson(json);
}
extension AlertsResponseDtoMapper on AlertsResponseDto {
List<AlertEntity> toEntities() {
extension NotificationsResponseDtoMapper on NotificationsResponseDto {
List<NotificationEntity> toEntities() {
return items
.map(
(item) => AlertEntity(
(item) => NotificationEntity(
id: item.id,
deviceIdentificator: item.deviceIdentificator,
deviceName: item.deviceName,

View File

@@ -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 'alerts_response_dto.dart';
part of 'notifications_response_dto.dart';
// **************************************************************************
// FreezedGenerator
@@ -11,24 +11,31 @@ part of 'alerts_response_dto.dart';
// dart format off
T _$identity<T>(T value) => value;
NotificationsResponseDto _$NotificationsResponseDtoFromJson(
Map<String, dynamic> json
) {
return _AlertsResponseDto.fromJson(
json
);
}
/// @nodoc
mixin _$AlertsResponseDto {
mixin _$NotificationsResponseDto {
int get total; List<AlertItemDto> get items; int get page; int get pages;
/// Create a copy of AlertsResponseDto
int get total; List<NotificationItemDto> get items; int get page; int get pages;
/// Create a copy of NotificationsResponseDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AlertsResponseDtoCopyWith<AlertsResponseDto> get copyWith => _$AlertsResponseDtoCopyWithImpl<AlertsResponseDto>(this as AlertsResponseDto, _$identity);
$NotificationsResponseDtoCopyWith<NotificationsResponseDto> get copyWith => _$NotificationsResponseDtoCopyWithImpl<NotificationsResponseDto>(this as NotificationsResponseDto, _$identity);
/// Serializes this AlertsResponseDto to a JSON map.
/// Serializes this NotificationsResponseDto to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AlertsResponseDto&&(identical(other.total, total) || other.total == total)&&const DeepCollectionEquality().equals(other.items, items)&&(identical(other.page, page) || other.page == page)&&(identical(other.pages, pages) || other.pages == pages));
return identical(this, other) || (other.runtimeType == runtimeType&&other is NotificationsResponseDto&&(identical(other.total, total) || other.total == total)&&const DeepCollectionEquality().equals(other.items, items)&&(identical(other.page, page) || other.page == page)&&(identical(other.pages, pages) || other.pages == pages));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -37,18 +44,18 @@ int get hashCode => Object.hash(runtimeType,total,const DeepCollectionEquality()
@override
String toString() {
return 'AlertsResponseDto(total: $total, items: $items, page: $page, pages: $pages)';
return 'NotificationsResponseDto(total: $total, items: $items, page: $page, pages: $pages)';
}
}
/// @nodoc
abstract mixin class $AlertsResponseDtoCopyWith<$Res> {
factory $AlertsResponseDtoCopyWith(AlertsResponseDto value, $Res Function(AlertsResponseDto) _then) = _$AlertsResponseDtoCopyWithImpl;
abstract mixin class $NotificationsResponseDtoCopyWith<$Res> {
factory $NotificationsResponseDtoCopyWith(NotificationsResponseDto value, $Res Function(NotificationsResponseDto) _then) = _$NotificationsResponseDtoCopyWithImpl;
@useResult
$Res call({
int total, List<AlertItemDto> items, int page, int pages
int total, List<NotificationItemDto> items, int page, int pages
});
@@ -56,20 +63,20 @@ $Res call({
}
/// @nodoc
class _$AlertsResponseDtoCopyWithImpl<$Res>
implements $AlertsResponseDtoCopyWith<$Res> {
_$AlertsResponseDtoCopyWithImpl(this._self, this._then);
class _$NotificationsResponseDtoCopyWithImpl<$Res>
implements $NotificationsResponseDtoCopyWith<$Res> {
_$NotificationsResponseDtoCopyWithImpl(this._self, this._then);
final AlertsResponseDto _self;
final $Res Function(AlertsResponseDto) _then;
final NotificationsResponseDto _self;
final $Res Function(NotificationsResponseDto) _then;
/// Create a copy of AlertsResponseDto
/// Create a copy of NotificationsResponseDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? total = null,Object? items = null,Object? page = null,Object? pages = null,}) {
return _then(_self.copyWith(
total: null == total ? _self.total : total // ignore: cast_nullable_to_non_nullable
as int,items: null == items ? _self.items : items // ignore: cast_nullable_to_non_nullable
as List<AlertItemDto>,page: null == page ? _self.page : page // ignore: cast_nullable_to_non_nullable
as List<NotificationItemDto>,page: null == page ? _self.page : page // ignore: cast_nullable_to_non_nullable
as int,pages: null == pages ? _self.pages : pages // ignore: cast_nullable_to_non_nullable
as int,
));
@@ -78,8 +85,8 @@ as int,
}
/// Adds pattern-matching-related methods to [AlertsResponseDto].
extension AlertsResponseDtoPatterns on AlertsResponseDto {
/// Adds pattern-matching-related methods to [NotificationsResponseDto].
extension NotificationsResponseDtoPatterns on NotificationsResponseDto {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
@@ -156,7 +163,7 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int total, List<AlertItemDto> items, int page, int pages)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int total, List<NotificationItemDto> items, int page, int pages)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _AlertsResponseDto() when $default != null:
return $default(_that.total,_that.items,_that.page,_that.pages);case _:
@@ -177,7 +184,7 @@ return $default(_that.total,_that.items,_that.page,_that.pages);case _:
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int total, List<AlertItemDto> items, int page, int pages) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int total, List<NotificationItemDto> items, int page, int pages) $default,) {final _that = this;
switch (_that) {
case _AlertsResponseDto():
return $default(_that.total,_that.items,_that.page,_that.pages);case _:
@@ -197,7 +204,7 @@ return $default(_that.total,_that.items,_that.page,_that.pages);case _:
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int total, List<AlertItemDto> items, int page, int pages)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int total, List<NotificationItemDto> items, int page, int pages)? $default,) {final _that = this;
switch (_that) {
case _AlertsResponseDto() when $default != null:
return $default(_that.total,_that.items,_that.page,_that.pages);case _:
@@ -211,13 +218,13 @@ return $default(_that.total,_that.items,_that.page,_that.pages);case _:
/// @nodoc
@JsonSerializable()
class _AlertsResponseDto implements AlertsResponseDto {
const _AlertsResponseDto({this.total = 0, final List<AlertItemDto> items = const [], this.page = 1, this.pages = 1}): _items = items;
class _AlertsResponseDto implements NotificationsResponseDto {
const _AlertsResponseDto({this.total = 0, final List<NotificationItemDto> items = const [], this.page = 1, this.pages = 1}): _items = items;
factory _AlertsResponseDto.fromJson(Map<String, dynamic> json) => _$AlertsResponseDtoFromJson(json);
@override@JsonKey() final int total;
final List<AlertItemDto> _items;
@override@JsonKey() List<AlertItemDto> get items {
final List<NotificationItemDto> _items;
@override@JsonKey() List<NotificationItemDto> get items {
if (_items is EqualUnmodifiableListView) return _items;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_items);
@@ -226,7 +233,7 @@ class _AlertsResponseDto implements AlertsResponseDto {
@override@JsonKey() final int page;
@override@JsonKey() final int pages;
/// Create a copy of AlertsResponseDto
/// Create a copy of NotificationsResponseDto
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
@@ -248,18 +255,18 @@ int get hashCode => Object.hash(runtimeType,total,const DeepCollectionEquality()
@override
String toString() {
return 'AlertsResponseDto(total: $total, items: $items, page: $page, pages: $pages)';
return 'NotificationsResponseDto(total: $total, items: $items, page: $page, pages: $pages)';
}
}
/// @nodoc
abstract mixin class _$AlertsResponseDtoCopyWith<$Res> implements $AlertsResponseDtoCopyWith<$Res> {
abstract mixin class _$AlertsResponseDtoCopyWith<$Res> implements $NotificationsResponseDtoCopyWith<$Res> {
factory _$AlertsResponseDtoCopyWith(_AlertsResponseDto value, $Res Function(_AlertsResponseDto) _then) = __$AlertsResponseDtoCopyWithImpl;
@override @useResult
$Res call({
int total, List<AlertItemDto> items, int page, int pages
int total, List<NotificationItemDto> items, int page, int pages
});
@@ -274,13 +281,13 @@ class __$AlertsResponseDtoCopyWithImpl<$Res>
final _AlertsResponseDto _self;
final $Res Function(_AlertsResponseDto) _then;
/// Create a copy of AlertsResponseDto
/// Create a copy of NotificationsResponseDto
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? total = null,Object? items = null,Object? page = null,Object? pages = null,}) {
return _then(_AlertsResponseDto(
total: null == total ? _self.total : total // ignore: cast_nullable_to_non_nullable
as int,items: null == items ? _self._items : items // ignore: cast_nullable_to_non_nullable
as List<AlertItemDto>,page: null == page ? _self.page : page // ignore: cast_nullable_to_non_nullable
as List<NotificationItemDto>,page: null == page ? _self.page : page // ignore: cast_nullable_to_non_nullable
as int,pages: null == pages ? _self.pages : pages // ignore: cast_nullable_to_non_nullable
as int,
));
@@ -289,24 +296,31 @@ as int,
}
NotificationItemDto _$NotificationItemDtoFromJson(
Map<String, dynamic> json
) {
return _AlertItemDto.fromJson(
json
);
}
/// @nodoc
mixin _$AlertItemDto {
mixin _$NotificationItemDto {
String get id; String get deviceIdentificator; String get deviceName; String get type; AlertGeofenceDto? get geofenceAlert; String? get delegationId; String? get userId; int get createdAt;
/// Create a copy of AlertItemDto
String get id; String get deviceIdentificator; String get deviceName; String get type; NotificationGeofenceDto? get geofenceAlert; String? get delegationId; String? get userId; int get createdAt;
/// Create a copy of NotificationItemDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AlertItemDtoCopyWith<AlertItemDto> get copyWith => _$AlertItemDtoCopyWithImpl<AlertItemDto>(this as AlertItemDto, _$identity);
$NotificationItemDtoCopyWith<NotificationItemDto> get copyWith => _$NotificationItemDtoCopyWithImpl<NotificationItemDto>(this as NotificationItemDto, _$identity);
/// Serializes this AlertItemDto to a JSON map.
/// Serializes this NotificationItemDto to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AlertItemDto&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.type, type) || other.type == type)&&(identical(other.geofenceAlert, geofenceAlert) || other.geofenceAlert == geofenceAlert)&&(identical(other.delegationId, delegationId) || other.delegationId == delegationId)&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt));
return identical(this, other) || (other.runtimeType == runtimeType&&other is NotificationItemDto&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.type, type) || other.type == type)&&(identical(other.geofenceAlert, geofenceAlert) || other.geofenceAlert == geofenceAlert)&&(identical(other.delegationId, delegationId) || other.delegationId == delegationId)&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -315,33 +329,33 @@ int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,deviceName,ty
@override
String toString() {
return 'AlertItemDto(id: $id, deviceIdentificator: $deviceIdentificator, deviceName: $deviceName, type: $type, geofenceAlert: $geofenceAlert, delegationId: $delegationId, userId: $userId, createdAt: $createdAt)';
return 'NotificationItemDto(id: $id, deviceIdentificator: $deviceIdentificator, deviceName: $deviceName, type: $type, geofenceAlert: $geofenceAlert, delegationId: $delegationId, userId: $userId, createdAt: $createdAt)';
}
}
/// @nodoc
abstract mixin class $AlertItemDtoCopyWith<$Res> {
factory $AlertItemDtoCopyWith(AlertItemDto value, $Res Function(AlertItemDto) _then) = _$AlertItemDtoCopyWithImpl;
abstract mixin class $NotificationItemDtoCopyWith<$Res> {
factory $NotificationItemDtoCopyWith(NotificationItemDto value, $Res Function(NotificationItemDto) _then) = _$NotificationItemDtoCopyWithImpl;
@useResult
$Res call({
String id, String deviceIdentificator, String deviceName, String type, AlertGeofenceDto? geofenceAlert, String? delegationId, String? userId, int createdAt
String id, String deviceIdentificator, String deviceName, String type, NotificationGeofenceDto? geofenceAlert, String? delegationId, String? userId, int createdAt
});
$AlertGeofenceDtoCopyWith<$Res>? get geofenceAlert;
$NotificationGeofenceDtoCopyWith<$Res>? get geofenceAlert;
}
/// @nodoc
class _$AlertItemDtoCopyWithImpl<$Res>
implements $AlertItemDtoCopyWith<$Res> {
_$AlertItemDtoCopyWithImpl(this._self, this._then);
class _$NotificationItemDtoCopyWithImpl<$Res>
implements $NotificationItemDtoCopyWith<$Res> {
_$NotificationItemDtoCopyWithImpl(this._self, this._then);
final AlertItemDto _self;
final $Res Function(AlertItemDto) _then;
final NotificationItemDto _self;
final $Res Function(NotificationItemDto) _then;
/// Create a copy of AlertItemDto
/// Create a copy of NotificationItemDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceIdentificator = null,Object? deviceName = null,Object? type = null,Object? geofenceAlert = freezed,Object? delegationId = freezed,Object? userId = freezed,Object? createdAt = null,}) {
return _then(_self.copyWith(
@@ -350,30 +364,30 @@ as String,deviceIdentificator: null == deviceIdentificator ? _self.deviceIdentif
as String,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable
as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as String,geofenceAlert: freezed == geofenceAlert ? _self.geofenceAlert : geofenceAlert // ignore: cast_nullable_to_non_nullable
as AlertGeofenceDto?,delegationId: freezed == delegationId ? _self.delegationId : delegationId // ignore: cast_nullable_to_non_nullable
as NotificationGeofenceDto?,delegationId: freezed == delegationId ? _self.delegationId : delegationId // ignore: cast_nullable_to_non_nullable
as String?,userId: freezed == userId ? _self.userId : userId // ignore: cast_nullable_to_non_nullable
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as int,
));
}
/// Create a copy of AlertItemDto
/// Create a copy of NotificationItemDto
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$AlertGeofenceDtoCopyWith<$Res>? get geofenceAlert {
$NotificationGeofenceDtoCopyWith<$Res>? get geofenceAlert {
if (_self.geofenceAlert == null) {
return null;
}
return $AlertGeofenceDtoCopyWith<$Res>(_self.geofenceAlert!, (value) {
return $NotificationGeofenceDtoCopyWith<$Res>(_self.geofenceAlert!, (value) {
return _then(_self.copyWith(geofenceAlert: value));
});
}
}
/// Adds pattern-matching-related methods to [AlertItemDto].
extension AlertItemDtoPatterns on AlertItemDto {
/// Adds pattern-matching-related methods to [NotificationItemDto].
extension NotificationItemDtoPatterns on NotificationItemDto {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
@@ -450,7 +464,7 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String deviceIdentificator, String deviceName, String type, AlertGeofenceDto? geofenceAlert, String? delegationId, String? userId, int createdAt)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String deviceIdentificator, String deviceName, String type, NotificationGeofenceDto? geofenceAlert, String? delegationId, String? userId, int createdAt)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _AlertItemDto() when $default != null:
return $default(_that.id,_that.deviceIdentificator,_that.deviceName,_that.type,_that.geofenceAlert,_that.delegationId,_that.userId,_that.createdAt);case _:
@@ -471,7 +485,7 @@ return $default(_that.id,_that.deviceIdentificator,_that.deviceName,_that.type,_
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String deviceIdentificator, String deviceName, String type, AlertGeofenceDto? geofenceAlert, String? delegationId, String? userId, int createdAt) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String deviceIdentificator, String deviceName, String type, NotificationGeofenceDto? geofenceAlert, String? delegationId, String? userId, int createdAt) $default,) {final _that = this;
switch (_that) {
case _AlertItemDto():
return $default(_that.id,_that.deviceIdentificator,_that.deviceName,_that.type,_that.geofenceAlert,_that.delegationId,_that.userId,_that.createdAt);case _:
@@ -491,7 +505,7 @@ return $default(_that.id,_that.deviceIdentificator,_that.deviceName,_that.type,_
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String deviceIdentificator, String deviceName, String type, AlertGeofenceDto? geofenceAlert, String? delegationId, String? userId, int createdAt)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String deviceIdentificator, String deviceName, String type, NotificationGeofenceDto? geofenceAlert, String? delegationId, String? userId, int createdAt)? $default,) {final _that = this;
switch (_that) {
case _AlertItemDto() when $default != null:
return $default(_that.id,_that.deviceIdentificator,_that.deviceName,_that.type,_that.geofenceAlert,_that.delegationId,_that.userId,_that.createdAt);case _:
@@ -505,7 +519,7 @@ return $default(_that.id,_that.deviceIdentificator,_that.deviceName,_that.type,_
/// @nodoc
@JsonSerializable()
class _AlertItemDto implements AlertItemDto {
class _AlertItemDto implements NotificationItemDto {
const _AlertItemDto({required this.id, this.deviceIdentificator = '', this.deviceName = '', this.type = '', this.geofenceAlert, this.delegationId, this.userId, this.createdAt = 0});
factory _AlertItemDto.fromJson(Map<String, dynamic> json) => _$AlertItemDtoFromJson(json);
@@ -513,12 +527,12 @@ class _AlertItemDto implements AlertItemDto {
@override@JsonKey() final String deviceIdentificator;
@override@JsonKey() final String deviceName;
@override@JsonKey() final String type;
@override final AlertGeofenceDto? geofenceAlert;
@override final NotificationGeofenceDto? geofenceAlert;
@override final String? delegationId;
@override final String? userId;
@override@JsonKey() final int createdAt;
/// Create a copy of AlertItemDto
/// Create a copy of NotificationItemDto
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
@@ -540,22 +554,22 @@ int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,deviceName,ty
@override
String toString() {
return 'AlertItemDto(id: $id, deviceIdentificator: $deviceIdentificator, deviceName: $deviceName, type: $type, geofenceAlert: $geofenceAlert, delegationId: $delegationId, userId: $userId, createdAt: $createdAt)';
return 'NotificationItemDto(id: $id, deviceIdentificator: $deviceIdentificator, deviceName: $deviceName, type: $type, geofenceAlert: $geofenceAlert, delegationId: $delegationId, userId: $userId, createdAt: $createdAt)';
}
}
/// @nodoc
abstract mixin class _$AlertItemDtoCopyWith<$Res> implements $AlertItemDtoCopyWith<$Res> {
abstract mixin class _$AlertItemDtoCopyWith<$Res> implements $NotificationItemDtoCopyWith<$Res> {
factory _$AlertItemDtoCopyWith(_AlertItemDto value, $Res Function(_AlertItemDto) _then) = __$AlertItemDtoCopyWithImpl;
@override @useResult
$Res call({
String id, String deviceIdentificator, String deviceName, String type, AlertGeofenceDto? geofenceAlert, String? delegationId, String? userId, int createdAt
String id, String deviceIdentificator, String deviceName, String type, NotificationGeofenceDto? geofenceAlert, String? delegationId, String? userId, int createdAt
});
@override $AlertGeofenceDtoCopyWith<$Res>? get geofenceAlert;
@override $NotificationGeofenceDtoCopyWith<$Res>? get geofenceAlert;
}
/// @nodoc
@@ -566,7 +580,7 @@ class __$AlertItemDtoCopyWithImpl<$Res>
final _AlertItemDto _self;
final $Res Function(_AlertItemDto) _then;
/// Create a copy of AlertItemDto
/// Create a copy of NotificationItemDto
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceIdentificator = null,Object? deviceName = null,Object? type = null,Object? geofenceAlert = freezed,Object? delegationId = freezed,Object? userId = freezed,Object? createdAt = null,}) {
return _then(_AlertItemDto(
@@ -575,46 +589,53 @@ as String,deviceIdentificator: null == deviceIdentificator ? _self.deviceIdentif
as String,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable
as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as String,geofenceAlert: freezed == geofenceAlert ? _self.geofenceAlert : geofenceAlert // ignore: cast_nullable_to_non_nullable
as AlertGeofenceDto?,delegationId: freezed == delegationId ? _self.delegationId : delegationId // ignore: cast_nullable_to_non_nullable
as NotificationGeofenceDto?,delegationId: freezed == delegationId ? _self.delegationId : delegationId // ignore: cast_nullable_to_non_nullable
as String?,userId: freezed == userId ? _self.userId : userId // ignore: cast_nullable_to_non_nullable
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as int,
));
}
/// Create a copy of AlertItemDto
/// Create a copy of NotificationItemDto
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$AlertGeofenceDtoCopyWith<$Res>? get geofenceAlert {
$NotificationGeofenceDtoCopyWith<$Res>? get geofenceAlert {
if (_self.geofenceAlert == null) {
return null;
}
return $AlertGeofenceDtoCopyWith<$Res>(_self.geofenceAlert!, (value) {
return $NotificationGeofenceDtoCopyWith<$Res>(_self.geofenceAlert!, (value) {
return _then(_self.copyWith(geofenceAlert: value));
});
}
}
NotificationGeofenceDto _$NotificationGeofenceDtoFromJson(
Map<String, dynamic> json
) {
return _AlertGeofenceDto.fromJson(
json
);
}
/// @nodoc
mixin _$AlertGeofenceDto {
mixin _$NotificationGeofenceDto {
String get id; String get name;
/// Create a copy of AlertGeofenceDto
/// Create a copy of NotificationGeofenceDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AlertGeofenceDtoCopyWith<AlertGeofenceDto> get copyWith => _$AlertGeofenceDtoCopyWithImpl<AlertGeofenceDto>(this as AlertGeofenceDto, _$identity);
$NotificationGeofenceDtoCopyWith<NotificationGeofenceDto> get copyWith => _$NotificationGeofenceDtoCopyWithImpl<NotificationGeofenceDto>(this as NotificationGeofenceDto, _$identity);
/// Serializes this AlertGeofenceDto to a JSON map.
/// Serializes this NotificationGeofenceDto to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AlertGeofenceDto&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name));
return identical(this, other) || (other.runtimeType == runtimeType&&other is NotificationGeofenceDto&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -623,15 +644,15 @@ int get hashCode => Object.hash(runtimeType,id,name);
@override
String toString() {
return 'AlertGeofenceDto(id: $id, name: $name)';
return 'NotificationGeofenceDto(id: $id, name: $name)';
}
}
/// @nodoc
abstract mixin class $AlertGeofenceDtoCopyWith<$Res> {
factory $AlertGeofenceDtoCopyWith(AlertGeofenceDto value, $Res Function(AlertGeofenceDto) _then) = _$AlertGeofenceDtoCopyWithImpl;
abstract mixin class $NotificationGeofenceDtoCopyWith<$Res> {
factory $NotificationGeofenceDtoCopyWith(NotificationGeofenceDto value, $Res Function(NotificationGeofenceDto) _then) = _$NotificationGeofenceDtoCopyWithImpl;
@useResult
$Res call({
String id, String name
@@ -642,14 +663,14 @@ $Res call({
}
/// @nodoc
class _$AlertGeofenceDtoCopyWithImpl<$Res>
implements $AlertGeofenceDtoCopyWith<$Res> {
_$AlertGeofenceDtoCopyWithImpl(this._self, this._then);
class _$NotificationGeofenceDtoCopyWithImpl<$Res>
implements $NotificationGeofenceDtoCopyWith<$Res> {
_$NotificationGeofenceDtoCopyWithImpl(this._self, this._then);
final AlertGeofenceDto _self;
final $Res Function(AlertGeofenceDto) _then;
final NotificationGeofenceDto _self;
final $Res Function(NotificationGeofenceDto) _then;
/// Create a copy of AlertGeofenceDto
/// Create a copy of NotificationGeofenceDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,}) {
return _then(_self.copyWith(
@@ -662,8 +683,8 @@ as String,
}
/// Adds pattern-matching-related methods to [AlertGeofenceDto].
extension AlertGeofenceDtoPatterns on AlertGeofenceDto {
/// Adds pattern-matching-related methods to [NotificationGeofenceDto].
extension NotificationGeofenceDtoPatterns on NotificationGeofenceDto {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
@@ -795,14 +816,14 @@ return $default(_that.id,_that.name);case _:
/// @nodoc
@JsonSerializable()
class _AlertGeofenceDto implements AlertGeofenceDto {
class _AlertGeofenceDto implements NotificationGeofenceDto {
const _AlertGeofenceDto({required this.id, required this.name});
factory _AlertGeofenceDto.fromJson(Map<String, dynamic> json) => _$AlertGeofenceDtoFromJson(json);
@override final String id;
@override final String name;
/// Create a copy of AlertGeofenceDto
/// Create a copy of NotificationGeofenceDto
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
@@ -824,14 +845,14 @@ int get hashCode => Object.hash(runtimeType,id,name);
@override
String toString() {
return 'AlertGeofenceDto(id: $id, name: $name)';
return 'NotificationGeofenceDto(id: $id, name: $name)';
}
}
/// @nodoc
abstract mixin class _$AlertGeofenceDtoCopyWith<$Res> implements $AlertGeofenceDtoCopyWith<$Res> {
abstract mixin class _$AlertGeofenceDtoCopyWith<$Res> implements $NotificationGeofenceDtoCopyWith<$Res> {
factory _$AlertGeofenceDtoCopyWith(_AlertGeofenceDto value, $Res Function(_AlertGeofenceDto) _then) = __$AlertGeofenceDtoCopyWithImpl;
@override @useResult
$Res call({
@@ -850,7 +871,7 @@ class __$AlertGeofenceDtoCopyWithImpl<$Res>
final _AlertGeofenceDto _self;
final $Res Function(_AlertGeofenceDto) _then;
/// Create a copy of AlertGeofenceDto
/// Create a copy of NotificationGeofenceDto
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,}) {
return _then(_AlertGeofenceDto(

View File

@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'alerts_response_dto.dart';
part of 'notifications_response_dto.dart';
// **************************************************************************
// JsonSerializableGenerator
@@ -11,7 +11,9 @@ _AlertsResponseDto _$AlertsResponseDtoFromJson(Map<String, dynamic> json) =>
total: (json['total'] as num?)?.toInt() ?? 0,
items:
(json['items'] as List<dynamic>?)
?.map((e) => AlertItemDto.fromJson(e as Map<String, dynamic>))
?.map(
(e) => NotificationItemDto.fromJson(e as Map<String, dynamic>),
)
.toList() ??
const [],
page: (json['page'] as num?)?.toInt() ?? 1,
@@ -34,7 +36,7 @@ _AlertItemDto _$AlertItemDtoFromJson(Map<String, dynamic> json) =>
type: json['type'] as String? ?? '',
geofenceAlert: json['geofenceAlert'] == null
? null
: AlertGeofenceDto.fromJson(
: NotificationGeofenceDto.fromJson(
json['geofenceAlert'] as Map<String, dynamic>,
),
delegationId: json['delegationId'] as String?,

View File

@@ -0,0 +1,30 @@
import 'package:dio/dio.dart';
import 'package:sf_infrastructure/sf_infrastructure.dart';
import '../../domain/entities/notification_entity.dart';
import '../../domain/repositories/notifications_repository.dart';
import '../datasource/notifications_remote_datasource.dart';
class NotificationsRepositoryImpl implements NotificationsRepository {
NotificationsRepositoryImpl(this._datasource);
final NotificationsRemoteDatasource _datasource;
@override
Future<(List<NotificationEntity>, int totalPages)> getNotifications({
required int page,
int pageSize = 20,
String? type,
}) async {
try {
return await _datasource.getNotifications(
page: page,
pageSize: pageSize,
type: type,
);
} on DioException catch (error) {
if (error.response?.statusCode == 404) return (<NotificationEntity>[], 1);
throw mapDioError(error, defaultMessage: 'Error getting alerts');
}
}
}

View File

@@ -1,10 +1,10 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'alert_entity.freezed.dart';
part 'notification_entity.freezed.dart';
@freezed
abstract class AlertEntity with _$AlertEntity {
const factory AlertEntity({
abstract class NotificationEntity with _$NotificationEntity {
const factory NotificationEntity({
required String id,
required String deviceIdentificator,
required String deviceName,

View File

@@ -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 'alert_entity.dart';
part of 'notification_entity.dart';
// **************************************************************************
// FreezedGenerator
@@ -12,20 +12,20 @@ part of 'alert_entity.dart';
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$AlertEntity {
mixin _$NotificationEntity {
String get id; String get deviceIdentificator; String get deviceName; String get type; GeofenceAlertEntity? get geofenceAlert; String? get delegationId; String? get userId; int get createdAt;
/// Create a copy of AlertEntity
/// Create a copy of NotificationEntity
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$AlertEntityCopyWith<AlertEntity> get copyWith => _$AlertEntityCopyWithImpl<AlertEntity>(this as AlertEntity, _$identity);
$NotificationEntityCopyWith<NotificationEntity> get copyWith => _$NotificationEntityCopyWithImpl<NotificationEntity>(this as NotificationEntity, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AlertEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.type, type) || other.type == type)&&(identical(other.geofenceAlert, geofenceAlert) || other.geofenceAlert == geofenceAlert)&&(identical(other.delegationId, delegationId) || other.delegationId == delegationId)&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt));
return identical(this, other) || (other.runtimeType == runtimeType&&other is NotificationEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.type, type) || other.type == type)&&(identical(other.geofenceAlert, geofenceAlert) || other.geofenceAlert == geofenceAlert)&&(identical(other.delegationId, delegationId) || other.delegationId == delegationId)&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt));
}
@@ -34,15 +34,15 @@ int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,deviceName,ty
@override
String toString() {
return 'AlertEntity(id: $id, deviceIdentificator: $deviceIdentificator, deviceName: $deviceName, type: $type, geofenceAlert: $geofenceAlert, delegationId: $delegationId, userId: $userId, createdAt: $createdAt)';
return 'NotificationEntity(id: $id, deviceIdentificator: $deviceIdentificator, deviceName: $deviceName, type: $type, geofenceAlert: $geofenceAlert, delegationId: $delegationId, userId: $userId, createdAt: $createdAt)';
}
}
/// @nodoc
abstract mixin class $AlertEntityCopyWith<$Res> {
factory $AlertEntityCopyWith(AlertEntity value, $Res Function(AlertEntity) _then) = _$AlertEntityCopyWithImpl;
abstract mixin class $NotificationEntityCopyWith<$Res> {
factory $NotificationEntityCopyWith(NotificationEntity value, $Res Function(NotificationEntity) _then) = _$NotificationEntityCopyWithImpl;
@useResult
$Res call({
String id, String deviceIdentificator, String deviceName, String type, GeofenceAlertEntity? geofenceAlert, String? delegationId, String? userId, int createdAt
@@ -53,14 +53,14 @@ $GeofenceAlertEntityCopyWith<$Res>? get geofenceAlert;
}
/// @nodoc
class _$AlertEntityCopyWithImpl<$Res>
implements $AlertEntityCopyWith<$Res> {
_$AlertEntityCopyWithImpl(this._self, this._then);
class _$NotificationEntityCopyWithImpl<$Res>
implements $NotificationEntityCopyWith<$Res> {
_$NotificationEntityCopyWithImpl(this._self, this._then);
final AlertEntity _self;
final $Res Function(AlertEntity) _then;
final NotificationEntity _self;
final $Res Function(NotificationEntity) _then;
/// Create a copy of AlertEntity
/// Create a copy of NotificationEntity
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceIdentificator = null,Object? deviceName = null,Object? type = null,Object? geofenceAlert = freezed,Object? delegationId = freezed,Object? userId = freezed,Object? createdAt = null,}) {
return _then(_self.copyWith(
@@ -75,7 +75,7 @@ as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore:
as int,
));
}
/// Create a copy of AlertEntity
/// Create a copy of NotificationEntity
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
@@ -91,8 +91,8 @@ $GeofenceAlertEntityCopyWith<$Res>? get geofenceAlert {
}
/// Adds pattern-matching-related methods to [AlertEntity].
extension AlertEntityPatterns on AlertEntity {
/// Adds pattern-matching-related methods to [NotificationEntity].
extension NotificationEntityPatterns on NotificationEntity {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
@@ -224,7 +224,7 @@ return $default(_that.id,_that.deviceIdentificator,_that.deviceName,_that.type,_
/// @nodoc
class _AlertEntity implements AlertEntity {
class _AlertEntity implements NotificationEntity {
const _AlertEntity({required this.id, required this.deviceIdentificator, required this.deviceName, required this.type, this.geofenceAlert, this.delegationId, this.userId, required this.createdAt});
@@ -237,7 +237,7 @@ class _AlertEntity implements AlertEntity {
@override final String? userId;
@override final int createdAt;
/// Create a copy of AlertEntity
/// Create a copy of NotificationEntity
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
@@ -256,14 +256,14 @@ int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,deviceName,ty
@override
String toString() {
return 'AlertEntity(id: $id, deviceIdentificator: $deviceIdentificator, deviceName: $deviceName, type: $type, geofenceAlert: $geofenceAlert, delegationId: $delegationId, userId: $userId, createdAt: $createdAt)';
return 'NotificationEntity(id: $id, deviceIdentificator: $deviceIdentificator, deviceName: $deviceName, type: $type, geofenceAlert: $geofenceAlert, delegationId: $delegationId, userId: $userId, createdAt: $createdAt)';
}
}
/// @nodoc
abstract mixin class _$AlertEntityCopyWith<$Res> implements $AlertEntityCopyWith<$Res> {
abstract mixin class _$AlertEntityCopyWith<$Res> implements $NotificationEntityCopyWith<$Res> {
factory _$AlertEntityCopyWith(_AlertEntity value, $Res Function(_AlertEntity) _then) = __$AlertEntityCopyWithImpl;
@override @useResult
$Res call({
@@ -282,7 +282,7 @@ class __$AlertEntityCopyWithImpl<$Res>
final _AlertEntity _self;
final $Res Function(_AlertEntity) _then;
/// Create a copy of AlertEntity
/// Create a copy of NotificationEntity
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceIdentificator = null,Object? deviceName = null,Object? type = null,Object? geofenceAlert = freezed,Object? delegationId = freezed,Object? userId = freezed,Object? createdAt = null,}) {
return _then(_AlertEntity(
@@ -298,7 +298,7 @@ as int,
));
}
/// Create a copy of AlertEntity
/// Create a copy of NotificationEntity
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')

View File

@@ -0,0 +1,9 @@
import '../entities/notification_entity.dart';
abstract class NotificationsRepository {
Future<(List<NotificationEntity>, int totalPages)> getNotifications({
required int page,
int pageSize,
String? type,
});
}

View File

@@ -0,0 +1,16 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get_it/get_it.dart';
import 'package:sf_infrastructure/sf_infrastructure.dart';
import '../data/datasource/notifications_remote_datasource.dart';
import '../data/datasource/notifications_remote_datasource_impl.dart';
import '../data/repositories/notifications_repository_impl.dart';
import '../domain/repositories/notifications_repository.dart';
final notificationsRemoteDatasourceProvider = Provider<NotificationsRemoteDatasource>(
(_) => NotificationsRemoteDatasourceImpl(GetIt.I<SaveFamilyRepository>()),
);
final notificationsRepositoryProvider = Provider<NotificationsRepository>(
(ref) => NotificationsRepositoryImpl(ref.read(notificationsRemoteDatasourceProvider)),
);

View File

@@ -1,7 +1,7 @@
import 'package:control_panel/src/core/domain/entities/alert_entity.dart';
import 'package:control_panel/src/features/notifications/presentation/providers/notifications_feed_provider.dart';
import 'package:control_panel/src/features/notifications/presentation/providers/notifications_filter_provider.dart';
import 'package:control_panel/src/features/notifications/presentation/widgets/notification_card.dart';
import 'package:settings/src/core/domain/entities/notification_entity.dart';
import 'package:settings/src/features/notifications/presentation/providers/notifications_feed_provider.dart';
import 'package:settings/src/features/notifications/presentation/providers/notifications_filter_provider.dart';
import 'package:settings/src/features/notifications/presentation/widgets/notification_card.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:legacy_theme/legacy_theme.dart';
@@ -231,7 +231,7 @@ class _FilteredNotificationsScreen extends ConsumerWidget {
}
class _NotificationsList extends ConsumerStatefulWidget {
final List<AlertEntity> notifications;
final List<NotificationEntity> notifications;
final bool isLoadingMore;
const _NotificationsList({

View File

@@ -1,8 +1,8 @@
import 'dart:async';
import 'package:control_panel/src/core/domain/entities/alert_entity.dart';
import 'package:control_panel/src/core/providers/alerts_repository_provider.dart';
import 'package:control_panel/src/features/notifications/presentation/providers/notifications_filter_provider.dart';
import 'package:settings/src/core/domain/entities/notification_entity.dart';
import 'package:settings/src/core/providers/notifications_repository_provider.dart';
import 'package:settings/src/features/notifications/presentation/providers/notifications_filter_provider.dart';
import 'package:legacy_device_state/legacy_device_state.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:sf_infrastructure/sf_infrastructure.dart';
@@ -19,13 +19,13 @@ class NotificationsFeedState {
this.isLoadingMore = false,
});
final List<AlertEntity> notifications;
final List<NotificationEntity> notifications;
final int currentPage;
final bool hasMore;
final bool isLoadingMore;
NotificationsFeedState copyWith({
List<AlertEntity>? notifications,
List<NotificationEntity>? notifications,
int? currentPage,
bool? hasMore,
bool? isLoadingMore,
@@ -53,8 +53,8 @@ class NotificationsFeed extends _$NotificationsFeed {
ref.onDispose(() => _subscription?.cancel());
final (notifications, totalPages) = await ref
.read(alertsRepositoryProvider)
.getAlerts(page: 1, pageSize: _pageSize, type: filter);
.read(notificationsRepositoryProvider)
.getNotifications(page: 1, pageSize: _pageSize, type: filter);
return NotificationsFeedState(
notifications: notifications,
@@ -72,7 +72,7 @@ class NotificationsFeed extends _$NotificationsFeed {
final filter = ref.read(notificationsFilterProvider);
if (filter != null && filter != event.type) return;
final newNotification = AlertEntity(
final newNotification = NotificationEntity(
id: '',
deviceIdentificator: event.deviceIdentificator,
deviceName: '',
@@ -98,8 +98,8 @@ class NotificationsFeed extends _$NotificationsFeed {
final filter = ref.read(notificationsFilterProvider);
final nextPage = current.currentPage + 1;
final (notifications, totalPages) = await ref
.read(alertsRepositoryProvider)
.getAlerts(page: nextPage, pageSize: _pageSize, type: filter);
.read(notificationsRepositoryProvider)
.getNotifications(page: nextPage, pageSize: _pageSize, type: filter);
state = AsyncData(
current.copyWith(

View File

@@ -33,7 +33,7 @@ final class NotificationsFeedProvider
NotificationsFeed create() => NotificationsFeed();
}
String _$notificationsFeedHash() => r'bb7878198548338c17db4b9ac51e3f88a24115d6';
String _$notificationsFeedHash() => r'907cd9e444a625ff38206809797a006321e1ed99';
abstract class _$NotificationsFeed
extends $AsyncNotifier<NotificationsFeedState> {

View File

@@ -4,10 +4,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:utils/utils.dart';
import '../../../../core/domain/entities/alert_entity.dart';
import '../../../../core/domain/entities/notification_entity.dart';
class NotificationCard extends ConsumerWidget {
final AlertEntity notification;
final NotificationEntity notification;
const NotificationCard({super.key, required this.notification});

View File

@@ -1,10 +1,10 @@
import 'dart:async';
import 'package:control_panel/src/core/domain/entities/alert_entity.dart';
import 'package:control_panel/src/core/domain/repositories/alerts_repository.dart';
import 'package:control_panel/src/core/providers/alerts_repository_provider.dart';
import 'package:control_panel/src/features/notifications/presentation/providers/notifications_feed_provider.dart';
import 'package:control_panel/src/features/notifications/presentation/providers/notifications_filter_provider.dart';
import 'package:settings/src/core/domain/entities/notification_entity.dart';
import 'package:settings/src/core/domain/repositories/notifications_repository.dart';
import 'package:settings/src/core/providers/notifications_repository_provider.dart';
import 'package:settings/src/features/notifications/presentation/providers/notifications_feed_provider.dart';
import 'package:settings/src/features/notifications/presentation/providers/notifications_filter_provider.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:legacy_device_state/legacy_device_state.dart';
@@ -12,7 +12,7 @@ import 'package:mocktail/mocktail.dart';
import 'package:sf_infrastructure/sf_infrastructure.dart';
import 'package:sf_shared/testing.dart';
class MockAlertsRepository extends Mock implements AlertsRepository {}
class MockAlertsRepository extends Mock implements NotificationsRepository {}
class FakeWebSocketService implements WebSocketService {
final _controller = StreamController<WebSocketEvent>.broadcast();
@@ -26,14 +26,14 @@ class FakeWebSocketService implements WebSocketService {
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
final _alert1 = AlertEntity(
final _alert1 = NotificationEntity(
id: '1',
deviceIdentificator: 'd1',
deviceName: 'Watch',
type: 'sos',
createdAt: 1,
);
final _alert2 = AlertEntity(
final _alert2 = NotificationEntity(
id: '2',
deviceIdentificator: 'd1',
deviceName: 'Watch',
@@ -43,12 +43,12 @@ final _alert2 = AlertEntity(
void main() {
ProviderContainer buildContainer({
required AlertsRepository repo,
required NotificationsRepository repo,
required FakeWebSocketService ws,
}) {
return makeContainer(
overrides: [
alertsRepositoryProvider.overrideWithValue(repo),
notificationsRepositoryProvider.overrideWithValue(repo),
webSocketServiceProvider.overrideWithValue(ws),
],
);
@@ -59,7 +59,7 @@ void main() {
final repo = MockAlertsRepository();
final ws = FakeWebSocketService();
when(
() => repo.getAlerts(
() => repo.getNotifications(
page: any(named: 'page'),
pageSize: any(named: 'pageSize'),
type: any(named: 'type'),
@@ -76,7 +76,7 @@ void main() {
expect(state.notifications, [_alert1, _alert2]);
expect(state.currentPage, 1);
expect(state.hasMore, isTrue);
verify(() => repo.getAlerts(page: 1, pageSize: 20, type: null))
verify(() => repo.getNotifications(page: 1, pageSize: 20, type: null))
.called(1);
});
@@ -84,7 +84,7 @@ void main() {
final repo = MockAlertsRepository();
final ws = FakeWebSocketService();
when(
() => repo.getAlerts(
() => repo.getNotifications(
page: any(named: 'page'),
pageSize: any(named: 'pageSize'),
type: any(named: 'type'),
@@ -100,7 +100,7 @@ void main() {
container.read(notificationsFilterProvider.notifier).select('sos');
await container.read(notificationsFeedProvider.future);
verify(() => repo.getAlerts(page: 1, pageSize: 20, type: 'sos'))
verify(() => repo.getNotifications(page: 1, pageSize: 20, type: 'sos'))
.called(1);
});
});
@@ -110,14 +110,14 @@ void main() {
final repo = MockAlertsRepository();
final ws = FakeWebSocketService();
when(
() => repo.getAlerts(
() => repo.getNotifications(
page: 1,
pageSize: any(named: 'pageSize'),
type: any(named: 'type'),
),
).thenAnswer((_) async => ([_alert1], 2));
when(
() => repo.getAlerts(
() => repo.getNotifications(
page: 2,
pageSize: any(named: 'pageSize'),
type: any(named: 'type'),
@@ -141,7 +141,7 @@ void main() {
final repo = MockAlertsRepository();
final ws = FakeWebSocketService();
when(
() => repo.getAlerts(
() => repo.getNotifications(
page: any(named: 'page'),
pageSize: any(named: 'pageSize'),
type: any(named: 'type'),
@@ -155,9 +155,9 @@ void main() {
await container.read(notificationsFeedProvider.future);
await container.read(notificationsFeedProvider.notifier).loadMore();
verify(() => repo.getAlerts(page: 1, pageSize: 20, type: null))
verify(() => repo.getNotifications(page: 1, pageSize: 20, type: null))
.called(1);
verifyNever(() => repo.getAlerts(page: 2, pageSize: 20, type: null));
verifyNever(() => repo.getNotifications(page: 2, pageSize: 20, type: null));
});
});
@@ -166,7 +166,7 @@ void main() {
final repo = MockAlertsRepository();
final ws = FakeWebSocketService();
when(
() => repo.getAlerts(
() => repo.getNotifications(
page: any(named: 'page'),
pageSize: any(named: 'pageSize'),
type: any(named: 'type'),
@@ -195,7 +195,7 @@ void main() {
final repo = MockAlertsRepository();
final ws = FakeWebSocketService();
when(
() => repo.getAlerts(
() => repo.getNotifications(
page: any(named: 'page'),
pageSize: any(named: 'pageSize'),
type: any(named: 'type'),