Skip to content

Commit

Permalink
feat: add radio sleep timer (#1054)
Browse files Browse the repository at this point in the history
the next similar station search is too unreliable, thus adding the pause timer button from podcasts instead. Now with mobile bottom sheet
  • Loading branch information
Feichtmeier authored Nov 26, 2024
1 parent efb9bb4 commit c4b56b8
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 85 deletions.
11 changes: 8 additions & 3 deletions lib/common/view/theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,10 @@ double get audioCardDimension => kAudioCardDimension - (isMobile ? 15 : 0);
double get bottomPlayerHeight => isMobile ? 80.0 : 90.0;

List<Widget> space({
double widthGap = 5,
double heightGap = 5,
double widthGap = kSmallestSpace,
double heightGap = kSmallestSpace,
required Iterable<Widget> children,
bool expandAll = false,
}) =>
children
.expand(
Expand All @@ -294,7 +295,11 @@ List<Widget> space({
width: widthGap,
height: heightGap,
);
yield item;
if (expandAll) {
yield Expanded(child: item);
} else {
yield item;
}
},
)
.skip(1)
Expand Down
6 changes: 2 additions & 4 deletions lib/player/view/player_main_controls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import '../../common/view/theme.dart';
import '../../extensions/build_context_x.dart';
import '../../extensions/theme_data_x.dart';
import '../../l10n/l10n.dart';
import '../../radio/view/next_station_button.dart';
import '../player_model.dart';
import 'play_button.dart';
import 'player_pause_timer_button.dart';
import 'repeat_button.dart';
import 'seek_button.dart';
import 'shuffle_button.dart';
Expand Down Expand Up @@ -116,9 +116,7 @@ class PlayerMainControls extends StatelessWidget with WatchItMixin {
active: active,
iconColor: defaultColor,
),
AudioType.radio => NextStationButton(
iconColor: defaultColor,
),
AudioType.radio => const PlayerPauseTimerButton(),
_ => const SizedBox.shrink(),
},
];
Expand Down
162 changes: 162 additions & 0 deletions lib/player/view/player_pause_timer_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import 'package:flutter/material.dart';
import 'package:watch_it/watch_it.dart';
import 'package:yaru/yaru.dart';

import '../../common/view/common_widgets.dart';
import '../../common/view/icons.dart';
import '../../common/view/modals.dart';
import '../../common/view/snackbars.dart';
import '../../common/view/theme.dart';
import '../../common/view/ui_constants.dart';
import '../../extensions/build_context_x.dart';
import '../../extensions/duration_x.dart';
import '../../l10n/l10n.dart';
import '../player_model.dart';

class PlayerPauseTimerButton extends StatelessWidget {
const PlayerPauseTimerButton({super.key});

@override
Widget build(BuildContext context) => IconButton(
tooltip: context.l10n.schedulePlaybackStopTimer,
onPressed: () => showModal(
context: context,
mode: ModalMode.platformModalMode,
content: isMobile ? const _BottomSheet() : const _Dialog(),
),
icon: Icon(Iconz.sleep),
);
}

class _Dialog extends StatefulWidget {
const _Dialog();

@override
State<_Dialog> createState() => _DialogState();
}

class _DialogState extends State<_Dialog> {
TimeOfDay _timeOfDay = TimeOfDay.now();
@override
Widget build(BuildContext context) {
return AlertDialog(
content: YaruTimeEntry(
autofocus: true,
initialTimeOfDay: _timeOfDay,
onChanged: (value) {
if (value != null) {
setState(() => _timeOfDay = value);
}
},
),
actions: [
TextButton(
onPressed: Navigator.of(context).pop,
child: Text(context.l10n.cancel),
),
ImportantButton(
onPressed: () {
final duration = Duration(
hours: _timeOfDay.hour - TimeOfDay.now().hour,
minutes: _timeOfDay.minute - TimeOfDay.now().minute,
);
di<PlayerModel>().setTimer(duration);
showSnackBar(
context: context,
content: Text(
context.l10n.playbackWillStopIn(
duration.formattedTime,
_timeOfDay.format(context),
),
),
);
Navigator.of(context).pop();
},
child: Text(context.l10n.ok),
),
],
);
}
}

class _BottomSheet extends StatefulWidget {
const _BottomSheet();

@override
State<_BottomSheet> createState() => _BottomSheetState();
}

class _BottomSheetState extends State<_BottomSheet> {
TimeOfDay _timeOfDay = TimeOfDay.now();
@override
Widget build(BuildContext context) {
return BottomSheet(
builder: (context) {
return Padding(
padding: const EdgeInsets.all(kLargestSpace),
child: Column(
children: space(
heightGap: kLargestSpace,
children: [
Text(
context.l10n.schedulePlaybackStopTimer,
style: context.textTheme.headlineSmall,
),
YaruTimeEntry(
autofocus: true,
initialTimeOfDay: _timeOfDay,
onChanged: (value) {
if (value != null) {
setState(() => _timeOfDay = value);
}
},
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Row(
children: space(
expandAll: true,
children: [
TextButton(
onPressed: Navigator.of(context).pop,
child: Text(context.l10n.cancel),
),
ImportantButton(
onPressed: () {
final duration = Duration(
hours: _timeOfDay.hour - TimeOfDay.now().hour,
minutes: _timeOfDay.minute -
TimeOfDay.now().minute,
);
di<PlayerModel>().setTimer(duration);
showSnackBar(
context: context,
content: Text(
context.l10n.playbackWillStopIn(
duration.formattedTime,
_timeOfDay.format(context),
),
),
);
Navigator.of(context).pop();
},
child: Text(context.l10n.ok),
),
],
),
),
],
),
),
],
),
),
);
},
onClosing: () {},
enableDrag: false,
);
}
}
4 changes: 2 additions & 2 deletions lib/podcasts/view/podcast_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import 'podcast_refresh_button.dart';
import 'podcast_reorder_button.dart';
import 'podcast_replay_button.dart';
import 'podcast_sub_button.dart';
import 'podcast_timer_button.dart';
import '../../player/view/player_pause_timer_button.dart';
import 'sliver_podcast_page_list.dart';

class PodcastPage extends StatefulWidget with WatchItStatefulWidgetMixin {
Expand Down Expand Up @@ -168,7 +168,7 @@ class _PodcastPageState extends State<PodcastPage> {
children: [
if (!isMobile)
PodcastReplayButton(audios: episodesWithDownloads),
const PodcastTimerButton(),
const PlayerPauseTimerButton(),
PodcastSubButton(
audios: episodesWithDownloads,
pageId: widget.feedUrl,
Expand Down
76 changes: 0 additions & 76 deletions lib/podcasts/view/podcast_timer_button.dart

This file was deleted.

0 comments on commit c4b56b8

Please sign in to comment.