Compare commits
1 Commits
feature/so
...
feature/he
| Author | SHA1 | Date | |
|---|---|---|---|
| 94c042d403 |
@@ -26,7 +26,7 @@ late final GoRouter appRouter;
|
||||
void configureAppRouter() {
|
||||
appRouter = GoRouter(
|
||||
navigatorKey: rootNavigatorKey,
|
||||
initialLocation: AppRoutes.controlPanel,
|
||||
initialLocation: AppRoutes.splash,
|
||||
debugLogDiagnostics: true,
|
||||
routes: [
|
||||
GoRoute(
|
||||
|
||||
@@ -130,6 +130,31 @@ class _HealthScreenState extends ConsumerState<HealthScreen>
|
||||
),
|
||||
],
|
||||
),
|
||||
footer: _SaveSection()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SaveSection extends ConsumerWidget{
|
||||
|
||||
const _SaveSection();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final theme = ref.read(themePortProvider);
|
||||
|
||||
final vm = ref.read(healthViewModelProvider.notifier);
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 10),
|
||||
child:
|
||||
PrimaryButton(
|
||||
onPressed: () async {
|
||||
await vm.measure();
|
||||
},
|
||||
text: context.translate(I18n.measure),
|
||||
color: theme.getColorFor(ThemeCode.legacyPrimary)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -14,12 +14,14 @@ final healthViewModelProvider =
|
||||
|
||||
class HealthViewModel extends Notifier<HealthViewState> {
|
||||
late final HealthRepository _repository;
|
||||
late final CommandsRepository _commandsRepository;
|
||||
|
||||
static const int _historyPageSize = 20;
|
||||
|
||||
@override
|
||||
HealthViewState build() {
|
||||
_repository = ref.read(healthRepositoryProvider);
|
||||
_commandsRepository = ref.read(commandsRepositoryProvider);
|
||||
_init();
|
||||
return const HealthViewState();
|
||||
}
|
||||
@@ -243,4 +245,32 @@ class HealthViewModel extends Notifier<HealthViewState> {
|
||||
final msg = e.toString();
|
||||
return msg.startsWith('Exception: ') ? msg.substring(11) : msg;
|
||||
}
|
||||
|
||||
Future<void> measure() async {
|
||||
|
||||
try {
|
||||
state = state.copyWith(
|
||||
isLoading: true,
|
||||
);
|
||||
|
||||
final device = ref.read(selectedDeviceProvider);
|
||||
if (device == null) return;
|
||||
|
||||
final request = SendCommandRequestModel(
|
||||
device: device.identificator,
|
||||
command: DeviceCommand.requestHeartRate,
|
||||
);
|
||||
|
||||
await _commandsRepository.send(request: request);
|
||||
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
);
|
||||
} catch (e) {
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: e.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
abstract class SetSoundUseCase {
|
||||
Future<void> setSound({required String deviceId});
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import 'package:settings/src/core/domain/repositories/settings_repository.dart';
|
||||
|
||||
import 'set_sound_use_case.dart';
|
||||
|
||||
|
||||
class SetSoundUseCaseImpl implements SetSoundUseCase {
|
||||
SetSoundUseCaseImpl(this._repository);
|
||||
|
||||
final SettingsRepository _repository;
|
||||
|
||||
@override
|
||||
Future<void> setSound({required String deviceId}) async {
|
||||
return;
|
||||
// return _repository.setSound(deviceId: deviceId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:settings/src/core/providers/settings_repository_provider.dart';
|
||||
|
||||
import '../../domain/set_sound_use_case.dart';
|
||||
import '../../domain/set_sound_use_case_impl.dart';
|
||||
|
||||
final setSoundUseCaseProvider = Provider.autoDispose<SetSoundUseCase>((ref) {
|
||||
final settingsRepository = ref.read(settingsRepositoryProvider);
|
||||
return SetSoundUseCaseImpl(settingsRepository);
|
||||
});
|
||||
@@ -20,26 +20,6 @@ class SoundScreen extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final theme = ref.read(themePortProvider);
|
||||
|
||||
ref.listen(soundViewModelProvider.select((s) => s.errorMessage), (
|
||||
_,
|
||||
errorMessage,
|
||||
) {
|
||||
if (errorMessage.isNotEmpty) {
|
||||
showTopSnackbar(
|
||||
context,
|
||||
message: errorMessage,
|
||||
type: MessageType.error,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
ref.listen(soundViewModelProvider.select((s) => s.isComplete), (
|
||||
_,
|
||||
isComplete,
|
||||
) {
|
||||
if (isComplete) Navigator.pop(context);
|
||||
});
|
||||
|
||||
return LegacyPageLayout(
|
||||
theme: theme,
|
||||
title: context.translate(I18n.sound),
|
||||
@@ -81,15 +61,15 @@ class _OptionsSection extends ConsumerWidget {
|
||||
_SectionButton(
|
||||
title: context.translate(I18n.soundAndVibration),
|
||||
icon: Icons.volume_up_outlined,
|
||||
active: soundOption == 'VIBRATION_AND_RINGING',
|
||||
onPressed: () {vm.setSoundOption('VIBRATION_AND_RINGING');},
|
||||
active: soundOption == 'SOUND_AND_VIBRATION',
|
||||
onPressed: () {vm.setSoundOption('SOUND_AND_VIBRATION');},
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
_SectionButton(
|
||||
title: context.translate(I18n.soundOnly),
|
||||
icon: Icons.volume_up_outlined,
|
||||
active: soundOption == 'RINGING',
|
||||
onPressed: () {vm.setSoundOption('RINGING');},
|
||||
active: soundOption == 'SOUND',
|
||||
onPressed: () {vm.setSoundOption('SOUND');},
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
_SectionButton(
|
||||
@@ -102,8 +82,8 @@ class _OptionsSection extends ConsumerWidget {
|
||||
_SectionButton(
|
||||
title: context.translate(I18n.silent),
|
||||
icon: Icons.volume_mute_outlined,
|
||||
active: soundOption == 'SILENCE',
|
||||
onPressed: () {vm.setSoundOption('SILENCE');},
|
||||
active: soundOption == 'SILENT',
|
||||
onPressed: () {vm.setSoundOption('SILENT');},
|
||||
),
|
||||
]
|
||||
),
|
||||
@@ -172,7 +152,7 @@ class _SaveSection extends ConsumerWidget {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
child: PrimaryButton(
|
||||
onPressed: () {vm.submit();},
|
||||
onPressed: vm.submit,
|
||||
text: context.translate(I18n.save),
|
||||
color: theme.getColorFor(ThemeCode.legacyPrimary)
|
||||
),
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:legacy_shared/legacy_shared.dart';
|
||||
import 'package:sf_shared/sf_shared.dart';
|
||||
|
||||
import '../../domain/set_sound_use_case.dart';
|
||||
import '../providers/set_sound_use_case_provider.dart';
|
||||
import 'sound_view_state.dart';
|
||||
|
||||
final soundViewModelProvider =
|
||||
@@ -9,11 +12,11 @@ NotifierProvider.autoDispose<SoundViewModel, SoundViewState>(
|
||||
);
|
||||
|
||||
class SoundViewModel extends Notifier<SoundViewState> {
|
||||
late final CommandsRepository _commandsRepository;
|
||||
late final SetSoundUseCase _setSoundUseCase;
|
||||
|
||||
@override
|
||||
SoundViewState build() {
|
||||
_commandsRepository = ref.read(commandsRepositoryProvider);
|
||||
_setSoundUseCase = ref.read(setSoundUseCaseProvider);
|
||||
|
||||
Future.microtask(() => load());
|
||||
|
||||
@@ -22,12 +25,16 @@ class SoundViewModel extends Notifier<SoundViewState> {
|
||||
|
||||
Future<void> load() async {
|
||||
final device = ref.read(selectedDeviceProvider);
|
||||
if (device == null) return;
|
||||
setDevice(device!);
|
||||
state = state.copyWith(
|
||||
soundOption: 'SOUND_AND_VIBRATION',
|
||||
isLoading: false,
|
||||
);
|
||||
}
|
||||
|
||||
void setDevice(DeviceEntity device) {
|
||||
state = state.copyWith(
|
||||
deviceId: device.identificator,
|
||||
soundOption: device.settings['soundMode'] ?? 'VIBRATION',
|
||||
isLoading: false,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,20 +50,8 @@ class SoundViewModel extends Notifier<SoundViewState> {
|
||||
try {
|
||||
state = state.copyWith(
|
||||
isLoading: true,
|
||||
isComplete: false,
|
||||
);
|
||||
|
||||
final request = SendCommandRequestModel(
|
||||
device: state.deviceId,
|
||||
command: DeviceCommand.setSoundMode,
|
||||
data: {'soundMode': state.soundOption}
|
||||
);
|
||||
await _commandsRepository.send(request: request);
|
||||
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
isComplete: true,
|
||||
);
|
||||
_setSoundUseCase.setSound(deviceId: state.deviceId);
|
||||
} catch (e) {
|
||||
state = state.copyWith(
|
||||
isLoading: false,
|
||||
|
||||
@@ -9,7 +9,6 @@ abstract class SoundViewState with _$SoundViewState {
|
||||
@Default('') String deviceId,
|
||||
String? soundOption,
|
||||
@Default(true) bool isLoading,
|
||||
@Default(false) bool isComplete,
|
||||
@Default('') String errorMessage,
|
||||
}) = _SoundViewState;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$SoundViewState {
|
||||
|
||||
String get deviceId; String? get soundOption; bool get isLoading; bool get isComplete; String get errorMessage;
|
||||
String get deviceId; String? get soundOption; bool get isLoading; String get errorMessage;
|
||||
/// Create a copy of SoundViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -25,16 +25,16 @@ $SoundViewStateCopyWith<SoundViewState> get copyWith => _$SoundViewStateCopyWith
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SoundViewState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.soundOption, soundOption) || other.soundOption == soundOption)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isComplete, isComplete) || other.isComplete == isComplete)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SoundViewState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.soundOption, soundOption) || other.soundOption == soundOption)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,deviceId,soundOption,isLoading,isComplete,errorMessage);
|
||||
int get hashCode => Object.hash(runtimeType,deviceId,soundOption,isLoading,errorMessage);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SoundViewState(deviceId: $deviceId, soundOption: $soundOption, isLoading: $isLoading, isComplete: $isComplete, errorMessage: $errorMessage)';
|
||||
return 'SoundViewState(deviceId: $deviceId, soundOption: $soundOption, isLoading: $isLoading, errorMessage: $errorMessage)';
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ abstract mixin class $SoundViewStateCopyWith<$Res> {
|
||||
factory $SoundViewStateCopyWith(SoundViewState value, $Res Function(SoundViewState) _then) = _$SoundViewStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String deviceId, String? soundOption, bool isLoading, bool isComplete, String errorMessage
|
||||
String deviceId, String? soundOption, bool isLoading, String errorMessage
|
||||
});
|
||||
|
||||
|
||||
@@ -62,12 +62,11 @@ class _$SoundViewStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SoundViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? deviceId = null,Object? soundOption = freezed,Object? isLoading = null,Object? isComplete = null,Object? errorMessage = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? deviceId = null,Object? soundOption = freezed,Object? isLoading = null,Object? errorMessage = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
||||
as String,soundOption: freezed == soundOption ? _self.soundOption : soundOption // ignore: cast_nullable_to_non_nullable
|
||||
as String?,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isComplete: null == isComplete ? _self.isComplete : isComplete // ignore: cast_nullable_to_non_nullable
|
||||
as bool,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
@@ -154,10 +153,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String deviceId, String? soundOption, bool isLoading, bool isComplete, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String deviceId, String? soundOption, bool isLoading, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SoundViewState() when $default != null:
|
||||
return $default(_that.deviceId,_that.soundOption,_that.isLoading,_that.isComplete,_that.errorMessage);case _:
|
||||
return $default(_that.deviceId,_that.soundOption,_that.isLoading,_that.errorMessage);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -175,10 +174,10 @@ return $default(_that.deviceId,_that.soundOption,_that.isLoading,_that.isComplet
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String deviceId, String? soundOption, bool isLoading, bool isComplete, String errorMessage) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String deviceId, String? soundOption, bool isLoading, String errorMessage) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SoundViewState():
|
||||
return $default(_that.deviceId,_that.soundOption,_that.isLoading,_that.isComplete,_that.errorMessage);case _:
|
||||
return $default(_that.deviceId,_that.soundOption,_that.isLoading,_that.errorMessage);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -195,10 +194,10 @@ return $default(_that.deviceId,_that.soundOption,_that.isLoading,_that.isComplet
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String deviceId, String? soundOption, bool isLoading, bool isComplete, String errorMessage)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String deviceId, String? soundOption, bool isLoading, String errorMessage)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SoundViewState() when $default != null:
|
||||
return $default(_that.deviceId,_that.soundOption,_that.isLoading,_that.isComplete,_that.errorMessage);case _:
|
||||
return $default(_that.deviceId,_that.soundOption,_that.isLoading,_that.errorMessage);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -210,13 +209,12 @@ return $default(_that.deviceId,_that.soundOption,_that.isLoading,_that.isComplet
|
||||
|
||||
|
||||
class _SoundViewState implements SoundViewState {
|
||||
const _SoundViewState({this.deviceId = '', this.soundOption, this.isLoading = true, this.isComplete = false, this.errorMessage = ''});
|
||||
const _SoundViewState({this.deviceId = '', this.soundOption, this.isLoading = true, this.errorMessage = ''});
|
||||
|
||||
|
||||
@override@JsonKey() final String deviceId;
|
||||
@override final String? soundOption;
|
||||
@override@JsonKey() final bool isLoading;
|
||||
@override@JsonKey() final bool isComplete;
|
||||
@override@JsonKey() final String errorMessage;
|
||||
|
||||
/// Create a copy of SoundViewState
|
||||
@@ -229,16 +227,16 @@ _$SoundViewStateCopyWith<_SoundViewState> get copyWith => __$SoundViewStateCopyW
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SoundViewState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.soundOption, soundOption) || other.soundOption == soundOption)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isComplete, isComplete) || other.isComplete == isComplete)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SoundViewState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.soundOption, soundOption) || other.soundOption == soundOption)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,deviceId,soundOption,isLoading,isComplete,errorMessage);
|
||||
int get hashCode => Object.hash(runtimeType,deviceId,soundOption,isLoading,errorMessage);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SoundViewState(deviceId: $deviceId, soundOption: $soundOption, isLoading: $isLoading, isComplete: $isComplete, errorMessage: $errorMessage)';
|
||||
return 'SoundViewState(deviceId: $deviceId, soundOption: $soundOption, isLoading: $isLoading, errorMessage: $errorMessage)';
|
||||
}
|
||||
|
||||
|
||||
@@ -249,7 +247,7 @@ abstract mixin class _$SoundViewStateCopyWith<$Res> implements $SoundViewStateCo
|
||||
factory _$SoundViewStateCopyWith(_SoundViewState value, $Res Function(_SoundViewState) _then) = __$SoundViewStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String deviceId, String? soundOption, bool isLoading, bool isComplete, String errorMessage
|
||||
String deviceId, String? soundOption, bool isLoading, String errorMessage
|
||||
});
|
||||
|
||||
|
||||
@@ -266,12 +264,11 @@ class __$SoundViewStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SoundViewState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? deviceId = null,Object? soundOption = freezed,Object? isLoading = null,Object? isComplete = null,Object? errorMessage = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? deviceId = null,Object? soundOption = freezed,Object? isLoading = null,Object? errorMessage = null,}) {
|
||||
return _then(_SoundViewState(
|
||||
deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
||||
as String,soundOption: freezed == soundOption ? _self.soundOption : soundOption // ignore: cast_nullable_to_non_nullable
|
||||
as String?,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isComplete: null == isComplete ? _self.isComplete : isComplete // ignore: cast_nullable_to_non_nullable
|
||||
as bool,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
|
||||
@@ -8,14 +8,16 @@ enum DeviceCommand {
|
||||
factory,
|
||||
@JsonValue('FIND_DEVICE')
|
||||
findDevice,
|
||||
@JsonValue('REQUEST_HEART_RATE')
|
||||
requestHeartRate,
|
||||
@JsonValue('RESTART')
|
||||
restart,
|
||||
@JsonValue('REWARDS')
|
||||
rewards,
|
||||
@JsonValue('SHUTDOWN')
|
||||
shutdown,
|
||||
@JsonValue('SET_SOUND_MODE')
|
||||
setSoundMode,
|
||||
@JsonValue('SOUND')
|
||||
sound,
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
@@ -25,8 +25,9 @@ Map<String, dynamic> _$SendCommandRequestModelToJson(
|
||||
const _$DeviceCommandEnumMap = {
|
||||
DeviceCommand.factory: 'FACTORY',
|
||||
DeviceCommand.findDevice: 'FIND_DEVICE',
|
||||
DeviceCommand.requestHeartRate: 'REQUEST_HEART_RATE',
|
||||
DeviceCommand.restart: 'RESTART',
|
||||
DeviceCommand.rewards: 'REWARDS',
|
||||
DeviceCommand.shutdown: 'SHUTDOWN',
|
||||
DeviceCommand.setSoundMode: 'SET_SOUND_MODE',
|
||||
DeviceCommand.sound: 'SOUND',
|
||||
};
|
||||
|
||||
@@ -744,5 +744,6 @@
|
||||
"vibrationOnly": "Vibration only",
|
||||
"silent": "Silent",
|
||||
"syncClockMessage": "Synchronize the device clock with the current time",
|
||||
"locationWifiNetworksOptional": "WiFi networks (optional)"
|
||||
"locationWifiNetworksOptional": "WiFi networks (optional)",
|
||||
"measure": "Measure"
|
||||
}
|
||||
|
||||
@@ -742,5 +742,6 @@
|
||||
"vibrationOnly": "Solo vibración",
|
||||
"silent": "Silencio",
|
||||
"syncClockMessage": "Sincroniza el reloj del dispositivo con la hora actual",
|
||||
"locationWifiNetworksOptional": "Redes WiFi (opcional)"
|
||||
"locationWifiNetworksOptional": "Redes WiFi (opcional)",
|
||||
"measure": "Medir"
|
||||
}
|
||||
|
||||
@@ -749,4 +749,5 @@ class I18n {
|
||||
static const String wifiSsid = 'wifiSsid';
|
||||
static const String wifiSsidHint = 'wifiSsidHint';
|
||||
static const String yesterday = 'yesterday';
|
||||
static const String measure = 'measure';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user