From 396b51e90fdd587c3c9829d55ae50493043cf8f8 Mon Sep 17 00:00:00 2001 From: exttex Date: Thu, 15 Oct 2020 22:10:17 +0200 Subject: [PATCH] 0.5.7 - Sleep timer --- lib/api/cache.dart | 8 +++ lib/api/player.dart | 1 + lib/languages/en_us.dart | 9 ++- lib/ui/menu.dart | 116 ++++++++++++++++++++++++++++++++++++++ lib/ui/player_screen.dart | 4 +- pubspec.lock | 49 +++++++--------- pubspec.yaml | 3 +- 7 files changed, 158 insertions(+), 32 deletions(-) diff --git a/lib/api/cache.dart b/lib/api/cache.dart index ef28909..bce5bdc 100644 --- a/lib/api/cache.dart +++ b/lib/api/cache.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:freezer/api/deezer.dart'; import 'package:freezer/api/definitions.dart'; import 'package:freezer/ui/details_screens.dart'; @@ -41,6 +43,12 @@ class Cache { @JsonKey(defaultValue: SortType.DEFAULT) SortType trackSort; + //Sleep timer + @JsonKey(ignore: true) + DateTime sleepTimerTime; + @JsonKey(ignore: true) + StreamSubscription sleepTimer; + //If download threads warning was shown @JsonKey(defaultValue: false) bool threadsWarning; diff --git a/lib/api/player.dart b/lib/api/player.dart index 009f2f0..f0e64dd 100644 --- a/lib/api/player.dart +++ b/lib/api/player.dart @@ -336,6 +336,7 @@ class AudioPlayerTask extends BackgroundAudioTask { //Restore position on play if (_lastPosition != null) { onSeekTo(_lastPosition); + _lastPosition = null; } } diff --git a/lib/languages/en_us.dart b/lib/languages/en_us.dart index 756c86e..c89f6b1 100644 --- a/lib/languages/en_us.dart +++ b/lib/languages/en_us.dart @@ -238,6 +238,13 @@ const language_en_us = { //0.5.6 Strings: "Create .nomedia files": "Create .nomedia files", - "To prevent gallery being filled with album art": "To prevent gallery being filled with album art" + "To prevent gallery being filled with album art": "To prevent gallery being filled with album art", + + //0.5.7 Strings: + "Sleep timer": "Sleep timer", + "Minutes:": "Minutes:", + "Hours:": "Hours:", + "Cancel current timer": "Cancel current timer", + "Current timer ends at": "Current timer ends at" } }; diff --git a/lib/ui/menu.dart b/lib/ui/menu.dart index b3f6f17..601dcb1 100644 --- a/lib/ui/menu.dart +++ b/lib/ui/menu.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:audio_service/audio_service.dart'; @@ -8,6 +10,7 @@ import 'package:freezer/api/download.dart'; import 'package:freezer/ui/details_screens.dart'; import 'package:freezer/ui/error.dart'; import 'package:freezer/translations.i18n.dart'; +import 'package:numberpicker/numberpicker.dart'; import 'package:share/share.dart'; import '../api/definitions.dart'; @@ -519,10 +522,123 @@ class MenuSheet { }, ); + Widget sleepTimer() => ListTile( + title: Text('Sleep timer'.i18n), + leading: Icon(Icons.access_time), + onTap: () async { + showDialog( + context: context, + builder: (context) { + return SleepTimerDialog(); + } + ); + }, + ); void _close() => Navigator.of(context).pop(); } + +class SleepTimerDialog extends StatefulWidget { + @override + _SleepTimerDialogState createState() => _SleepTimerDialogState(); +} + +class _SleepTimerDialogState extends State { + int hours = 0; + int minutes = 30; + + String _endTime() { + return '${cache.sleepTimerTime.hour.toString().padLeft(2, '0')}:${cache.sleepTimerTime.minute.toString().padLeft(2, '0')}'; + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text('Sleep timer'.i18n), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('Hours:'.i18n), + NumberPicker.integer( + initialValue: hours, + minValue: 0, + maxValue: 69, + onChanged: (v) => setState(() => hours = v), + highlightSelectedValue: true, + ), + ], + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('Minutes:'.i18n), + NumberPicker.integer( + initialValue: minutes, + minValue: 0, + maxValue: 60, + onChanged: (v) => setState(() => minutes = v), + highlightSelectedValue: true + ), + ], + ), + ], + ), + Container(height: 4.0), + if (cache.sleepTimerTime != null) + Text( + 'Current timer ends at'.i18n + ': ' +_endTime(), + textAlign: TextAlign.center, + ) + ], + ), + actions: [ + FlatButton( + child: Text('Dismiss'.i18n), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + if (cache.sleepTimer != null) + FlatButton( + child: Text('Cancel current timer'.i18n), + onPressed: () { + cache.sleepTimer.cancel(); + cache.sleepTimer = null; + cache.sleepTimerTime = null; + Navigator.of(context).pop(); + }, + ), + + FlatButton( + child: Text('Save'.i18n), + onPressed: () { + Duration duration = Duration(hours: hours, minutes: minutes); + if (cache.sleepTimer != null) { + cache.sleepTimer.cancel(); + } + //Create timer + cache.sleepTimer = Stream.fromFuture(Future.delayed(duration)).listen((_) { + AudioService.pause(); + cache.sleepTimer.cancel(); + cache.sleepTimerTime = null; + cache.sleepTimer = null; + }); + cache.sleepTimerTime = DateTime.now().add(duration); + Navigator.of(context).pop(); + }, + ), + ], + ); + } +} + + class SelectPlaylistDialog extends StatefulWidget { final Track track; diff --git a/lib/ui/player_screen.dart b/lib/ui/player_screen.dart index b8a35fe..c39c536 100644 --- a/lib/ui/player_screen.dart +++ b/lib/ui/player_screen.dart @@ -197,7 +197,7 @@ class _PlayerScreenHorizontalState extends State { onPressed: () { Track t = Track.fromMediaItem(AudioService.currentMediaItem); MenuSheet m = MenuSheet(context); - m.defaultTrackMenu(t); + m.defaultTrackMenu(t, options: [m.sleepTimer()]); }, ) ], @@ -331,7 +331,7 @@ class _PlayerScreenVerticalState extends State { onPressed: () { Track t = Track.fromMediaItem(AudioService.currentMediaItem); MenuSheet m = MenuSheet(context); - m.defaultTrackMenu(t); + m.defaultTrackMenu(t, options: [m.sleepTimer()]); }, ) ], diff --git a/pubspec.lock b/pubspec.lock index f56ccac..961cdf4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -42,7 +42,7 @@ packages: name: audio_session url: "https://pub.dartlang.org" source: hosted - version: "0.0.7" + version: "0.0.9" boolean_selector: dependency: transitive description: @@ -161,7 +161,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "3.4.1" + version: "3.5.0" collection: dependency: "direct main" description: @@ -175,7 +175,7 @@ packages: name: connectivity url: "https://pub.dartlang.org" source: hosted - version: "0.4.9+3" + version: "0.4.9+5" connectivity_for_web: dependency: transitive description: @@ -288,13 +288,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0-nullsafety.1" - ffi: - dependency: transitive - description: - name: ffi - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.3" file: dependency: transitive description: @@ -355,7 +348,7 @@ packages: name: flutter_local_notifications url: "https://pub.dartlang.org" source: hosted - version: "1.4.4+5" + version: "1.5.0+1" flutter_local_notifications_platform_interface: dependency: transitive description: @@ -433,7 +426,7 @@ packages: name: html url: "https://pub.dartlang.org" source: hosted - version: "0.14.0+3" + version: "0.14.0+4" http: dependency: transitive description: @@ -462,6 +455,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.4.5" + infinite_listview: + dependency: transitive + description: + name: infinite_listview + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1+1" intl: dependency: "direct main" description: @@ -567,6 +567,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.1" + numberpicker: + dependency: "direct main" + description: + name: numberpicker + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" octo_image: dependency: transitive description: @@ -608,7 +615,7 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.18" + version: "1.6.10" path_provider_ex: dependency: "direct main" description: @@ -637,13 +644,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.3" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.4+1" pedantic: dependency: transitive description: @@ -872,7 +872,7 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "5.7.2" + version: "5.7.4" url_launcher_linux: dependency: transitive description: @@ -936,13 +936,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" - win32: - dependency: transitive - description: - name: win32 - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.3" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6ff28d5..7a61b12 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.5.6+1 +version: 0.5.7+1 environment: sdk: ">=2.8.0 <3.0.0" @@ -68,6 +68,7 @@ dependencies: url_launcher: ^5.7.2 uni_links: ^0.4.0 share: ^0.6.5+2 + numberpicker: ^1.2.1 audio_session: ^0.0.9 audio_service: