mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2026-01-02 16:29:31 +00:00
feat: Add duration_picker dependency to pubspec.yaml
This commit is contained in:
parent
b98188d7fb
commit
fbd789f989
13 changed files with 558 additions and 49 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:duration_picker/duration_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
|
@ -7,7 +8,9 @@ import 'package:whispering_pages/constants/sizes.dart';
|
|||
import 'package:whispering_pages/features/player/providers/currently_playing_provider.dart';
|
||||
import 'package:whispering_pages/features/player/view/audiobook_player.dart';
|
||||
import 'package:whispering_pages/features/sleep_timer/core/sleep_timer.dart';
|
||||
import 'package:whispering_pages/features/sleep_timer/providers/sleep_timer_provider.dart';
|
||||
import 'package:whispering_pages/features/sleep_timer/providers/sleep_timer_provider.dart'
|
||||
show sleepTimerProvider;
|
||||
import 'package:whispering_pages/settings/app_settings_provider.dart';
|
||||
import 'package:whispering_pages/shared/extensions/inverse_lerp.dart';
|
||||
|
||||
import 'widgets/audiobook_player_seek_button.dart';
|
||||
|
|
@ -227,17 +230,84 @@ class SleepTimerButton extends HookConsumerWidget {
|
|||
final sleepTimer = ref.watch(sleepTimerProvider);
|
||||
// if sleep timer is not active, show the button with the sleep timer icon
|
||||
// if the sleep timer is active, show the remaining time in a pill shaped container
|
||||
return sleepTimer == null
|
||||
? IconButton(
|
||||
color: sleepTimer != null
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.onSurface,
|
||||
icon: const Icon(Icons.timer_rounded),
|
||||
onPressed: () {},
|
||||
)
|
||||
: RemainingSleepTimeDisplay(
|
||||
timer: sleepTimer,
|
||||
return Tooltip(
|
||||
message: 'Sleep Timer',
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
// show the sleep timer dialog
|
||||
final resultingDuration = await showDurationPicker(
|
||||
context: context,
|
||||
initialTime: ref
|
||||
.watch(appSettingsProvider)
|
||||
.playerSettings
|
||||
.sleepTimerSettings
|
||||
.defaultDuration,
|
||||
);
|
||||
if (resultingDuration != null) {
|
||||
// if 0 is selected, cancel the timer
|
||||
if (resultingDuration.inSeconds == 0) {
|
||||
ref.read(sleepTimerProvider.notifier).cancelTimer();
|
||||
} else {
|
||||
ref.read(sleepTimerProvider.notifier).setTimer(resultingDuration);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: sleepTimer == null
|
||||
? Icon(
|
||||
Icons.timer_rounded,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
)
|
||||
: RemainingSleepTimeDisplay(
|
||||
timer: sleepTimer,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SleepTimerDialog extends HookConsumerWidget {
|
||||
const SleepTimerDialog({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final sleepTimer = ref.watch(sleepTimerProvider);
|
||||
final sleepTimerSettings =
|
||||
ref.watch(appSettingsProvider).playerSettings.sleepTimerSettings;
|
||||
final timerDurationController = useTextEditingController(
|
||||
text: sleepTimerSettings.defaultDuration.inMinutes.toString(),
|
||||
);
|
||||
|
||||
return AlertDialog(
|
||||
title: const Text('Sleep Timer'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('Set the duration for the sleep timer'),
|
||||
TextField(
|
||||
controller: timerDurationController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Duration in minutes',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// sleepTimer.setTimer(
|
||||
// Duration(
|
||||
// minutes: int.tryParse(timerDurationController.text) ?? 0,
|
||||
// ),
|
||||
// );
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Set Timer'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,14 @@ import 'package:whispering_pages/features/player/core/audiobook_player.dart';
|
|||
/// timer is cancelled when the music player is paused or stopped
|
||||
class SleepTimer {
|
||||
/// The duration after which the music player will be paused
|
||||
final Duration duration;
|
||||
Duration _duration;
|
||||
|
||||
Duration get duration => _duration;
|
||||
|
||||
set duration(Duration value) {
|
||||
_duration = value;
|
||||
reset();
|
||||
}
|
||||
|
||||
/// The player to be paused
|
||||
final AudiobookPlayer player;
|
||||
|
|
@ -23,22 +30,30 @@ class SleepTimer {
|
|||
/// when the timer was started
|
||||
DateTime? startedAt;
|
||||
|
||||
SleepTimer({required this.duration, required this.player}) {
|
||||
player.playbackEventStream.listen((event) {
|
||||
if (event.processingState == ProcessingState.completed ||
|
||||
event.processingState == ProcessingState.idle) {
|
||||
reset();
|
||||
}
|
||||
});
|
||||
/// subscriptions
|
||||
final List<StreamSubscription> _subscriptions = [];
|
||||
|
||||
SleepTimer({required duration, required this.player}) : _duration = duration {
|
||||
_subscriptions.add(
|
||||
player.playbackEventStream.listen((event) {
|
||||
if (event.processingState == ProcessingState.completed ||
|
||||
event.processingState == ProcessingState.idle) {
|
||||
reset();
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
/// pause the player when the timer is up
|
||||
player.playerStateStream.listen((state) {
|
||||
if (state.playing && timer == null) {
|
||||
startTimer();
|
||||
} else if (!state.playing) {
|
||||
reset();
|
||||
}
|
||||
});
|
||||
_subscriptions.add(
|
||||
player.playerStateStream.listen((state) {
|
||||
if (state.playing && timer == null) {
|
||||
startTimer();
|
||||
} else if (!state.playing) {
|
||||
reset();
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
debugPrint('SleepTimer created with duration: $duration');
|
||||
}
|
||||
|
||||
|
|
@ -53,9 +68,12 @@ class SleepTimer {
|
|||
}
|
||||
}
|
||||
|
||||
/// starts the timer
|
||||
void startTimer() {
|
||||
/// starts the timer with the given duration or the default duration
|
||||
void startTimer([
|
||||
Duration? forDuration,
|
||||
]) {
|
||||
reset();
|
||||
duration = forDuration ?? duration;
|
||||
timer = Timer(duration, () {
|
||||
player.pause();
|
||||
reset();
|
||||
|
|
@ -84,6 +102,9 @@ class SleepTimer {
|
|||
/// dispose the timer
|
||||
void dispose() {
|
||||
reset();
|
||||
for (var sub in _subscriptions) {
|
||||
sub.cancel();
|
||||
}
|
||||
debugPrint('SleepTimer disposed');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,59 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:whispering_pages/features/player/providers/audiobook_player.dart';
|
||||
import 'package:whispering_pages/features/sleep_timer/core/sleep_timer.dart';
|
||||
import 'package:whispering_pages/features/sleep_timer/core/sleep_timer.dart'
|
||||
as core;
|
||||
import 'package:whispering_pages/settings/app_settings_provider.dart';
|
||||
import 'package:whispering_pages/shared/extensions/time_of_day.dart';
|
||||
|
||||
part 'sleep_timer_provider.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
SleepTimer? sleepTimer(SleepTimerRef ref) {
|
||||
final appSettings = ref.watch(appSettingsProvider);
|
||||
final sleepTimerSettings = appSettings.playerSettings.sleepTimerSettings;
|
||||
var sleepTimer = SleepTimer(
|
||||
// duration: sleepTimerSettings.defaultDuration,
|
||||
duration: const Duration(seconds: 5),
|
||||
player: ref.watch(simpleAudiobookPlayerProvider),
|
||||
);
|
||||
ref.onDispose(sleepTimer.dispose);
|
||||
return sleepTimer;
|
||||
class SleepTimer extends _$SleepTimer {
|
||||
@override
|
||||
core.SleepTimer? build() {
|
||||
final appSettings = ref.watch(appSettingsProvider);
|
||||
final sleepTimerSettings = appSettings.playerSettings.sleepTimerSettings;
|
||||
bool isEnabled = sleepTimerSettings.autoTurnOnTimer;
|
||||
if (!isEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((!sleepTimerSettings.alwaysAutoTurnOnTimer) &&
|
||||
(sleepTimerSettings.autoTurnOnTime
|
||||
.toTimeOfDay()
|
||||
.isAfter(TimeOfDay.now()) &&
|
||||
sleepTimerSettings.autoTurnOffTime
|
||||
.toTimeOfDay()
|
||||
.isBefore(TimeOfDay.now()))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var sleepTimer = core.SleepTimer(
|
||||
// duration: sleepTimerSettings.defaultDuration,
|
||||
duration: const Duration(seconds: 5),
|
||||
player: ref.watch(simpleAudiobookPlayerProvider),
|
||||
);
|
||||
ref.onDispose(sleepTimer.dispose);
|
||||
return sleepTimer;
|
||||
}
|
||||
|
||||
void setTimer(Duration resultingDuration) {
|
||||
if (state != null) {
|
||||
state!.duration = resultingDuration;
|
||||
ref.notifyListeners();
|
||||
} else {
|
||||
final timer = core.SleepTimer(
|
||||
duration: resultingDuration,
|
||||
player: ref.watch(simpleAudiobookPlayerProvider),
|
||||
);
|
||||
ref.onDispose(timer.dispose);
|
||||
state = timer;
|
||||
}
|
||||
}
|
||||
|
||||
void cancelTimer() {
|
||||
state?.dispose();
|
||||
state = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@ part of 'sleep_timer_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$sleepTimerHash() => r'79646b12412f3300166db29328664a5e58e405bd';
|
||||
String _$sleepTimerHash() => r'de2f39febda3c2234e792f64199c51828206ea9b';
|
||||
|
||||
/// See also [sleepTimer].
|
||||
@ProviderFor(sleepTimer)
|
||||
final sleepTimerProvider = Provider<SleepTimer?>.internal(
|
||||
sleepTimer,
|
||||
/// See also [SleepTimer].
|
||||
@ProviderFor(SleepTimer)
|
||||
final sleepTimerProvider =
|
||||
NotifierProvider<SleepTimer, core.SleepTimer?>.internal(
|
||||
SleepTimer.new,
|
||||
name: r'sleepTimerProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$sleepTimerHash,
|
||||
|
|
@ -19,6 +20,6 @@ final sleepTimerProvider = Provider<SleepTimer?>.internal(
|
|||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef SleepTimerRef = ProviderRef<SleepTimer?>;
|
||||
typedef _$SleepTimer = Notifier<core.SleepTimer?>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||
|
|
|
|||
|
|
@ -21,10 +21,19 @@ class Routes {
|
|||
pathParamName: 'itemId',
|
||||
name: 'libraryItem',
|
||||
);
|
||||
|
||||
// settings
|
||||
static const settings = _SimpleRoute(
|
||||
pathName: 'config',
|
||||
name: 'settings',
|
||||
);
|
||||
static const autoSleepTimerSettings = _SimpleRoute(
|
||||
pathName: 'autosleeptimer',
|
||||
name: 'autoSleepTimerSettings',
|
||||
// parentRoute: settings,
|
||||
);
|
||||
|
||||
// search and explore
|
||||
static const search = _SimpleRoute(
|
||||
pathName: 'search',
|
||||
name: 'search',
|
||||
|
|
@ -51,9 +60,12 @@ class _SimpleRoute {
|
|||
final String name;
|
||||
final _SimpleRoute? parentRoute;
|
||||
|
||||
String get path =>
|
||||
'${parentRoute?.path ?? ''}${parentRoute != null ? '/' : ''}$localPath';
|
||||
/// the full path of the route
|
||||
String get path {
|
||||
return '${parentRoute?.path ?? ''}$localPath';
|
||||
}
|
||||
|
||||
/// the local path of the route
|
||||
String get localPath =>
|
||||
'/$pathName${pathParamName != null ? '/:$pathParamName' : ''}';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import 'package:whispering_pages/features/explore/view/explore_page.dart';
|
|||
import 'package:whispering_pages/features/explore/view/search_result_page.dart';
|
||||
import 'package:whispering_pages/features/item_viewer/view/library_item_page.dart';
|
||||
import 'package:whispering_pages/features/onboarding/view/onboarding_single_page.dart';
|
||||
import 'package:whispering_pages/pages/app_settings.dart';
|
||||
import 'package:whispering_pages/pages/home_page.dart';
|
||||
import 'package:whispering_pages/settings/view/app_settings_page.dart';
|
||||
import 'package:whispering_pages/settings/view/auto_sleep_timer_settings_page.dart';
|
||||
|
||||
import 'scaffold_with_nav_bar.dart';
|
||||
import 'transitions/slide.dart';
|
||||
|
|
@ -128,6 +129,15 @@ class MyAppRouter {
|
|||
// builder: (context, state) => const AppSettingsPage(),
|
||||
pageBuilder: defaultPageBuilder(const AppSettingsPage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.autoSleepTimerSettings.path,
|
||||
name: Routes.autoSleepTimerSettings.name,
|
||||
// builder: (context, state) =>
|
||||
// const AutoSleepTimerSettingsPage(),
|
||||
pageBuilder: defaultPageBuilder(
|
||||
const AutoSleepTimerSettingsPage(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:whispering_pages/api/authenticated_user_provider.dart';
|
||||
import 'package:whispering_pages/api/server_provider.dart';
|
||||
import 'package:whispering_pages/router/router.dart';
|
||||
import 'package:whispering_pages/settings/app_settings_provider.dart';
|
||||
|
||||
class AppSettingsPage extends HookConsumerWidget {
|
||||
|
|
@ -19,6 +21,7 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
final availableUsers = ref.watch(authenticatedUserProvider);
|
||||
final serverURIController = useTextEditingController();
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final sleepTimerSettings = appSettings.playerSettings.sleepTimerSettings;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
|
|
@ -26,6 +29,7 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
),
|
||||
body: SettingsList(
|
||||
sections: [
|
||||
// Appearance section
|
||||
SettingsSection(
|
||||
margin: const EdgeInsetsDirectional.symmetric(
|
||||
horizontal: 16.0,
|
||||
|
|
@ -55,7 +59,7 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
),
|
||||
leading: appSettings.useMaterialThemeOnItemPage
|
||||
? const Icon(Icons.auto_fix_high)
|
||||
: const Icon(Icons.auto_fix_off),
|
||||
: const Icon(Icons.auto_fix_off),
|
||||
onToggle: (value) {
|
||||
ref.read(appSettingsProvider.notifier).updateState(
|
||||
appSettings.copyWith(
|
||||
|
|
@ -66,6 +70,60 @@ class AppSettingsPage extends HookConsumerWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Sleep Timer section
|
||||
SettingsSection(
|
||||
margin: const EdgeInsetsDirectional.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
title: Text(
|
||||
'Sleep Timer',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
tiles: [
|
||||
SettingsTile.navigation(
|
||||
// initialValue: sleepTimerSettings.autoTurnOnTimer,
|
||||
title: const Text('Auto Turn On Timer'),
|
||||
description: const Text(
|
||||
'Automatically turn on the sleep timer based on the time of day',
|
||||
),
|
||||
leading: sleepTimerSettings.autoTurnOnTimer
|
||||
? const Icon(Icons.timer)
|
||||
: const Icon(Icons.timer_off),
|
||||
onPressed: (context) {
|
||||
// push the sleep timer settings page
|
||||
context.pushNamed(Routes.autoSleepTimerSettings.name);
|
||||
},
|
||||
// a switch to enable or disable the auto turn off time
|
||||
trailing: IntrinsicHeight(
|
||||
child: Row(
|
||||
children: [
|
||||
VerticalDivider(
|
||||
color: Theme.of(context).dividerColor.withOpacity(0.5),
|
||||
indent: 8.0,
|
||||
endIndent: 8.0,
|
||||
// width: 8.0,
|
||||
// thickness: 2.0,
|
||||
// height: 24.0,
|
||||
),
|
||||
Switch(
|
||||
value: sleepTimerSettings.autoTurnOnTimer,
|
||||
onChanged: (value) {
|
||||
ref.read(appSettingsProvider.notifier).updateState(
|
||||
appSettings.copyWith.playerSettings
|
||||
.sleepTimerSettings(
|
||||
autoTurnOnTimer: value,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
110
lib/settings/view/auto_sleep_timer_settings_page.dart
Normal file
110
lib/settings/view/auto_sleep_timer_settings_page.dart
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:whispering_pages/settings/app_settings_provider.dart';
|
||||
import 'package:whispering_pages/shared/extensions/time_of_day.dart';
|
||||
|
||||
class AutoSleepTimerSettingsPage extends HookConsumerWidget {
|
||||
const AutoSleepTimerSettingsPage({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final appSettings = ref.watch(appSettingsProvider);
|
||||
final sleepTimerSettings = appSettings.playerSettings.sleepTimerSettings;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Auto Sleep Timer Settings'),
|
||||
),
|
||||
body: SettingsList(
|
||||
sections: [
|
||||
SettingsSection(
|
||||
margin: const EdgeInsetsDirectional.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
tiles: [
|
||||
SettingsTile.switchTile(
|
||||
// initialValue: sleepTimerSettings.autoTurnOnTimer,
|
||||
title: const Text('Auto Turn On Timer'),
|
||||
description: const Text(
|
||||
'Automatically turn on the sleep timer based on the time of day',
|
||||
),
|
||||
leading: sleepTimerSettings.autoTurnOnTimer
|
||||
? const Icon(Icons.timer)
|
||||
: const Icon(Icons.timer_off),
|
||||
onToggle: (value) {
|
||||
ref.read(appSettingsProvider.notifier).updateState(
|
||||
appSettings.copyWith.playerSettings.sleepTimerSettings(
|
||||
autoTurnOnTimer: value,
|
||||
),
|
||||
);
|
||||
},
|
||||
initialValue: sleepTimerSettings.autoTurnOnTimer,
|
||||
),
|
||||
// auto turn on time settings, enabled only when autoTurnOnTimer is enabled
|
||||
SettingsTile.navigation(
|
||||
enabled: sleepTimerSettings.autoTurnOnTimer,
|
||||
title: const Text('Auto Turn On Time'),
|
||||
description: const Text(
|
||||
'Turn on the sleep timer at the specified time',
|
||||
),
|
||||
onPressed: (context) async {
|
||||
// navigate to the time picker
|
||||
final selected = await showTimePicker(
|
||||
context: context,
|
||||
initialTime:
|
||||
sleepTimerSettings.autoTurnOnTime.toTimeOfDay(),
|
||||
);
|
||||
if (selected != null) {
|
||||
ref.read(appSettingsProvider.notifier).updateState(
|
||||
appSettings.copyWith.playerSettings
|
||||
.sleepTimerSettings(
|
||||
autoTurnOnTime: selected.toDuration(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
value: Text(
|
||||
sleepTimerSettings.autoTurnOnTime
|
||||
.toTimeOfDay()
|
||||
.format(context),
|
||||
),
|
||||
),
|
||||
SettingsTile.navigation(
|
||||
title: const Text('Auto Turn Off Time'),
|
||||
description: const Text(
|
||||
'Turn off the sleep timer at the specified time',
|
||||
),
|
||||
enabled: sleepTimerSettings.autoTurnOnTimer,
|
||||
onPressed: (context) async {
|
||||
// navigate to the time picker
|
||||
final selected = await showTimePicker(
|
||||
context: context,
|
||||
initialTime:
|
||||
sleepTimerSettings.autoTurnOffTime.toTimeOfDay(),
|
||||
);
|
||||
if (selected != null) {
|
||||
ref.read(appSettingsProvider.notifier).updateState(
|
||||
appSettings.copyWith.playerSettings
|
||||
.sleepTimerSettings(
|
||||
autoTurnOffTime: selected.toDuration(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
value: Text(
|
||||
sleepTimerSettings.autoTurnOffTime
|
||||
.toTimeOfDay()
|
||||
.format(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
31
lib/shared/extensions/time_of_day.dart
Normal file
31
lib/shared/extensions/time_of_day.dart
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
extension ToTimeOfDay on Duration {
|
||||
TimeOfDay toTimeOfDay() {
|
||||
return TimeOfDay(hour: inHours, minute: inMinutes % 60);
|
||||
}
|
||||
}
|
||||
|
||||
extension ToDuration on TimeOfDay {
|
||||
Duration toDuration() {
|
||||
return Duration(hours: hour, minutes: minute);
|
||||
}
|
||||
}
|
||||
|
||||
extension TimeOfDayExtension on TimeOfDay {
|
||||
int compareTo(TimeOfDay other) {
|
||||
if (hour < other.hour) return -1;
|
||||
if (hour > other.hour) return 1;
|
||||
if (minute < other.minute) return -1;
|
||||
if (minute > other.minute) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool operator <(TimeOfDay other) => compareTo(other) < 0;
|
||||
bool operator >(TimeOfDay other) => compareTo(other) > 0;
|
||||
bool operator <=(TimeOfDay other) => compareTo(other) <= 0;
|
||||
bool operator >=(TimeOfDay other) => compareTo(other) >= 0;
|
||||
|
||||
bool isBefore(TimeOfDay other) => this < other;
|
||||
bool isAfter(TimeOfDay other) => this > other;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue