0.5.8 - queue reordering, bug and ui fixes, shortcut icon
|
@ -293,6 +293,7 @@ public class Deezer {
|
||||||
isFlac = false;
|
isFlac = false;
|
||||||
}
|
}
|
||||||
Tag tag = f.getTag();
|
Tag tag = f.getTag();
|
||||||
|
tag.setEncoding("utf-8");
|
||||||
|
|
||||||
tag.setField(FieldKey.TITLE, publicTrack.getString("title"));
|
tag.setField(FieldKey.TITLE, publicTrack.getString("title"));
|
||||||
tag.setField(FieldKey.ALBUM, publicTrack.getJSONObject("album").getString("title"));
|
tag.setField(FieldKey.ALBUM, publicTrack.getJSONObject("album").getString("title"));
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector
|
||||||
|
android:height="108dp"
|
||||||
|
android:width="108dp"
|
||||||
|
android:viewportHeight="108"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#3DDC84"
|
||||||
|
android:pathData="M0,0h108v108h-108z"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_favorites_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_favorites_foreground"/>
|
||||||
|
</adaptive-icon>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_favorites_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_favorites_foreground"/>
|
||||||
|
</adaptive-icon>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_flow_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_flow_foreground"/>
|
||||||
|
</adaptive-icon>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_flow_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_flow_foreground"/>
|
||||||
|
</adaptive-icon>
|
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 7.9 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 156 KiB |
After Width: | Height: | Size: 47 KiB |
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_favorites_background">#3DDC84</color>
|
||||||
|
</resources>
|
|
@ -49,6 +49,9 @@ class Cache {
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
StreamSubscription sleepTimer;
|
StreamSubscription sleepTimer;
|
||||||
|
|
||||||
|
@JsonKey(defaultValue: const [])
|
||||||
|
List<String> searchHistory;
|
||||||
|
|
||||||
//If download threads warning was shown
|
//If download threads warning was shown
|
||||||
@JsonKey(defaultValue: false)
|
@JsonKey(defaultValue: false)
|
||||||
bool threadsWarning;
|
bool threadsWarning;
|
||||||
|
|
|
@ -31,6 +31,8 @@ Cache _$CacheFromJson(Map<String, dynamic> json) {
|
||||||
PlaylistSortType.DEFAULT
|
PlaylistSortType.DEFAULT
|
||||||
..trackSort = _$enumDecodeNullable(_$SortTypeEnumMap, json['trackSort']) ??
|
..trackSort = _$enumDecodeNullable(_$SortTypeEnumMap, json['trackSort']) ??
|
||||||
SortType.DEFAULT
|
SortType.DEFAULT
|
||||||
|
..searchHistory =
|
||||||
|
(json['searchHistory'] as List)?.map((e) => e as String)?.toList() ?? []
|
||||||
..threadsWarning = json['threadsWarning'] as bool ?? false;
|
..threadsWarning = json['threadsWarning'] as bool ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +46,7 @@ Map<String, dynamic> _$CacheToJson(Cache instance) => <String, dynamic>{
|
||||||
'libraryPlaylistSort':
|
'libraryPlaylistSort':
|
||||||
_$PlaylistSortTypeEnumMap[instance.libraryPlaylistSort],
|
_$PlaylistSortTypeEnumMap[instance.libraryPlaylistSort],
|
||||||
'trackSort': _$SortTypeEnumMap[instance.trackSort],
|
'trackSort': _$SortTypeEnumMap[instance.trackSort],
|
||||||
|
'searchHistory': instance.searchHistory,
|
||||||
'threadsWarning': instance.threadsWarning,
|
'threadsWarning': instance.threadsWarning,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -221,7 +221,7 @@ class PlayerHelper {
|
||||||
QueueSource queueSource = QueueSource(
|
QueueSource queueSource = QueueSource(
|
||||||
id: stl.id,
|
id: stl.id,
|
||||||
source: (stl.id == 'flow')?'flow':'smarttracklist',
|
source: (stl.id == 'flow')?'flow':'smarttracklist',
|
||||||
text: stl.title
|
text: stl.title??(stl.id == 'flow')?'Flow'.i18n:'Smart track list'.i18n
|
||||||
);
|
);
|
||||||
await playFromTrackList(stl.tracks, stl.tracks[0].id, queueSource);
|
await playFromTrackList(stl.tracks, stl.tracks[0].id, queueSource);
|
||||||
}
|
}
|
||||||
|
@ -233,6 +233,11 @@ class PlayerHelper {
|
||||||
await AudioService.customAction('queueSource', queueSource.toJson());
|
await AudioService.customAction('queueSource', queueSource.toJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Reorder tracks in queue
|
||||||
|
Future reorder(int oldIndex, int newIndex) async {
|
||||||
|
await AudioService.customAction('reorder', [oldIndex, newIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void backgroundTaskEntrypoint() async {
|
void backgroundTaskEntrypoint() async {
|
||||||
|
@ -562,6 +567,18 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||||
if (name == 'screenAndroidAuto' && _androidAutoCallback != null) {
|
if (name == 'screenAndroidAuto' && _androidAutoCallback != null) {
|
||||||
_androidAutoCallback.complete(jsonDecode(args).map<MediaItem>((m) => MediaItem.fromJson(m)).toList());
|
_androidAutoCallback.complete(jsonDecode(args).map<MediaItem>((m) => MediaItem.fromJson(m)).toList());
|
||||||
}
|
}
|
||||||
|
//Reorder tracks, args = [old, new]
|
||||||
|
if (name == 'reorder') {
|
||||||
|
await _audioSource.move(args[0], args[1]);
|
||||||
|
//Switch in queue
|
||||||
|
List<MediaItem> newQueue = List.from(_queue);
|
||||||
|
newQueue.removeAt(args[0]);
|
||||||
|
newQueue.insert(args[1], _queue[args[0]]);
|
||||||
|
_queue = newQueue;
|
||||||
|
//Update UI
|
||||||
|
AudioServiceBackground.setQueue(_queue);
|
||||||
|
_broadcastState();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,6 +245,9 @@ const language_en_us = {
|
||||||
"Minutes:": "Minutes:",
|
"Minutes:": "Minutes:",
|
||||||
"Hours:": "Hours:",
|
"Hours:": "Hours:",
|
||||||
"Cancel current timer": "Cancel current timer",
|
"Cancel current timer": "Cancel current timer",
|
||||||
"Current timer ends at": "Current timer ends at"
|
"Current timer ends at": "Current timer ends at",
|
||||||
|
|
||||||
|
//0.5.8 Strings:
|
||||||
|
"Smart track list": "Smart track list"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,7 @@ import 'package:freezer/ui/search.dart';
|
||||||
import 'package:i18n_extension/i18n_widget.dart';
|
import 'package:i18n_extension/i18n_widget.dart';
|
||||||
import 'package:move_to_background/move_to_background.dart';
|
import 'package:move_to_background/move_to_background.dart';
|
||||||
import 'package:freezer/translations.i18n.dart';
|
import 'package:freezer/translations.i18n.dart';
|
||||||
|
import 'package:quick_actions/quick_actions.dart';
|
||||||
import 'package:uni_links/uni_links.dart';
|
import 'package:uni_links/uni_links.dart';
|
||||||
|
|
||||||
import 'api/deezer.dart';
|
import 'api/deezer.dart';
|
||||||
|
@ -51,6 +52,7 @@ class _FreezerAppState extends State<FreezerApp> {
|
||||||
void initState() {
|
void initState() {
|
||||||
//Make update theme global
|
//Make update theme global
|
||||||
updateTheme = _updateTheme;
|
updateTheme = _updateTheme;
|
||||||
|
_updateTheme();
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +65,9 @@ class _FreezerAppState extends State<FreezerApp> {
|
||||||
setState(() {
|
setState(() {
|
||||||
settings.themeData;
|
settings.themeData;
|
||||||
});
|
});
|
||||||
|
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
|
||||||
|
systemNavigationBarColor: settings.themeData.bottomAppBarColor,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Locale _locale() {
|
Locale _locale() {
|
||||||
|
@ -158,28 +163,47 @@ class _MainScreenState extends State<MainScreen> with SingleTickerProviderStateM
|
||||||
void initState() {
|
void initState() {
|
||||||
navigatorKey = GlobalKey<NavigatorState>();
|
navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
//Setup URLs
|
//Start with parameters
|
||||||
setupUniLinks();
|
_setupUniLinks();
|
||||||
|
|
||||||
_loadPreloadInfo();
|
_loadPreloadInfo();
|
||||||
|
_prepareQuickActions();
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _prepareQuickActions() {
|
||||||
|
final QuickActions quickActions = QuickActions();
|
||||||
|
quickActions.initialize((type) {
|
||||||
|
if (type != null)
|
||||||
|
_startPreload(type);
|
||||||
|
});
|
||||||
|
|
||||||
|
//Actions
|
||||||
|
quickActions.setShortcutItems([
|
||||||
|
ShortcutItem(type: 'favorites', localizedTitle: 'Favorites'.i18n, icon: 'ic_favorites'),
|
||||||
|
ShortcutItem(type: 'flow', localizedTitle: 'Flow'.i18n, icon: 'ic_flow'),
|
||||||
|
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startPreload(String type) async {
|
||||||
|
await deezerAPI.authorize();
|
||||||
|
if (type == 'flow') {
|
||||||
|
await playerHelper.playFromSmartTrackList(SmartTrackList(id: 'flow'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type == 'favorites') {
|
||||||
|
Playlist p = await deezerAPI.fullPlaylist(deezerAPI.favoritesPlaylistId);
|
||||||
|
playerHelper.playFromPlaylist(p, p.tracks[0].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _loadPreloadInfo() async {
|
void _loadPreloadInfo() async {
|
||||||
String info = await DownloadManager.platform.invokeMethod('getPreloadInfo');
|
String info = await DownloadManager.platform.invokeMethod('getPreloadInfo');
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
//Used if started from android auto
|
//Used if started from android auto
|
||||||
|
|
||||||
await deezerAPI.authorize();
|
await deezerAPI.authorize();
|
||||||
if (info == 'flow') {
|
_startPreload(info);
|
||||||
await playerHelper.playFromSmartTrackList(SmartTrackList(id: 'flow'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (info == 'favorites') {
|
|
||||||
Playlist p = await deezerAPI.fullPlaylist(deezerAPI.favoritesPlaylistId);
|
|
||||||
playerHelper.playFromPlaylist(p, p.tracks[0].id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +214,7 @@ class _MainScreenState extends State<MainScreen> with SingleTickerProviderStateM
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupUniLinks() async {
|
void _setupUniLinks() async {
|
||||||
//Listen to URLs
|
//Listen to URLs
|
||||||
_urlLinkStream = getUriLinksStream().listen((Uri uri) {
|
_urlLinkStream = getUriLinksStream().listen((Uri uri) {
|
||||||
openScreenByURL(context, uri.toString());
|
openScreenByURL(context, uri.toString());
|
||||||
|
|
|
@ -560,6 +560,7 @@ class _SleepTimerDialogState extends State<SleepTimerDialog> {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:freezer/settings.dart';
|
import 'package:freezer/settings.dart';
|
||||||
|
|
||||||
import '../api/player.dart';
|
import '../api/player.dart';
|
||||||
|
@ -46,7 +47,12 @@ class PlayerBar extends StatelessWidget {
|
||||||
Container(
|
Container(
|
||||||
color: Theme.of(context).bottomAppBarColor,
|
color: Theme.of(context).bottomAppBarColor,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
onTap: () => Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => PlayerScreen())),
|
onTap: () {
|
||||||
|
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => PlayerScreen()));
|
||||||
|
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
|
||||||
|
systemNavigationBarColor: settings.themeData.scaffoldBackgroundColor,
|
||||||
|
));
|
||||||
|
},
|
||||||
leading: CachedImage(
|
leading: CachedImage(
|
||||||
width: 50,
|
width: 50,
|
||||||
height: 50,
|
height: 50,
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_screenutil/screenutil.dart';
|
import 'package:flutter_screenutil/screenutil.dart';
|
||||||
import 'package:freezer/api/deezer.dart';
|
import 'package:freezer/api/deezer.dart';
|
||||||
import 'package:freezer/api/player.dart';
|
import 'package:freezer/api/player.dart';
|
||||||
|
import 'package:freezer/settings.dart';
|
||||||
import 'package:freezer/translations.i18n.dart';
|
import 'package:freezer/translations.i18n.dart';
|
||||||
import 'package:freezer/ui/menu.dart';
|
import 'package:freezer/ui/menu.dart';
|
||||||
import 'package:freezer/ui/settings_screen.dart';
|
import 'package:freezer/ui/settings_screen.dart';
|
||||||
|
@ -25,6 +27,13 @@ class PlayerScreen extends StatefulWidget {
|
||||||
|
|
||||||
class _PlayerScreenState extends State<PlayerScreen> {
|
class _PlayerScreenState extends State<PlayerScreen> {
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
|
||||||
|
systemNavigationBarColor: settings.themeData.bottomAppBarColor,
|
||||||
|
));
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -578,7 +587,7 @@ class PlayerScreenTopRow extends StatelessWidget {
|
||||||
Container(
|
Container(
|
||||||
width: this.textWidth??ScreenUtil().setWidth(550),
|
width: this.textWidth??ScreenUtil().setWidth(550),
|
||||||
child: Text(
|
child: Text(
|
||||||
(short??false)?playerHelper.queueSource.text:'Playing from:'.i18n + ' ' + playerHelper.queueSource.text,
|
(short??false)?(playerHelper.queueSource.text??''):'Playing from:'.i18n + ' ' + (playerHelper.queueSource.text??''),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
|
@ -779,9 +788,13 @@ class _QueueScreenState extends State<QueueScreen> {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: ListView.builder(
|
body: ReorderableListView(
|
||||||
itemCount: AudioService.queue.length,
|
onReorder: (int oldIndex, int newIndex) async {
|
||||||
itemBuilder: (context, i) {
|
if (oldIndex == playerHelper.queueIndex) return;
|
||||||
|
await playerHelper.reorder(oldIndex, newIndex);
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
children: List.generate(AudioService.queue.length, (int i) {
|
||||||
Track t = Track.fromMediaItem(AudioService.queue[i]);
|
Track t = Track.fromMediaItem(AudioService.queue[i]);
|
||||||
return TrackTile(
|
return TrackTile(
|
||||||
t,
|
t,
|
||||||
|
@ -789,12 +802,9 @@ class _QueueScreenState extends State<QueueScreen> {
|
||||||
await AudioService.playFromMediaId(t.id);
|
await AudioService.playFromMediaId(t.id);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
onHold: () {
|
key: Key(t.id),
|
||||||
MenuSheet m = MenuSheet(context);
|
|
||||||
m.defaultTrackMenu(t);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
}),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:connectivity/connectivity.dart';
|
import 'package:connectivity/connectivity.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:freezer/api/cache.dart';
|
||||||
import 'package:freezer/api/download.dart';
|
import 'package:freezer/api/download.dart';
|
||||||
import 'package:freezer/api/player.dart';
|
import 'package:freezer/api/player.dart';
|
||||||
import 'package:freezer/ui/details_screens.dart';
|
import 'package:freezer/ui/details_screens.dart';
|
||||||
|
@ -63,6 +64,10 @@ class _SearchScreenState extends State<SearchScreen> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Add to search history
|
||||||
|
try {cache.searchHistory.remove(_query);} catch (_) {}
|
||||||
|
cache.searchHistory.add(_query);
|
||||||
|
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(builder: (context) => SearchResultsScreen(_query, offline: _offline,))
|
MaterialPageRoute(builder: (context) => SearchResultsScreen(_query, offline: _offline,))
|
||||||
);
|
);
|
||||||
|
@ -158,6 +163,19 @@ class _SearchScreenState extends State<SearchScreen> {
|
||||||
if (_loading)
|
if (_loading)
|
||||||
LinearProgressIndicator(),
|
LinearProgressIndicator(),
|
||||||
Divider(),
|
Divider(),
|
||||||
|
|
||||||
|
//History
|
||||||
|
if (cache.searchHistory.length > 0 && (_query??'').length == 0)
|
||||||
|
...List.generate(cache.searchHistory.length > 10 ? 10 : cache.searchHistory.length, (int i) => ListTile(
|
||||||
|
title: Text(cache.searchHistory[i]),
|
||||||
|
leading: Icon(Icons.history),
|
||||||
|
onTap: () {
|
||||||
|
setState(() => _query = cache.searchHistory[i]);
|
||||||
|
_submit(context);
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
|
||||||
|
//Suggestions
|
||||||
...List.generate((_suggestions??[]).length, (i) => ListTile(
|
...List.generate((_suggestions??[]).length, (i) => ListTile(
|
||||||
title: Text(_suggestions[i]),
|
title: Text(_suggestions[i]),
|
||||||
leading: Icon(Icons.search),
|
leading: Icon(Icons.search),
|
||||||
|
|
|
@ -714,6 +714,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.5"
|
version: "0.1.5"
|
||||||
|
quick_actions:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: quick_actions
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.0+10"
|
||||||
quiver:
|
quiver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -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.
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
version: 0.5.7+1
|
version: 0.5.8+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.8.0 <3.0.0"
|
sdk: ">=2.8.0 <3.0.0"
|
||||||
|
@ -69,6 +69,7 @@ dependencies:
|
||||||
uni_links: ^0.4.0
|
uni_links: ^0.4.0
|
||||||
share: ^0.6.5+2
|
share: ^0.6.5+2
|
||||||
numberpicker: ^1.2.1
|
numberpicker: ^1.2.1
|
||||||
|
quick_actions: ^0.4.0+10
|
||||||
|
|
||||||
audio_session: ^0.0.9
|
audio_session: ^0.0.9
|
||||||
audio_service:
|
audio_service:
|
||||||
|
|