Compare commits

..

No commits in common. "50717ebbd3ad6fcfe0c4ecafa89c3f7c87d0101e" and "55e7a5e7e3f45df9a29961070a78e13ffc1f0052" have entirely different histories.

16 changed files with 479 additions and 657 deletions

View file

@ -990,17 +990,17 @@ class HomePageSection {
'grid-preview-two': HomePageSectionLayout.row, 'grid-preview-two': HomePageSectionLayout.row,
'grid': HomePageSectionLayout.grid, 'grid': HomePageSectionLayout.grid,
'slideshow': HomePageSectionLayout.slideshow, 'slideshow': HomePageSectionLayout.slideshow,
'horizontal-list': HomePageSectionLayout.horizontalList
}[json['layout'] ?? '']; }[json['layout'] ?? ''];
if (layout == null) { if (layout == null) {
_logger.warning('UNKNOWN LAYOUT: ${json['layout']}'); _logger.warning('UNKNOWN LAYOUT: ${json['layout']}');
return null; return null;
} }
_logger.fine(json['title']); _logger.fine('LAYOUT: $layout');
final items = ((json['items'] ?? []) as List) final items = <HomePageItem>[];
.map((e) => HomePageItem.fromPrivateJson(e as Map)) for (var i in (json['items'] ?? [])) {
.whereNotNull() HomePageItem? hpi = HomePageItem.fromPrivateJson(i);
.toList(growable: false); if (hpi != null) items.add(hpi);
}
return HomePageSection( return HomePageSection(
title: json['title'], title: json['title'],
items: items, items: items,
@ -1044,6 +1044,10 @@ class HomePageItem {
return HomePageItem( return HomePageItem(
type: HomePageItemType.ARTIST, type: HomePageItemType.ARTIST,
value: Artist.fromPrivateJson(json['data'])); value: Artist.fromPrivateJson(json['data']));
case 'channel':
return HomePageItem(
type: HomePageItemType.CHANNEL,
value: DeezerChannel.fromPrivateJson(json, false));
case 'album': case 'album':
return HomePageItem( return HomePageItem(
type: HomePageItemType.ALBUM, type: HomePageItemType.ALBUM,
@ -1052,18 +1056,10 @@ class HomePageItem {
return HomePageItem( return HomePageItem(
type: HomePageItemType.SHOW, type: HomePageItemType.SHOW,
value: Show.fromPrivateJson(json['data'])); value: Show.fromPrivateJson(json['data']));
case 'channel':
return HomePageItem(
type: HomePageItemType.CHANNEL,
value: DeezerChannel.fromPrivateJson(json, false));
case 'external-link': case 'external-link':
return HomePageItem( return HomePageItem(
type: HomePageItemType.EXTERNAL_LINK, type: HomePageItemType.EXTERNAL_LINK,
value: DeezerChannel.fromPrivateJson(json, true)); value: DeezerChannel.fromPrivateJson(json, true));
case 'track':
return HomePageItem(
type: HomePageItemType.TRACK,
value: Track.fromPrivateJson(json['data']));
default: default:
return null; return null;
} }
@ -1105,13 +1101,9 @@ class HomePageItem {
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
String type = this.type.name; String type = describeEnum(this.type);
return {'type': type, 'value': value.toJson()}; return {'type': type, 'value': value.toJson()};
} }
String toString() {
return type.name;
}
} }
@HiveType(typeId: 14) @HiveType(typeId: 14)
@ -1189,9 +1181,6 @@ enum HomePageItemType {
@HiveField(6) @HiveField(6)
EXTERNAL_LINK, EXTERNAL_LINK,
@HiveField(7)
TRACK, // for track mixes
} }
@HiveType(typeId: 3) @HiveType(typeId: 3)
@ -1204,10 +1193,6 @@ enum HomePageSectionLayout {
/// ROW but bigger /// ROW but bigger
@HiveField(2) @HiveField(2)
slideshow, slideshow,
/// Homepage song radios
@HiveField(3)
horizontalList,
} }
enum RepeatType { NONE, LIST, TRACK } enum RepeatType { NONE, LIST, TRACK }

View file

@ -255,7 +255,7 @@ class AudioPlayerTask extends BaseAudioHandler {
// listen for connectivity changes // listen for connectivity changes
_subscriptions.add(Connectivity() _subscriptions.add(Connectivity()
.onConnectivityChanged .onConnectivityChanged
.listen(_determineAudioQualityByResults)); .listen(_determineAudioQualityByResult));
} }
if (shouldLoadQueue) { if (shouldLoadQueue) {
@ -271,7 +271,7 @@ class AudioPlayerTask extends BaseAudioHandler {
try { try {
await Connectivity() await Connectivity()
.checkConnectivity() .checkConnectivity()
.then(_determineAudioQualityByResults); .then(_determineAudioQualityByResult);
return true; return true;
} catch (e) { } catch (e) {
_isConnectivityPluginAvailable = false; _isConnectivityPluginAvailable = false;
@ -282,13 +282,12 @@ class AudioPlayerTask extends BaseAudioHandler {
_logger.warning( _logger.warning(
'Couldn\'t determine connection! Falling back to other (which may use wifi quality)'); 'Couldn\'t determine connection! Falling back to other (which may use wifi quality)');
// on error, return dummy value -- error can happen on linux if not using NetworkManager, for example // on error, return dummy value -- error can happen on linux if not using NetworkManager, for example
_determineAudioQualityByResults([ConnectivityResult.other]); _determineAudioQualityByResult(ConnectivityResult.other);
return false; return false;
} }
/// Determines the [AudioQuality] to use according to [result] /// Determines the [AudioQuality] to use according to [result]
void _determineAudioQualityByResults(List<ConnectivityResult> results) { void _determineAudioQualityByResult(ConnectivityResult result) {
final result = results[0];
switch (result) { switch (result) {
case ConnectivityResult.mobile: case ConnectivityResult.mobile:
case ConnectivityResult.bluetooth: case ConnectivityResult.bluetooth:

View file

@ -31,7 +31,7 @@ import 'package:freezer/ui/search.dart';
import 'package:freezer/ui/settings_screen.dart'; import 'package:freezer/ui/settings_screen.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:hive_flutter/adapters.dart'; import 'package:hive_flutter/adapters.dart';
import 'package:i18n_extension/i18n_extension.dart'; import 'package:i18n_extension/i18n_widget.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:freezer/translations.i18n.dart'; import 'package:freezer/translations.i18n.dart';
import 'package:quick_actions/quick_actions.dart'; import 'package:quick_actions/quick_actions.dart';
@ -287,15 +287,14 @@ class _LoginMainWrapperState extends State<LoginMainWrapper> {
super.initState(); super.initState();
} }
Future<void> _logOut() async { Future _logOut() async {
await GetIt.instance<DeezerAPI>().logout(); await GetIt.instance<DeezerAPI>().logout();
setState(() {
settings.arl = null; settings.arl = null;
settings.offlineMode = false; settings.offlineMode = false;
});
await settings.save(); await settings.save();
await Cache.wipe(); await Cache.wipe();
setState(() {});
} }
@override @override

51
lib/ui/animated_bars.dart Normal file
View file

@ -0,0 +1,51 @@
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class AnimatedBars extends StatefulWidget {
final double size;
final Color? color;
const AnimatedBars({
super.key,
this.size = 24.0,
this.color,
});
@override
State<AnimatedBars> createState() => _AnimatedBarsState();
}
class _AnimatedBarsState extends State<AnimatedBars>
with TickerProviderStateMixin {
late final _controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 1000))
..repeat(reverse: true);
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final color = widget.color ?? Theme.of(context).colorScheme.onSurface;
const count = 3;
AnimatedIcons.search_ellipsis;
return SizedBox.square(
dimension: widget.size,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(
count,
(index) => SizedBox(
width: widget.size / count,
child: Align(
alignment: Alignment.bottomCenter,
child: Container(color: color),
),
)),
));
}
}

View file

@ -71,15 +71,7 @@ class FancyScaffoldState extends State<FancyScaffold>
begin: widget.bottomPanelHeight / MediaQuery.of(context).size.height, begin: widget.bottomPanelHeight / MediaQuery.of(context).size.height,
end: 1.0, end: 1.0,
).animate(dragController); ).animate(dragController);
return ValueListenableBuilder( return Stack(
valueListenable: statusNotifier,
builder: (context, state, child) => PopScope(
canPop: state == AnimationStatus.dismissed,
onPopInvoked: state == AnimationStatus.dismissed
? null
: (_) => dragController.fling(velocity: -1.0),
child: child!),
child: Stack(
children: [ children: [
Positioned.fill( Positioned.fill(
child: Scaffold( child: Scaffold(
@ -148,10 +140,15 @@ class FancyScaffoldState extends State<FancyScaffold>
builder: (context, state, _) => Stack( builder: (context, state, _) => Stack(
children: [ children: [
if (state != AnimationStatus.dismissed) if (state != AnimationStatus.dismissed)
Positioned.fill( PopScope(
canPop: false,
onPopInvoked: (_) =>
dragController.fling(velocity: -1.0),
child: Positioned.fill(
key: const Key('player_screen'), key: const Key('player_screen'),
child: widget.expandedPanel, child: widget.expandedPanel,
), ),
),
if (state != AnimationStatus.completed) if (state != AnimationStatus.completed)
Positioned( Positioned(
top: 0, top: 0,
@ -159,10 +156,8 @@ class FancyScaffoldState extends State<FancyScaffold>
left: 0, left: 0,
key: const Key('player_bar'), key: const Key('player_bar'),
child: FadeTransition( child: FadeTransition(
opacity: Tween(begin: 1.0, end: 0.0).animate( opacity: Tween(begin: 1.0, end: 0.0)
CurvedAnimation( .animate(dragController),
parent: dragController,
curve: const Interval(0.0, 0.25))),
child: SizedBox( child: SizedBox(
height: widget.bottomPanelHeight, height: widget.bottomPanelHeight,
child: widget.bottomPanel), child: widget.bottomPanel),
@ -176,7 +171,6 @@ class FancyScaffoldState extends State<FancyScaffold>
), ),
), ),
], ],
),
); );
} }

View file

@ -1,4 +1,3 @@
import 'package:collection/collection.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -211,7 +210,7 @@ class _HomePageWidgetState extends State<HomePageWidget> {
return HomePageGridSection(section); return HomePageGridSection(section);
case HomePageSectionLayout.slideshow: case HomePageSectionLayout.slideshow:
case HomePageSectionLayout.row: case HomePageSectionLayout.row:
case HomePageSectionLayout.horizontalList: default:
return HomepageRowSection(section); return HomepageRowSection(section);
} }
} }
@ -244,91 +243,73 @@ class _HomePageWidgetState extends State<HomePageWidget> {
} }
} }
class HomepageRowSection extends StatelessWidget { class HomepageRowSection extends StatefulWidget {
final HomePageSection section; final HomePageSection section;
const HomepageRowSection(this.section, {super.key}); const HomepageRowSection(this.section, {super.key});
Widget buildChild(BuildContext context, List<HomePageItem> items, @override
{bool hasMore = false}) { State<HomepageRowSection> createState() => _HomepageRowSectionState();
return Row(children: [
...items.map((item) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: HomePageItemWidget(item),
)),
if (hasMore)
TextButton(
onPressed: () => Navigator.of(context).pushRoute(
builder: (context) => HomePageScreen(
title: section.title!,
channel: DeezerChannel(target: section.pagePath),
),
),
child: Text('Show more'.i18n))
]);
} }
List<List<T>> _sliceInNLists<T>(List<T> source, int n) { class _HomepageRowSectionState extends State<HomepageRowSection> {
final List<List<T>> dest = List.generate(n, (_) => [], growable: false); final _controller = ScrollController();
int i = 0; @override
for (var item in source) { void dispose() {
dest[i].add(item); _controller.dispose();
if (++i == n) i = 0; super.dispose();
}
return dest;
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Widget child = switch (section.layout) {
HomePageSectionLayout.horizontalList => Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: _sliceInNLists(section.items!, 3)
.map((e) => buildChild(context, e))
.toList(growable: false)),
_ =>
buildChild(context, section.items!, hasMore: section.hasMore ?? false)
};
return ListTile( return ListTile(
title: InkWell( title: Text(
onTap: section.hasMore == true widget.section.title ?? '',
? () => Navigator.of(context).pushRoute(
builder: (context) => HomePageScreen(
title: section.title!,
channel: DeezerChannel(target: section.pagePath),
),
)
: null,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
section.title ?? '',
textAlign: TextAlign.left, textAlign: TextAlign.left,
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: style: const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w900),
const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w900),
)),
if (section.hasMore == true) ...[
const SizedBox(width: 16.0),
const Icon(Icons.keyboard_arrow_right),
],
],
),
), ),
subtitle: Scrollbar( subtitle: Scrollbar(
controller: _controller,
thickness: MainScreen.of(context).isDesktop ? null : 1.0, thickness: MainScreen.of(context).isDesktop ? null : 1.0,
child: SingleChildScrollView( child: SingleChildScrollView(
controller: _controller,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: child, child: Row(
children: List.generate(widget.section.items!.length + 1, (j) {
//Has more items
if (j == widget.section.items!.length) {
if (widget.section.hasMore ?? false) {
return TextButton(
child: Text(
'Show more'.i18n,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 20.0),
),
onPressed: () => Navigator.of(context).pushRoute(
builder: (context) => HomePageScreen(
title: widget.section.title!,
channel:
DeezerChannel(target: widget.section.pagePath),
), ),
), ),
); );
} }
return const SizedBox();
}
//Show item
HomePageItem item = widget.section.items![j];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: HomePageItemWidget(item),
);
}),
),
),
));
}
} }
class HomePageGridSection extends StatelessWidget { class HomePageGridSection extends StatelessWidget {
@ -387,7 +368,6 @@ class HomePageItemWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
switch (item.type) { switch (item.type) {
case HomePageItemType.SMARTTRACKLIST: case HomePageItemType.SMARTTRACKLIST:
return SmartTrackListTile( return SmartTrackListTile(
@ -464,16 +444,6 @@ class HomePageItemWidget extends StatelessWidget {
.pushRoute(builder: (context) => ShowScreen(item.value)); .pushRoute(builder: (context) => ShowScreen(item.value));
}, },
); );
case HomePageItemType.TRACK:
final track = item.value as Track;
return TrackCardTile.fromTrack(
track,
onTap: () => playerHelper.playSearchMixDeferred(track),
onSecondary: (details) =>
MenuSheet(context).defaultTrackMenu(track, details: details),
width:
mediaQuery.size.width > 530 ? null : mediaQuery.size.width * 0.75,
);
default: default:
return const SizedBox(height: 0, width: 0); return const SizedBox(height: 0, width: 0);
} }

View file

@ -293,8 +293,7 @@ class _LibraryTracksState extends State<LibraryTracks> {
return; return;
} }
ConnectivityResult connectivity = ConnectivityResult connectivity = await Connectivity().checkConnectivity();
(await Connectivity().checkConnectivity())[0];
if (connectivity != ConnectivityResult.none) { if (connectivity != ConnectivityResult.none) {
setState(() => _loading = true); setState(() => _loading = true);
int pos = tracks.length; int pos = tracks.length;

View file

@ -96,6 +96,7 @@ class _LoginOnOtherDeviceState extends State<LoginOnOtherDevice> {
} }
} }
print(res);
final data = res.data as Map; final data = res.data as Map;
if (!data['ok']) { if (!data['ok']) {
setState(() { setState(() {

View file

@ -1,21 +1,17 @@
import 'dart:async'; import 'dart:async';
import 'dart:collection';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:fading_edge_scrollview/fading_edge_scrollview.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:freezer/api/definitions.dart'; import 'package:freezer/api/definitions.dart';
import 'package:freezer/api/pipe_api.dart'; import 'package:freezer/api/pipe_api.dart';
import 'package:freezer/api/player/audio_handler.dart';
import 'package:freezer/api/player/player_helper.dart'; import 'package:freezer/api/player/player_helper.dart';
import 'package:freezer/settings.dart'; import 'package:freezer/settings.dart';
import 'package:freezer/translations.i18n.dart'; import 'package:freezer/translations.i18n.dart';
import 'package:freezer/ui/error.dart'; import 'package:freezer/ui/error.dart';
import 'package:freezer/ui/player_bar.dart'; import 'package:freezer/ui/player_bar.dart';
import 'package:freezer/ui/player_screen.dart'; import 'package:freezer/ui/player_screen.dart';
import 'package:mini_music_visualizer/mini_music_visualizer.dart';
class LyricsScreen extends StatelessWidget { class LyricsScreen extends StatelessWidget {
const LyricsScreen({super.key}); const LyricsScreen({super.key});
@ -25,10 +21,11 @@ class LyricsScreen extends StatelessWidget {
return PlayerScreenBackground( return PlayerScreenBackground(
enabled: settings.playerBackgroundOnLyrics, enabled: settings.playerBackgroundOnLyrics,
appBar: AppBar( appBar: AppBar(
title: Text('Lyrics'.i18n),
systemOverlayStyle: PlayerScreenBackground.getSystemUiOverlayStyle( systemOverlayStyle: PlayerScreenBackground.getSystemUiOverlayStyle(
context, context,
enabled: settings.playerBackgroundOnLyrics), enabled: settings.playerBackgroundOnLyrics),
forceMaterialTransparency: true, backgroundColor: Colors.transparent,
), ),
child: const Column( child: const Column(
children: [ children: [
@ -51,7 +48,7 @@ class _LyricsWidgetState extends State<LyricsWidget>
with WidgetsBindingObserver { with WidgetsBindingObserver {
StreamSubscription? _mediaItemSub; StreamSubscription? _mediaItemSub;
StreamSubscription? _positionSub; StreamSubscription? _positionSub;
int _currentIndex = -1; int? _currentIndex = -1;
Duration _nextOffset = Duration.zero; Duration _nextOffset = Duration.zero;
Duration _currentOffset = Duration.zero; Duration _currentOffset = Duration.zero;
String? _currentTrackId; String? _currentTrackId;
@ -71,9 +68,6 @@ class _LyricsWidgetState extends State<LyricsWidget>
bool _showTranslation = false; bool _showTranslation = false;
bool _availableTranslation = false; bool _availableTranslation = false;
// each individual lyric widget's height, either computed or cached
final _lyricHeights = HashMap<int, double>();
Future<void> _loadForId(String trackId) async { Future<void> _loadForId(String trackId) async {
if (_currentTrackId == trackId) return; if (_currentTrackId == trackId) return;
_currentTrackId = trackId; _currentTrackId = trackId;
@ -143,7 +137,7 @@ class _LyricsWidgetState extends State<LyricsWidget>
} else { } else {
final widgetHeight = _widgetConstraints!.maxHeight; final widgetHeight = _widgetConstraints!.maxHeight;
final minScroll = actualHeight * _currentIndex!; final minScroll = actualHeight * _currentIndex!;
scrollTo = minScroll + height / 2; scrollTo = minScroll - widgetHeight / 2 + height / 2;
} }
if (scrollTo < 0.0) scrollTo = 0.0; if (scrollTo < 0.0) scrollTo = 0.0;
@ -163,10 +157,10 @@ class _LyricsWidgetState extends State<LyricsWidget>
if (position < _nextOffset && position > _currentOffset) return; if (position < _nextOffset && position > _currentOffset) return;
_currentIndex = _currentIndex =
_lyrics?.lyrics?.lastIndexWhere((l) => l.offset! <= position) ?? -1; _lyrics?.lyrics?.lastIndexWhere((l) => l.offset! <= position);
if (_currentIndex < 0) return; if (_currentIndex! < 0) return;
if (_currentIndex < _lyrics!.lyrics!.length - 1) { if (_currentIndex! < _lyrics!.lyrics!.length - 1) {
// update nextOffset // update nextOffset
_nextOffset = _lyrics!.lyrics![_currentIndex! + 1].offset!; _nextOffset = _lyrics!.lyrics![_currentIndex! + 1].offset!;
} else { } else {
@ -214,6 +208,7 @@ class _LyricsWidgetState extends State<LyricsWidget>
@override @override
void didChangeAppLifecycleState(AppLifecycleState state) { void didChangeAppLifecycleState(AppLifecycleState state) {
print('fuck? $state');
switch (state) { switch (state) {
case AppLifecycleState.paused: case AppLifecycleState.paused:
_cancelSubscriptions(); _cancelSubscriptions();
@ -245,16 +240,30 @@ class _LyricsWidgetState extends State<LyricsWidget>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final textColor =
settings.playerBackgroundOnLyrics && settings.blurPlayerBackground
? Theme.of(context).brightness == Brightness.light
? Colors.black87
: Colors.white70
: Theme.of(context).colorScheme.onBackground;
return Stack( return Stack(
children: [ children: [
_error != null Column(children: [
? ErrorScreen(message: _error.toString()) if (_freeScroll && !_loading)
Center(
child: TextButton(
onPressed: () {
setState(() => _freeScroll = false);
_scrollToLyric();
},
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all(Colors.white)),
child: Text(
_currentIndex! >= 0
? (_lyrics?.lyrics?[_currentIndex!].text ?? '...')
: '...',
textAlign: TextAlign.center,
)),
),
Expanded(
child: _error != null
?
//Shouldn't really happen, empty lyrics have own text
ErrorScreen(message: _error.toString())
: :
// Loading lyrics // Loading lyrics
_loading _loading
@ -262,7 +271,8 @@ class _LyricsWidgetState extends State<LyricsWidget>
: LayoutBuilder(builder: (context, constraints) { : LayoutBuilder(builder: (context, constraints) {
_widgetConstraints = constraints; _widgetConstraints = constraints;
return NotificationListener<ScrollStartNotification>( return NotificationListener<ScrollStartNotification>(
onNotification: (notification) { onNotification:
(ScrollStartNotification notification) {
if (!_syncedLyrics) return false; if (!_syncedLyrics) return false;
final extentDiff = final extentDiff =
(notification.metrics.extentBefore - (notification.metrics.extentBefore -
@ -280,14 +290,9 @@ class _LyricsWidgetState extends State<LyricsWidget>
}, },
child: ScrollConfiguration( child: ScrollConfiguration(
behavior: _scrollBehavior, behavior: _scrollBehavior,
child: FadingEdgeScrollView.fromScrollView(
gradientFractionOnStart: 0.25,
gradientFractionOnEnd: 0.25,
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 8.0, horizontal: 8.0),
vertical: constraints.maxHeight / 2 -
height / 2),
controller: _controller, controller: _controller,
itemExtent: !_syncedLyrics itemExtent: !_syncedLyrics
? null ? null
@ -295,30 +300,8 @@ class _LyricsWidgetState extends State<LyricsWidget>
(_showTranslation (_showTranslation
? additionalTranslationHeight ? additionalTranslationHeight
: 0.0), : 0.0),
itemCount: _lyrics!.lyrics!.length + 1, itemCount: _lyrics!.lyrics!.length,
itemBuilder: (BuildContext context, int i) { itemBuilder: (BuildContext context, int i) {
if (i-- == 0) {
return SizedBox(
height: height,
child: Center(
child: SizedBox(
width: 8.0 * 3 + 6.0,
child: StreamBuilder<bool>(
initialData: playerHelper
.playing.valueOrNull,
stream: playerHelper.playing,
builder: (context, snapshot) {
return MiniMusicVisualizer(
color: textColor,
width: 8.0,
height: 16.0,
animate: (snapshot.data ??
false) &&
_currentIndex == -1,
);
}),
)));
}
return DecoratedBox( return DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius:
@ -329,22 +312,15 @@ class _LyricsWidgetState extends State<LyricsWidget>
), ),
child: InkWell( child: InkWell(
borderRadius: borderRadius:
BorderRadius.circular(12.0), BorderRadius.circular(8.0),
onTap: _syncedLyrics && onTap: _syncedLyrics &&
_lyrics!.id != null _lyrics!.id != null
? () => audioHandler.seek( ? () => audioHandler.seek(
_lyrics!.lyrics![i].offset!) _lyrics!.lyrics![i].offset!)
: null, : null,
child: Padding( child: Center(
padding:
const EdgeInsets.symmetric(
horizontal: 4.0,
//vertical: 24.0,
),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
Text( Text(
_lyrics!.lyrics![i].text!, _lyrics!.lyrics![i].text!,
@ -352,7 +328,6 @@ class _LyricsWidgetState extends State<LyricsWidget>
? TextAlign.center ? TextAlign.center
: TextAlign.start, : TextAlign.start,
style: TextStyle( style: TextStyle(
color: textColor,
fontSize: _syncedLyrics fontSize: _syncedLyrics
? 26.0 ? 26.0
: 20.0, : 20.0,
@ -382,14 +357,15 @@ class _LyricsWidgetState extends State<LyricsWidget>
), ),
))); )));
}, },
)))); )));
}), }),
),
]),
if (_availableTranslation) if (_availableTranslation)
Positioned( Align(
bottom: 16.0, alignment: Alignment.bottomCenter,
left: 0, child: Padding(
right: 0, padding: const EdgeInsets.only(bottom: 8.0),
child: Center(
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
setState(() => _showTranslation = !_showTranslation); setState(() => _showTranslation = !_showTranslation);
@ -399,18 +375,7 @@ class _LyricsWidgetState extends State<LyricsWidget>
child: Text(_showTranslation child: Text(_showTranslation
? 'Without translation'.i18n ? 'Without translation'.i18n
: 'With translation'.i18n)), : 'With translation'.i18n)),
), )),
),
if (_freeScroll)
Positioned(
bottom: 16.0,
right: 16.0,
child: FloatingActionButton(
child: const Icon(Icons.sync),
onPressed: () => setState(() {
_freeScroll = false;
_scrollToLyric();
})))
], ],
); );
} }

View file

@ -20,73 +20,70 @@ import 'package:url_launcher/url_launcher.dart';
class SliverTrackPersistentHeader extends SliverPersistentHeaderDelegate { class SliverTrackPersistentHeader extends SliverPersistentHeaderDelegate {
final Track track; final Track track;
static const kExtent = 84.0 + 16.0 * 2 + 2.0; final double extent;
const SliverTrackPersistentHeader(this.track); const SliverTrackPersistentHeader(this.track, {required this.extent});
@override @override
bool shouldRebuild(oldDelegate) => false; bool shouldRebuild(oldDelegate) => false;
@override @override
double get maxExtent => kExtent; double get maxExtent => extent;
@override @override
double get minExtent => kExtent; double get minExtent => extent;
@override @override
Widget build( Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) { BuildContext context, double shrinkOffset, bool overlapsContent) {
return DecoratedBox( return DecoratedBox(
decoration: decoration: BoxDecoration(color: Theme.of(context).cardColor),
BoxDecoration(color: Theme.of(context).colorScheme.background),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SizedBox(height: 16.0), const SizedBox(height: 16.0),
Row( Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[ children: <Widget>[
const SizedBox(width: 16.0),
Semantics( Semantics(
label: "Album art".i18n, label: "Album art".i18n,
image: true, image: true,
child: CachedImage( child: CachedImage(
url: track.albumArt!.full, url: track.albumArt!.full,
height: 86.0, height: 128,
width: 86.0, width: 128,
), ),
), ),
Expanded( SizedBox(
child: Padding( width: 240.0,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Text( Text(
track.title!, track.title!,
maxLines: 1, maxLines: 1,
textAlign: TextAlign.center, textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(
), fontSize: 22.0, fontWeight: FontWeight.bold),
Text(
track.album!.title!,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
maxLines: 1,
), ),
Text( Text(
track.artistString, track.artistString,
textAlign: TextAlign.center, textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,
style: Theme.of(context).textTheme.bodyMedium, style: const TextStyle(fontSize: 20.0),
), ),
const SizedBox(height: 8.0),
Text(
track.album!.title!,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
Text(track.durationString)
], ],
), ),
), ),
),
], ],
), ),
const SizedBox(height: 16.0), const SizedBox(height: 16.0),
@ -205,7 +202,6 @@ class MenuSheet {
builder: (context, scrollController) => Material( builder: (context, scrollController) => Material(
type: MaterialType.card, type: MaterialType.card,
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
color: Theme.of(context).colorScheme.background,
borderRadius: borderRadius:
const BorderRadius.vertical(top: Radius.circular(20.0)), const BorderRadius.vertical(top: Radius.circular(20.0)),
child: SafeArea( child: SafeArea(
@ -214,7 +210,8 @@ class MenuSheet {
slivers: [ slivers: [
SliverPersistentHeader( SliverPersistentHeader(
pinned: true, pinned: true,
delegate: SliverTrackPersistentHeader(track)), delegate: SliverTrackPersistentHeader(track,
extent: 128.0 + 16.0 + 16.0)),
SliverList( SliverList(
delegate: SliverChildListDelegate.fixed(options delegate: SliverChildListDelegate.fixed(options
.map((option) => ListTile( .map((option) => ListTile(

View file

@ -163,15 +163,12 @@ class PlayerScreenBackground extends StatelessWidget {
Widget _buildChild( Widget _buildChild(
BuildContext context, BackgroundProvider provider, Widget child) { BuildContext context, BackgroundProvider provider, Widget child) {
final isLightMode = Theme.of(context).brightness == Brightness.light;
return Stack(children: [ return Stack(children: [
if (provider.imageProvider != null || settings.colorGradientBackground) if (provider.imageProvider != null || settings.colorGradientBackground)
Positioned.fill( Positioned.fill(
child: provider.imageProvider != null child: provider.imageProvider != null
? DecoratedBox( ? DecoratedBox(
decoration: BoxDecoration( decoration: const BoxDecoration(color: Colors.black),
color: Color.lerp(provider.dominantColor,
isLightMode ? Colors.white : Colors.black, 0.75)),
child: ImageFiltered( child: ImageFiltered(
imageFilter: ImageFilter.blur( imageFilter: ImageFilter.blur(
tileMode: TileMode.decal, tileMode: TileMode.decal,
@ -183,7 +180,10 @@ class PlayerScreenBackground extends StatelessWidget {
image: DecorationImage( image: DecorationImage(
image: provider.imageProvider!, image: provider.imageProvider!,
fit: BoxFit.cover, fit: BoxFit.cover,
opacity: 0.35, colorFilter: ColorFilter.mode(
Colors.white
.withOpacity(settings.isDark ? 0.55 : 0.75),
BlendMode.dstATop),
)), )),
), ),
), ),
@ -195,8 +195,7 @@ class PlayerScreenBackground extends StatelessWidget {
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
colors: [ colors: [
if (provider.dominantColor != null) if (provider.dominantColor != null)
Color.lerp(provider.dominantColor, provider.dominantColor!,
isLightMode ? Colors.white : Colors.black, 0.5)!,
Theme.of(context).scaffoldBackgroundColor, Theme.of(context).scaffoldBackgroundColor,
], ],
stops: const [0.0, 0.6], stops: const [0.0, 0.6],
@ -370,7 +369,10 @@ class PlayerScreenDesktop extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0), padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: PlayerScreenTopRow( child: PlayerScreenTopRow(
textSize: 12.h, iconSize: 21.h, desktopMode: true), textSize: 12.h,
iconSize: 21.h,
showQueueButton: false,
),
), ),
Flexible( Flexible(
child: ConstrainedBox( child: ConstrainedBox(
@ -1047,7 +1049,7 @@ class _BigAlbumArtState extends State<BigAlbumArt> with WidgetsBindingObserver {
right: 16.0, right: 16.0,
child: LyricsButton( child: LyricsButton(
onTap: _pushLyrics, onTap: _pushLyrics,
size: 20.spMax, size: constraints.maxHeight / 20,
), ),
); );
}, },
@ -1119,15 +1121,14 @@ class PlayerScreenTopRow extends StatelessWidget {
final double? iconSize; final double? iconSize;
final double? textWidth; final double? textWidth;
final bool short; final bool short;
final bool desktopMode; final bool showQueueButton; // not needed on desktop
const PlayerScreenTopRow({ const PlayerScreenTopRow(
super.key, {super.key,
this.textSize, this.textSize,
this.iconSize, this.iconSize,
this.textWidth, this.textWidth,
this.short = false, this.short = false,
this.desktopMode = false, this.showQueueButton = true});
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -1174,9 +1175,20 @@ class PlayerScreenTopRow extends StatelessWidget {
.copyWith(fontSize: textSize ?? 38.sp))); .copyWith(fontSize: textSize ?? 38.sp)));
}), }),
), ),
desktopMode showQueueButton
? PlayerMenuButtonDesktop(size: size) ? IconButton(
: PlayerMenuButton(size: size) icon: Icon(
Icons.menu,
semanticLabel: "Queue".i18n,
),
iconSize: size,
splashRadius: size * 1.5,
onPressed: () => Navigator.of(context).pushRoute(
builder: (ctx) => QueueScreen(
closePlayer: FancyScaffold.of(context)!.closePanel,
)),
)
: SizedBox.square(dimension: size + 16.0),
], ],
); );
} }
@ -1317,19 +1329,7 @@ class BottomBarControls extends StatelessWidget {
textSize: size * 0.75, textSize: size * 0.75,
), ),
const Expanded(child: SizedBox()), const Expanded(child: SizedBox()),
if (!desktopMode) PlayerMenuButton(size: size),
IconButton(
icon: Icon(
Icons.playlist_play,
semanticLabel: "Queue".i18n,
),
iconSize: size,
splashRadius: size * 1.5,
onPressed: () => Navigator.of(context).pushRoute(
builder: (ctx) => QueueScreen(
closePlayer: FancyScaffold.of(context)!.closePanel,
)),
),
], ],
); );
} }
@ -1371,19 +1371,9 @@ class BottomBarControls extends StatelessWidget {
// toastLength: Toast.LENGTH_SHORT); // toastLength: Toast.LENGTH_SHORT);
// }, // },
// ), // ),
if (!desktopMode) desktopMode
IconButton( ? PlayerMenuButtonDesktop(size: iconSize)
icon: Icon( : PlayerMenuButton(size: iconSize)
Icons.playlist_play,
semanticLabel: "Queue".i18n,
),
iconSize: size,
splashRadius: size * 1.5,
onPressed: () => Navigator.of(context).pushRoute(
builder: (ctx) => QueueScreen(
closePlayer: FancyScaffold.of(context)!.closePanel,
)),
),
], ],
); );
} }

View file

@ -170,10 +170,11 @@ class _QueueListWidgetState extends State<QueueListWidget> {
trailing: ReorderableDragStartListener( trailing: ReorderableDragStartListener(
index: index, child: const Icon(Icons.drag_handle)), index: index, child: const Icon(Icons.drag_handle)),
onTap: () { onTap: () {
audioHandler.skipToQueueItem(index).then((value) {
if (widget.shouldPopOnTap) { if (widget.shouldPopOnTap) {
Navigator.pop(context); Navigator.of(context).pop();
} }
audioHandler.skipToQueueItem(index); });
}, },
onSecondary: (details) => menuSheet.defaultTrackMenu( onSecondary: (details) => menuSheet.defaultTrackMenu(
Track.fromMediaItem(mediaItem), Track.fromMediaItem(mediaItem),

View file

@ -8,7 +8,7 @@ import 'package:freezer/api/player/player_helper.dart';
import 'package:freezer/icons.dart'; import 'package:freezer/icons.dart';
import 'package:freezer/main.dart'; import 'package:freezer/main.dart';
import 'package:freezer/translations.i18n.dart'; import 'package:freezer/translations.i18n.dart';
import 'package:mini_music_visualizer/mini_music_visualizer.dart'; import 'package:freezer/ui/animated_bars.dart';
import '../api/definitions.dart'; import '../api/definitions.dart';
import 'cached_image.dart'; import 'cached_image.dart';
@ -23,93 +23,6 @@ VoidCallback? normalizeSecondary(SecondaryTapCallback? callback) {
return () => callback.call(null); return () => callback.call(null);
} }
class TrackCardTile extends StatelessWidget {
static const _kDefaultWidth = 424.0;
final VoidCallback onTap;
/// Hold or Right Click
final SecondaryTapCallback? onSecondary;
final Widget? trailing;
final String trackId;
final String title;
final String artist;
final String artUri;
final bool explicit;
final double? width;
const TrackCardTile({
required this.trackId,
required this.title,
required this.artist,
required this.artUri,
required this.explicit,
required this.onTap,
this.onSecondary,
this.trailing,
this.width,
super.key,
});
factory TrackCardTile.fromTrack(
Track track, {
required VoidCallback onTap,
SecondaryTapCallback? onSecondary,
Widget? trailing,
double? width,
}) =>
TrackCardTile(
trackId: track.id,
title: track.title!,
artist: track.artistString,
artUri: track.albumArt!.thumb,
explicit: track.explicit ?? false,
onSecondary: onSecondary,
onTap: onTap,
width: width,
trailing: trailing,
);
@override
Widget build(BuildContext context) {
return SizedBox(
width: width ?? _kDefaultWidth,
height: 64.0,
child: Card(
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: onTap,
onLongPress: normalizeSecondary(onSecondary),
onSecondaryTapUp: onSecondary,
child: Row(mainAxisSize: MainAxisSize.min, children: [
CachedImage(url: artUri, rounded: false),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, overflow: TextOverflow.ellipsis, maxLines: 1),
Text(
artist,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(color: Theme.of(context).disabledColor),
)
]),
),
),
]),
),
),
);
}
}
class TrackTile extends StatelessWidget { class TrackTile extends StatelessWidget {
final VoidCallback? onTap; final VoidCallback? onTap;
@ -200,39 +113,34 @@ class TrackTile extends StatelessWidget {
artist, artist,
maxLines: 1, maxLines: 1,
), ),
leading: StreamBuilder<MediaItem?>( leading: CachedImage(
initialData: audioHandler.mediaItem.value,
stream: audioHandler.mediaItem,
builder: (context, snapshot) {
final child = CachedImage(
url: artUri, url: artUri,
width: 48.0, width: 48.0,
height: 48.0, height: 48.0,
);
if (snapshot.data?.id == trackId) {
return Stack(children: [
child,
Positioned.fill(
child: DecoratedBox(
decoration: const BoxDecoration(color: Colors.black26),
child: Center(
child: SizedBox(
width: 18.0,
height: 16.0,
child: StreamBuilder<bool>(
stream: playerHelper.playing,
builder: (context, snapshot) {
return MiniMusicVisualizer(
color: Colors.white70,
animate: snapshot.data ?? false);
})),
)),
), ),
]); // StreamBuilder<MediaItem?>(
} // initialData: audioHandler.mediaItem.value,
return child; // stream: audioHandler.mediaItem,
}), // builder: (context, snapshot) {
// final child = CachedImage(
// url: artUri,
// width: 48.0,
// height: 48.0,
// );
//
// if (snapshot.data?.id == trackId) {
// return Stack(children: [
// child,
// const Positioned.fill(
// child: DecoratedBox(
// decoration: BoxDecoration(color: Colors.black26),
// child: AnimatedBars()),
// ),
// ]);
// }
//
// return child;
// }),
onTap: onTap, onTap: onTap,
onLongPress: normalizeSecondary(onSecondary), onLongPress: normalizeSecondary(onSecondary),
trailing: Row( trailing: Row(
@ -491,34 +399,21 @@ class PlaylistCardTile extends StatelessWidget {
class PlayItemButton extends StatelessWidget { class PlayItemButton extends StatelessWidget {
final FutureOr<void> Function() onTap; final FutureOr<void> Function() onTap;
final double size; final double size;
final bool filled; const PlayItemButton({required this.onTap, this.size = 32.0, super.key});
const PlayItemButton({
required this.onTap,
this.size = 32.0,
this.filled = true,
super.key,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox.square( return SizedBox.square(
dimension: size, dimension: size,
child: DecoratedBox( child: DecoratedBox(
decoration: filled decoration: const BoxDecoration(
? const BoxDecoration( shape: BoxShape.circle, color: Colors.white),
shape: BoxShape.circle, color: Colors.white)
: const BoxDecoration(),
child: Center( child: Center(
child: AwaitingButton( child: AwaitingButton(
onTap: onTap, onTap: onTap,
child: Icon( child: Icon(
Icons.play_arrow, Icons.play_arrow,
color: filled ? Colors.black : Colors.white, color: Colors.black,
shadows: filled
? null
: const [
Shadow(blurRadius: 2.0, color: Colors.black)
],
size: size / 1.5, size: size / 1.5,
))))); )))));
} }

View file

@ -26,7 +26,7 @@ import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin")) AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin"))

View file

@ -5,26 +5,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: _fe_analyzer_shared name: _fe_analyzer_shared
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "67.0.0" version: "61.0.0"
analyzer: analyzer:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: analyzer name: analyzer
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.4.1" version: "5.13.0"
archive: archive:
dependency: transitive dependency: transitive
description: description:
name: archive name: archive
sha256: "0763b45fa9294197a2885c8567927e2830ade852e5c896fd4ab7e0e348d0f373" sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.5.0" version: "3.4.10"
args: args:
dependency: transitive dependency: transitive
description: description:
@ -229,18 +229,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: connectivity_plus name: connectivity_plus
sha256: db7a4e143dc72cc3cb2044ef9b052a7ebfe729513e6a82943bc3526f784365b8 sha256: "224a77051d52a11fbad53dd57827594d3bd24f945af28bd70bab376d68d437f0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.3" version: "5.0.2"
connectivity_plus_platform_interface: connectivity_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: connectivity_plus_platform_interface name: connectivity_plus_platform_interface
sha256: b6a56efe1e6675be240de39107281d4034b64ac23438026355b4234042a35adb sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "1.2.4"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -269,10 +269,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: cross_file name: cross_file
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.4+1" version: "0.3.3+8"
crypto: crypto:
dependency: "direct main" dependency: "direct main"
description: description:
@ -371,7 +371,7 @@ packages:
source: hosted source: hosted
version: "2.0.5" version: "2.0.5"
fading_edge_scrollview: fading_edge_scrollview:
dependency: "direct main" dependency: transitive
description: description:
name: fading_edge_scrollview name: fading_edge_scrollview
sha256: c25c2231652ce774cc31824d0112f11f653881f43d7f5302c05af11942052031 sha256: c25c2231652ce774cc31824d0112f11f653881f43d7f5302c05af11942052031
@ -475,10 +475,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_cache_manager name: flutter_cache_manager
sha256: "395d6b7831f21f3b989ebedbb785545932adb9afe2622c1ffacf7f4b53a7e544" sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.3.2" version: "3.3.1"
flutter_cache_manager_hive: flutter_cache_manager_hive:
dependency: "direct main" dependency: "direct main"
description: description:
@ -508,10 +508,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: "8cdc719114ab1c86c64bb7a86d3a679674c3637edd229e3a994797d4a1504ce4" sha256: "55b9b229307a10974b26296ff29f2e132256ba4bd74266939118eaefa941cb00"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "17.1.0" version: "16.3.3"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
@ -683,10 +683,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.2.0"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -707,18 +707,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: i18n_extension name: i18n_extension
sha256: "514fca4f34e8eb73cd29d2938225bf139b1ff3cede462c0b2875f60f470e64b2" sha256: "813da89a434e617e3065a5d729f148a4d2d93d227e4d1ed4e77660eda6fa58c2"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "11.0.12" version: "10.0.3"
i18n_extension_core:
dependency: transitive
description:
name: i18n_extension_core
sha256: f45157bcd04d4fd88811e8e7c104a66ffbf77d16a6cf8526197c30cb78cbf1c4
url: "https://pub.dev"
source: hosted
version: "2.0.6"
i18n_extension_importer: i18n_extension_importer:
dependency: "direct main" dependency: "direct main"
description: description:
@ -763,26 +755,26 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: isar name: isar
sha256: "01de08cdea6e2060987e75bdedea46f244d9657fcd0e73b4372d6309b0e60f73" sha256: "99165dadb2cf2329d3140198363a7e7bff9bbd441871898a87e26914d25cf1ea"
url: "https://pub.isar-community.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.6" version: "3.1.0+1"
isar_flutter_libs: isar_flutter_libs:
dependency: "direct main" dependency: "direct main"
description: description:
name: isar_flutter_libs name: isar_flutter_libs
sha256: "268ef3fa93f213096f34e8f7f91ad16d920b33631fbdae317f3eb29f90e95b85" sha256: bc6768cc4b9c61aabff77152e7f33b4b17d2fc93134f7af1c3dd51500fe8d5e8
url: "https://pub.isar-community.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.6" version: "3.1.0+1"
isar_generator: isar_generator:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: isar_generator name: isar_generator
sha256: d2bbd77573c60ae1eddc323a20020223ba161e5a06e84143ea659411fb73b574 sha256: "76c121e1295a30423604f2f819bc255bc79f852f3bc8743a24017df6068ad133"
url: "https://pub.isar-community.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.6" version: "3.1.0+1"
js: js:
dependency: transitive dependency: transitive
description: description:
@ -951,14 +943,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.5" version: "1.0.5"
mini_music_visualizer:
dependency: "direct main"
description:
name: mini_music_visualizer
sha256: "095b3c5e12f4c045544432829a044a7fe1c5a7789a6d0003347c73d9bf3170cc"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
move_to_background: move_to_background:
dependency: "direct main" dependency: "direct main"
description: description:
@ -979,18 +963,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: network_info_plus name: network_info_plus
sha256: "5bd4b86e28fed5ed4e6ac7764133c031dfb7d3f46aa2a81b46f55038aa78ecc0" sha256: "4601b815b1c6a46d84839f65cd774a7d999738471d910fae00d813e9e98b04e1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.3" version: "4.1.0+1"
network_info_plus_platform_interface: network_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: network_info_plus_platform_interface name: network_info_plus_platform_interface
sha256: "2e193d61d3072ac17824638793d3b89c6d581ce90c11604f4ca87311b42f2706" sha256: "881f5029c5edaf19c616c201d3d8b366c5b1384afd5c1da5a49e4345de82fb8b"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "1.1.3"
nm: nm:
dependency: transitive dependency: transitive
description: description:
@ -1043,18 +1027,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: package_info_plus name: package_info_plus
sha256: "2c582551839386fa7ddbc7770658be7c0f87f388a4bff72066478f597c34d17f" sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "5.0.1"
package_info_plus_platform_interface: package_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_platform_interface name: package_info_plus_platform_interface
sha256: f49918f3433a3146047372f9d4f1f847511f2acd5cd030e1f44fe5a50036b70e sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "2.0.1"
palette_generator: palette_generator:
dependency: "direct main" dependency: "direct main"
description: description:
@ -1187,10 +1171,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: photo_view name: photo_view
sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e" sha256: "8036802a00bae2a78fc197af8a158e3e2f7b500561ed23b4c458107685e645bb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.15.0" version: "0.14.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -1324,18 +1308,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: share_plus name: share_plus
sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544 sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.0.0" version: "7.2.2"
share_plus_platform_interface: share_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: share_plus_platform_interface name: share_plus_platform_interface
sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4" sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "3.4.0"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
@ -1393,10 +1377,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: spotify name: spotify
sha256: d8effb9fa14731fe98fc5d111e0e1a0aac27b34366b5dcb8db79e6dd2219c000 sha256: "50bd5a07b580ee441d0b4d81227185ada768332c353671aa7555ea47cc68eb9e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.6+1" version: "0.13.5"
sprintf: sprintf:
dependency: transitive dependency: transitive
description: description:
@ -1617,10 +1601,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.2.3"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
@ -1665,10 +1649,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: wakelock_plus name: wakelock_plus
sha256: c8b7cc80f045533b40a0e6c9109905494e3cf32c0fbd5c62616998e0de44003f sha256: f268ca2116db22e57577fb99d52515a24bdc1d570f12ac18bb762361d43b043d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.4" version: "1.1.4"
wakelock_plus_platform_interface: wakelock_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -1689,18 +1673,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: web name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" version: "0.4.2"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.5" version: "2.4.3"
webview_flutter: webview_flutter:
dependency: "direct main" dependency: "direct main"
description: description:

View file

@ -35,45 +35,45 @@ dependencies:
path: ^1.6.4 path: ^1.6.4
sqflite: ^2.0.0+3 sqflite: ^2.0.0+3
permission_handler: ^11.2.0 permission_handler: ^11.2.0
intl: ^0.18.1 intl: ^0.18.0
filesize: ^2.0.1 filesize: ^2.0.1
fluttertoast: ^8.0.8 fluttertoast: ^8.0.8
palette_generator: ^0.3.0 palette_generator: ^0.3.0
flutter_material_color_picker: ^1.0.5 flutter_material_color_picker: ^1.0.5
country_pickers: ^2.0.0 country_pickers: ^2.0.0
move_to_background: ^1.0.1 move_to_background: ^1.0.1
flutter_local_notifications: ^17.1.0 flutter_local_notifications: ^16.3.2
collection: ^1.17.1 collection: ^1.17.1
random_string: ^2.0.1 random_string: ^2.0.1
async: ^2.6.1 async: ^2.6.1
html: ^0.15.0 html: ^0.15.0
flutter_screenutil: ^5.0.0+2 flutter_screenutil: ^5.0.0+2
marquee: ^2.2.0 marquee: ^2.2.0
flutter_cache_manager: ^3.3.2 flutter_cache_manager: ^3.0.0
cached_network_image: ^3.1.0 cached_network_image: ^3.1.0
i18n_extension: ^11.0.12 i18n_extension: ^10.0.3
url_launcher: ^6.0.5 url_launcher: ^6.0.5
uni_links: ^0.5.1 uni_links: ^0.5.1
numberpicker: ^2.1.1 numberpicker: ^2.1.1
quick_actions: ^1.0.5 quick_actions: ^1.0.5
photo_view: ^0.15.0 photo_view: ^0.14.0
scrobblenaut: scrobblenaut:
git: git:
url: https://github.com/Pato05/Scrobblenaut.git url: https://github.com/Pato05/Scrobblenaut.git
ref: main ref: main
open_file: ^3.0.3 open_file: ^3.0.3
version: ^3.0.2 version: ^3.0.2
wakelock_plus: ^1.2.4 wakelock_plus: ^1.1.1
google_fonts: ^6.1.0 google_fonts: ^6.1.0
audio_session: ^0.1.6 audio_session: ^0.1.6
audio_service: ^0.18.1 audio_service: ^0.18.1
provider: ^6.0.0 provider: ^6.0.0
hive_flutter: ^1.1.0 hive_flutter: ^1.1.0
connectivity_plus: ^6.0.3 connectivity_plus: ^5.0.2
share_plus: ^9.0.0 share_plus: ^7.0.2
disk_space_plus: ^0.2.3 disk_space_plus: ^0.2.3
dynamic_color: ^1.6.6 dynamic_color: ^1.6.6
package_info_plus: ^7.0.0 package_info_plus: ^5.0.1
encrypt: ^5.0.1 encrypt: ^5.0.1
dart_blowfish: dart_blowfish:
git: git:
@ -93,12 +93,8 @@ dependencies:
audio_service_mpris: ^0.1.3 audio_service_mpris: ^0.1.3
rxdart: ^0.27.7 rxdart: ^0.27.7
isar: isar: ^3.1.0+1
hosted: https://pub.isar-community.dev isar_flutter_libs: ^3.1.0+1
version: ^3.1.6
isar_flutter_libs:
hosted: https://pub.isar-community.dev
version: ^3.1.6
flutter_background_service: ^5.0.1 flutter_background_service: ^5.0.1
dio: ^5.3.3 dio: ^5.3.3
dio_cookie_manager: ^3.1.1 dio_cookie_manager: ^3.1.1
@ -106,7 +102,7 @@ dependencies:
git: https://github.com/Pato05/flutter_cache_manager_hive.git git: https://github.com/Pato05/flutter_cache_manager_hive.git
flex_color_picker: ^3.3.0 flex_color_picker: ^3.3.0
webview_flutter: ^4.4.4 webview_flutter: ^4.4.4
network_info_plus: ^5.0.3 network_info_plus: ^4.1.0+1
pointycastle: ^3.7.4 pointycastle: ^3.7.4
i18n_extension_importer: ^0.0.6 i18n_extension_importer: ^0.0.6
tray_manager: ^0.2.1 tray_manager: ^0.2.1
@ -114,22 +110,18 @@ dependencies:
get_it: ^7.6.7 get_it: ^7.6.7
freezed_annotation: freezed_annotation:
^2.4.1 ^2.4.1
mini_music_visualizer: ^1.1.0
fading_edge_scrollview: ^3.0.0
#deezcryptor: #deezcryptor:
#path: deezcryptor/ #path: deezcryptor/
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
analyzer: ^6.4.1 analyzer: ^5.13.0
json_serializable: ^6.0.1 json_serializable: ^6.0.1
build_runner: ^2.4.6 build_runner: ^2.4.6
hive_generator: ^2.0.0 hive_generator: ^2.0.0
flutter_lints: ^3.0.1 flutter_lints: ^3.0.1
isar_generator: isar_generator: ^3.1.0+1
hosted: https://pub.isar-community.dev
version: ^3.1.0
freezed: ^2.4.7 freezed: ^2.4.7
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the