ui: better sleep timer ui in player and fix auto turn on settings (#43)

* refactor: enhance sleep timer functionality and improve duration formatting

* refactor: update sleep timer settings handling

* refactor: update cancel icon for sleep timer button

* refactor: implement isBetween method for TimeOfDay and simplify sleep timer logic

* refactor: update alwaysAutoTurnOnTimer default value and improve icon usage in settings

* refactor: remove unused IconButton and update sleep timer preset durations
This commit is contained in:
Dr.Blank 2024-10-02 09:18:06 -04:00 committed by GitHub
parent 933bfc5750
commit 12100ffbcd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 755 additions and 383 deletions

View file

@ -1,17 +1,11 @@
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';
import 'package:miniplayer/miniplayer.dart';
import 'package:vaani/constants/sizes.dart';
import 'package:vaani/features/player/providers/currently_playing_provider.dart';
import 'package:vaani/features/player/providers/player_form.dart';
import 'package:vaani/features/player/view/audiobook_player.dart';
import 'package:vaani/features/sleep_timer/core/sleep_timer.dart';
import 'package:vaani/features/sleep_timer/providers/sleep_timer_provider.dart'
show sleepTimerProvider;
import 'package:vaani/settings/app_settings_provider.dart';
import 'package:vaani/shared/extensions/duration_format.dart';
import 'package:vaani/features/sleep_timer/view/sleep_timer_button.dart';
import 'package:vaani/shared/extensions/inverse_lerp.dart';
import 'package:vaani/shared/widgets/not_implemented.dart';
@ -246,13 +240,13 @@ class PlayerWhenExpanded extends HookConsumerWidget {
// chapter list
const ChapterSelectionButton(),
// settings
IconButton(
icon: const Icon(Icons.more_horiz),
onPressed: () {
// show toast
showNotImplementedToast(context);
},
),
// IconButton(
// icon: const Icon(Icons.more_horiz),
// onPressed: () {
// // show toast
// showNotImplementedToast(context);
// },
// ),
],
),
),
@ -261,128 +255,3 @@ class PlayerWhenExpanded extends HookConsumerWidget {
);
}
}
class SleepTimerButton extends HookConsumerWidget {
const SleepTimerButton({
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
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 Tooltip(
message: 'Sleep Timer',
child: InkWell(
onTap: () async {
pendingPlayerModals++;
// show the sleep timer dialog
final resultingDuration = await showDurationPicker(
context: context,
initialTime: ref
.watch(appSettingsProvider)
.playerSettings
.sleepTimerSettings
.defaultDuration,
);
pendingPlayerModals--;
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'),
),
],
);
}
}
class RemainingSleepTimeDisplay extends HookConsumerWidget {
const RemainingSleepTimeDisplay({
super.key,
required this.timer,
});
final SleepTimer timer;
@override
Widget build(BuildContext context, WidgetRef ref) {
final remainingTime = useStream(timer.remainingTimeStream).data;
return Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
borderRadius: BorderRadius.circular(16),
),
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
child: Text(
timer.timer == null
? timer.duration.smartBinaryFormat
: remainingTime?.smartBinaryFormat ?? '',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
);
}
}

View file

@ -6,6 +6,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:list_wheel_scroll_view_nls/list_wheel_scroll_view_nls.dart';
import 'package:vaani/features/player/providers/audiobook_player.dart';
import 'package:vaani/settings/app_settings_provider.dart';
import 'package:vaani/shared/hooks.dart';
const double itemExtent = 25;
class SpeedSelector extends HookConsumerWidget {
const SpeedSelector({
@ -34,11 +37,11 @@ class SpeedSelector extends HookConsumerWidget {
// the speed options
final minSpeed = min(
speeds.reduce((minSpeedSoFar, element) => min(minSpeedSoFar, element)),
speeds.reduce(min),
playerSettings.minSpeed,
);
final maxSpeed = max(
speeds.reduce((maxSpeedSoFar, element) => max(maxSpeedSoFar, element)),
speeds.reduce(max),
playerSettings.maxSpeed,
);
final speedIncrement = playerSettings.speedIncrement;
@ -53,10 +56,9 @@ class SpeedSelector extends HookConsumerWidget {
},
);
final scrollController = FixedExtentScrollController(
final scrollController = useFixedExtentScrollController(
initialItem: availableSpeedsList.indexOf(currentSpeed),
);
const double itemExtent = 25;
return Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -89,7 +91,6 @@ class SpeedSelector extends HookConsumerWidget {
availableSpeedsList: availableSpeedsList,
speedState: speedState,
scrollController: scrollController,
itemExtent: itemExtent,
),
),
),
@ -159,14 +160,12 @@ class SpeedWheel extends StatelessWidget {
required this.availableSpeedsList,
required this.speedState,
required this.scrollController,
required this.itemExtent,
this.showIncrementButtons = true,
});
final List<double> availableSpeedsList;
final ValueNotifier<double> speedState;
final FixedExtentScrollController scrollController;
final double itemExtent;
final bool showIncrementButtons;
@override
@ -203,7 +202,7 @@ class SpeedWheel extends StatelessWidget {
physics: const FixedExtentScrollPhysics(),
children: availableSpeedsList
.map(
(speed) => SpeedLine(itemExtent: itemExtent, speed: speed),
(speed) => SpeedLine(speed: speed),
)
.toList(),
onSelectedItemChanged: (index) {
@ -236,11 +235,9 @@ class SpeedWheel extends StatelessWidget {
class SpeedLine extends StatelessWidget {
const SpeedLine({
super.key,
required this.itemExtent,
required this.speed,
});
final double itemExtent;
final double speed;
@override
@ -250,7 +247,6 @@ class SpeedLine extends StatelessWidget {
// a vertical line
Expanded(
child: Container(
// height: itemExtent,
// thick if multiple of 1, thin if multiple of 0.5 and transparent if multiple of 0.05
width: speed % 0.5 == 0
? 3