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

View file

@ -255,7 +255,7 @@ class AudioPlayerTask extends BaseAudioHandler {
// listen for connectivity changes
_subscriptions.add(Connectivity()
.onConnectivityChanged
.listen(_determineAudioQualityByResults));
.listen(_determineAudioQualityByResult));
}
if (shouldLoadQueue) {
@ -271,7 +271,7 @@ class AudioPlayerTask extends BaseAudioHandler {
try {
await Connectivity()
.checkConnectivity()
.then(_determineAudioQualityByResults);
.then(_determineAudioQualityByResult);
return true;
} catch (e) {
_isConnectivityPluginAvailable = false;
@ -282,13 +282,12 @@ class AudioPlayerTask extends BaseAudioHandler {
_logger.warning(
'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
_determineAudioQualityByResults([ConnectivityResult.other]);
_determineAudioQualityByResult(ConnectivityResult.other);
return false;
}
/// Determines the [AudioQuality] to use according to [result]
void _determineAudioQualityByResults(List<ConnectivityResult> results) {
final result = results[0];
void _determineAudioQualityByResult(ConnectivityResult result) {
switch (result) {
case ConnectivityResult.mobile:
case ConnectivityResult.bluetooth:

View file

@ -31,7 +31,7 @@ import 'package:freezer/ui/search.dart';
import 'package:freezer/ui/settings_screen.dart';
import 'package:get_it/get_it.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:freezer/translations.i18n.dart';
import 'package:quick_actions/quick_actions.dart';
@ -287,15 +287,14 @@ class _LoginMainWrapperState extends State<LoginMainWrapper> {
super.initState();
}
Future<void> _logOut() async {
Future _logOut() async {
await GetIt.instance<DeezerAPI>().logout();
settings.arl = null;
settings.offlineMode = false;
setState(() {
settings.arl = null;
settings.offlineMode = false;
});
await settings.save();
await Cache.wipe();
setState(() {});
}
@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,112 +71,106 @@ class FancyScaffoldState extends State<FancyScaffold>
begin: widget.bottomPanelHeight / MediaQuery.of(context).size.height,
end: 1.0,
).animate(dragController);
return ValueListenableBuilder(
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: [
Positioned.fill(
child: Scaffold(
body: widget.navigationRail != null
? Row(children: [
widget.navigationRail!,
const VerticalDivider(
indent: 0.0,
endIndent: 0.0,
width: 2.0,
),
Expanded(child: widget.body)
])
: widget.body,
drawer: widget.drawer,
bottomNavigationBar: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: widget.bottomPanelHeight),
if (widget.bottomNavigationBar != null)
SizeTransition(
axisAlignment: -1.0,
sizeFactor:
Tween(begin: 1.0, end: 0.0).animate(sizeAnimation),
child: widget.bottomNavigationBar,
return Stack(
children: [
Positioned.fill(
child: Scaffold(
body: widget.navigationRail != null
? Row(children: [
widget.navigationRail!,
const VerticalDivider(
indent: 0.0,
endIndent: 0.0,
width: 2.0,
),
],
),
Expanded(child: widget.body)
])
: widget.body,
drawer: widget.drawer,
bottomNavigationBar: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: widget.bottomPanelHeight),
if (widget.bottomNavigationBar != null)
SizeTransition(
axisAlignment: -1.0,
sizeFactor:
Tween(begin: 1.0, end: 0.0).animate(sizeAnimation),
child: widget.bottomNavigationBar,
),
],
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: AnimatedBuilder(
animation: sizeAnimation,
builder: (context, child) {
final x = 1.0 - sizeAnimation.value;
return Padding(
padding: EdgeInsets.only(
bottom: (defaultBottomPadding /*+ 8.0*/) * x,
//right: 8.0 * x,
//left: 8.0 * x,
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: AnimatedBuilder(
animation: sizeAnimation,
builder: (context, child) {
final x = 1.0 - sizeAnimation.value;
return Padding(
padding: EdgeInsets.only(
bottom: (defaultBottomPadding /*+ 8.0*/) * x,
//right: 8.0 * x,
//left: 8.0 * x,
),
child: child,
);
},
child: ValueListenableBuilder(
valueListenable: statusNotifier,
builder: (context, state, child) {
return GestureDetector(
onVerticalDragEnd: _onVerticalDragEnd,
onVerticalDragUpdate: _onVerticalDragUpdate,
child: child,
);
},
child: ValueListenableBuilder(
valueListenable: statusNotifier,
builder: (context, state, child) {
return GestureDetector(
onVerticalDragEnd: _onVerticalDragEnd,
onVerticalDragUpdate: _onVerticalDragUpdate,
child: child,
);
},
child: SizeTransition(
sizeFactor: sizeAnimation,
axisAlignment: -1.0,
axis: Axis.vertical,
child: SizedBox(
height: screenHeight,
width: MediaQuery.of(context).size.width,
child: ValueListenableBuilder(
valueListenable: statusNotifier,
builder: (context, state, _) => Stack(
children: [
if (state != AnimationStatus.dismissed)
Positioned.fill(
child: SizeTransition(
sizeFactor: sizeAnimation,
axisAlignment: -1.0,
axis: Axis.vertical,
child: SizedBox(
height: screenHeight,
width: MediaQuery.of(context).size.width,
child: ValueListenableBuilder(
valueListenable: statusNotifier,
builder: (context, state, _) => Stack(
children: [
if (state != AnimationStatus.dismissed)
PopScope(
canPop: false,
onPopInvoked: (_) =>
dragController.fling(velocity: -1.0),
child: Positioned.fill(
key: const Key('player_screen'),
child: widget.expandedPanel,
),
if (state != AnimationStatus.completed)
Positioned(
top: 0,
right: 0,
left: 0,
key: const Key('player_bar'),
child: FadeTransition(
opacity: Tween(begin: 1.0, end: 0.0).animate(
CurvedAnimation(
parent: dragController,
curve: const Interval(0.0, 0.25))),
child: SizedBox(
height: widget.bottomPanelHeight,
child: widget.bottomPanel),
),
),
if (state != AnimationStatus.completed)
Positioned(
top: 0,
right: 0,
left: 0,
key: const Key('player_bar'),
child: FadeTransition(
opacity: Tween(begin: 1.0, end: 0.0)
.animate(dragController),
child: SizedBox(
height: widget.bottomPanelHeight,
child: widget.bottomPanel),
),
],
),
),
],
),
)),
),
),
)),
),
),
],
),
),
],
);
}

View file

@ -1,4 +1,3 @@
import 'package:collection/collection.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -211,7 +210,7 @@ class _HomePageWidgetState extends State<HomePageWidget> {
return HomePageGridSection(section);
case HomePageSectionLayout.slideshow:
case HomePageSectionLayout.row:
case HomePageSectionLayout.horizontalList:
default:
return HomepageRowSection(section);
}
}
@ -244,90 +243,72 @@ class _HomePageWidgetState extends State<HomePageWidget> {
}
}
class HomepageRowSection extends StatelessWidget {
class HomepageRowSection extends StatefulWidget {
final HomePageSection section;
const HomepageRowSection(this.section, {super.key});
Widget buildChild(BuildContext context, List<HomePageItem> items,
{bool hasMore = false}) {
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))
]);
}
@override
State<HomepageRowSection> createState() => _HomepageRowSectionState();
}
List<List<T>> _sliceInNLists<T>(List<T> source, int n) {
final List<List<T>> dest = List.generate(n, (_) => [], growable: false);
class _HomepageRowSectionState extends State<HomepageRowSection> {
final _controller = ScrollController();
int i = 0;
for (var item in source) {
dest[i].add(item);
if (++i == n) i = 0;
}
return dest;
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
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(
title: InkWell(
onTap: section.hasMore == true
? () => 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,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style:
const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w900),
)),
if (section.hasMore == true) ...[
const SizedBox(width: 16.0),
const Icon(Icons.keyboard_arrow_right),
],
],
title: Text(
widget.section.title ?? '',
textAlign: TextAlign.left,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w900),
),
),
subtitle: Scrollbar(
thickness: MainScreen.of(context).isDesktop ? null : 1.0,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: child,
),
),
);
subtitle: Scrollbar(
controller: _controller,
thickness: MainScreen.of(context).isDesktop ? null : 1.0,
child: SingleChildScrollView(
controller: _controller,
scrollDirection: Axis.horizontal,
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),
);
}),
),
),
));
}
}
@ -387,7 +368,6 @@ class HomePageItemWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
switch (item.type) {
case HomePageItemType.SMARTTRACKLIST:
return SmartTrackListTile(
@ -464,16 +444,6 @@ class HomePageItemWidget extends StatelessWidget {
.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:
return const SizedBox(height: 0, width: 0);
}

View file

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

View file

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

View file

@ -1,21 +1,17 @@
import 'dart:async';
import 'dart:collection';
import 'package:audio_service/audio_service.dart';
import 'package:dio/dio.dart';
import 'package:fading_edge_scrollview/fading_edge_scrollview.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:freezer/api/definitions.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/settings.dart';
import 'package:freezer/translations.i18n.dart';
import 'package:freezer/ui/error.dart';
import 'package:freezer/ui/player_bar.dart';
import 'package:freezer/ui/player_screen.dart';
import 'package:mini_music_visualizer/mini_music_visualizer.dart';
class LyricsScreen extends StatelessWidget {
const LyricsScreen({super.key});
@ -25,10 +21,11 @@ class LyricsScreen extends StatelessWidget {
return PlayerScreenBackground(
enabled: settings.playerBackgroundOnLyrics,
appBar: AppBar(
title: Text('Lyrics'.i18n),
systemOverlayStyle: PlayerScreenBackground.getSystemUiOverlayStyle(
context,
enabled: settings.playerBackgroundOnLyrics),
forceMaterialTransparency: true,
backgroundColor: Colors.transparent,
),
child: const Column(
children: [
@ -51,7 +48,7 @@ class _LyricsWidgetState extends State<LyricsWidget>
with WidgetsBindingObserver {
StreamSubscription? _mediaItemSub;
StreamSubscription? _positionSub;
int _currentIndex = -1;
int? _currentIndex = -1;
Duration _nextOffset = Duration.zero;
Duration _currentOffset = Duration.zero;
String? _currentTrackId;
@ -71,9 +68,6 @@ class _LyricsWidgetState extends State<LyricsWidget>
bool _showTranslation = 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 {
if (_currentTrackId == trackId) return;
_currentTrackId = trackId;
@ -143,7 +137,7 @@ class _LyricsWidgetState extends State<LyricsWidget>
} else {
final widgetHeight = _widgetConstraints!.maxHeight;
final minScroll = actualHeight * _currentIndex!;
scrollTo = minScroll + height / 2;
scrollTo = minScroll - widgetHeight / 2 + height / 2;
}
if (scrollTo < 0.0) scrollTo = 0.0;
@ -163,10 +157,10 @@ class _LyricsWidgetState extends State<LyricsWidget>
if (position < _nextOffset && position > _currentOffset) return;
_currentIndex =
_lyrics?.lyrics?.lastIndexWhere((l) => l.offset! <= position) ?? -1;
if (_currentIndex < 0) return;
_lyrics?.lyrics?.lastIndexWhere((l) => l.offset! <= position);
if (_currentIndex! < 0) return;
if (_currentIndex < _lyrics!.lyrics!.length - 1) {
if (_currentIndex! < _lyrics!.lyrics!.length - 1) {
// update nextOffset
_nextOffset = _lyrics!.lyrics![_currentIndex! + 1].offset!;
} else {
@ -214,6 +208,7 @@ class _LyricsWidgetState extends State<LyricsWidget>
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print('fuck? $state');
switch (state) {
case AppLifecycleState.paused:
_cancelSubscriptions();
@ -245,49 +240,59 @@ class _LyricsWidgetState extends State<LyricsWidget>
@override
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(
children: [
_error != null
? ErrorScreen(message: _error.toString())
:
// Loading lyrics
_loading
? const Center(child: CircularProgressIndicator())
: LayoutBuilder(builder: (context, constraints) {
_widgetConstraints = constraints;
return NotificationListener<ScrollStartNotification>(
onNotification: (notification) {
if (!_syncedLyrics) return false;
final extentDiff =
(notification.metrics.extentBefore -
notification.metrics.extentAfter)
.abs();
// avoid accidental clicks
const extentThreshold = 10.0;
if (extentDiff >= extentThreshold &&
!_animatedScroll &&
!_loading &&
!_freeScroll) {
setState(() => _freeScroll = true);
}
return false;
},
child: ScrollConfiguration(
behavior: _scrollBehavior,
child: FadingEdgeScrollView.fromScrollView(
gradientFractionOnStart: 0.25,
gradientFractionOnEnd: 0.25,
Column(children: [
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
? const Center(child: CircularProgressIndicator())
: LayoutBuilder(builder: (context, constraints) {
_widgetConstraints = constraints;
return NotificationListener<ScrollStartNotification>(
onNotification:
(ScrollStartNotification notification) {
if (!_syncedLyrics) return false;
final extentDiff =
(notification.metrics.extentBefore -
notification.metrics.extentAfter)
.abs();
// avoid accidental clicks
const extentThreshold = 10.0;
if (extentDiff >= extentThreshold &&
!_animatedScroll &&
!_loading &&
!_freeScroll) {
setState(() => _freeScroll = true);
}
return false;
},
child: ScrollConfiguration(
behavior: _scrollBehavior,
child: ListView.builder(
padding: EdgeInsets.symmetric(
horizontal: 8.0,
vertical: constraints.maxHeight / 2 -
height / 2),
padding: const EdgeInsets.symmetric(
horizontal: 8.0),
controller: _controller,
itemExtent: !_syncedLyrics
? null
@ -295,30 +300,8 @@ class _LyricsWidgetState extends State<LyricsWidget>
(_showTranslation
? additionalTranslationHeight
: 0.0),
itemCount: _lyrics!.lyrics!.length + 1,
itemCount: _lyrics!.lyrics!.length,
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(
decoration: BoxDecoration(
borderRadius:
@ -329,22 +312,15 @@ class _LyricsWidgetState extends State<LyricsWidget>
),
child: InkWell(
borderRadius:
BorderRadius.circular(12.0),
BorderRadius.circular(8.0),
onTap: _syncedLyrics &&
_lyrics!.id != null
? () => audioHandler.seek(
_lyrics!.lyrics![i].offset!)
: null,
child: Padding(
padding:
const EdgeInsets.symmetric(
horizontal: 4.0,
//vertical: 24.0,
),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
_lyrics!.lyrics![i].text!,
@ -352,7 +328,6 @@ class _LyricsWidgetState extends State<LyricsWidget>
? TextAlign.center
: TextAlign.start,
style: TextStyle(
color: textColor,
fontSize: _syncedLyrics
? 26.0
: 20.0,
@ -382,35 +357,25 @@ class _LyricsWidgetState extends State<LyricsWidget>
),
)));
},
))));
}),
if (_availableTranslation)
Positioned(
bottom: 16.0,
left: 0,
right: 0,
child: Center(
child: ElevatedButton(
onPressed: () {
setState(() => _showTranslation = !_showTranslation);
SchedulerBinding.instance
.addPostFrameCallback((_) => _scrollToLyric());
},
child: Text(_showTranslation
? 'Without 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();
})))
]),
if (_availableTranslation)
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: ElevatedButton(
onPressed: () {
setState(() => _showTranslation = !_showTranslation);
SchedulerBinding.instance
.addPostFrameCallback((_) => _scrollToLyric());
},
child: Text(_showTranslation
? 'Without translation'.i18n
: 'With translation'.i18n)),
)),
],
);
}

View file

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

View file

@ -163,15 +163,12 @@ class PlayerScreenBackground extends StatelessWidget {
Widget _buildChild(
BuildContext context, BackgroundProvider provider, Widget child) {
final isLightMode = Theme.of(context).brightness == Brightness.light;
return Stack(children: [
if (provider.imageProvider != null || settings.colorGradientBackground)
Positioned.fill(
child: provider.imageProvider != null
? DecoratedBox(
decoration: BoxDecoration(
color: Color.lerp(provider.dominantColor,
isLightMode ? Colors.white : Colors.black, 0.75)),
decoration: const BoxDecoration(color: Colors.black),
child: ImageFiltered(
imageFilter: ImageFilter.blur(
tileMode: TileMode.decal,
@ -183,7 +180,10 @@ class PlayerScreenBackground extends StatelessWidget {
image: DecorationImage(
image: provider.imageProvider!,
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,
colors: [
if (provider.dominantColor != null)
Color.lerp(provider.dominantColor,
isLightMode ? Colors.white : Colors.black, 0.5)!,
provider.dominantColor!,
Theme.of(context).scaffoldBackgroundColor,
],
stops: const [0.0, 0.6],
@ -370,7 +369,10 @@ class PlayerScreenDesktop extends StatelessWidget {
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: PlayerScreenTopRow(
textSize: 12.h, iconSize: 21.h, desktopMode: true),
textSize: 12.h,
iconSize: 21.h,
showQueueButton: false,
),
),
Flexible(
child: ConstrainedBox(
@ -1047,7 +1049,7 @@ class _BigAlbumArtState extends State<BigAlbumArt> with WidgetsBindingObserver {
right: 16.0,
child: LyricsButton(
onTap: _pushLyrics,
size: 20.spMax,
size: constraints.maxHeight / 20,
),
);
},
@ -1119,15 +1121,14 @@ class PlayerScreenTopRow extends StatelessWidget {
final double? iconSize;
final double? textWidth;
final bool short;
final bool desktopMode;
const PlayerScreenTopRow({
super.key,
this.textSize,
this.iconSize,
this.textWidth,
this.short = false,
this.desktopMode = false,
});
final bool showQueueButton; // not needed on desktop
const PlayerScreenTopRow(
{super.key,
this.textSize,
this.iconSize,
this.textWidth,
this.short = false,
this.showQueueButton = true});
@override
Widget build(BuildContext context) {
@ -1174,9 +1175,20 @@ class PlayerScreenTopRow extends StatelessWidget {
.copyWith(fontSize: textSize ?? 38.sp)));
}),
),
desktopMode
? PlayerMenuButtonDesktop(size: size)
: PlayerMenuButton(size: size)
showQueueButton
? IconButton(
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,
),
const Expanded(child: SizedBox()),
if (!desktopMode)
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,
)),
),
PlayerMenuButton(size: size),
],
);
}
@ -1371,19 +1371,9 @@ class BottomBarControls extends StatelessWidget {
// toastLength: Toast.LENGTH_SHORT);
// },
// ),
if (!desktopMode)
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,
)),
),
desktopMode
? PlayerMenuButtonDesktop(size: iconSize)
: PlayerMenuButton(size: iconSize)
],
);
}

View file

@ -170,10 +170,11 @@ class _QueueListWidgetState extends State<QueueListWidget> {
trailing: ReorderableDragStartListener(
index: index, child: const Icon(Icons.drag_handle)),
onTap: () {
if (widget.shouldPopOnTap) {
Navigator.pop(context);
}
audioHandler.skipToQueueItem(index);
audioHandler.skipToQueueItem(index).then((value) {
if (widget.shouldPopOnTap) {
Navigator.of(context).pop();
}
});
},
onSecondary: (details) => menuSheet.defaultTrackMenu(
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/main.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 'cached_image.dart';
@ -23,93 +23,6 @@ VoidCallback? normalizeSecondary(SecondaryTapCallback? callback) {
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 {
final VoidCallback? onTap;
@ -200,39 +113,34 @@ class TrackTile extends StatelessWidget {
artist,
maxLines: 1,
),
leading: StreamBuilder<MediaItem?>(
initialData: audioHandler.mediaItem.value,
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,
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);
})),
)),
),
]);
}
return child;
}),
leading: CachedImage(
url: artUri,
width: 48.0,
height: 48.0,
),
// StreamBuilder<MediaItem?>(
// initialData: audioHandler.mediaItem.value,
// 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,
onLongPress: normalizeSecondary(onSecondary),
trailing: Row(
@ -491,34 +399,21 @@ class PlaylistCardTile extends StatelessWidget {
class PlayItemButton extends StatelessWidget {
final FutureOr<void> Function() onTap;
final double size;
final bool filled;
const PlayItemButton({
required this.onTap,
this.size = 32.0,
this.filled = true,
super.key,
});
const PlayItemButton({required this.onTap, this.size = 32.0, super.key});
@override
Widget build(BuildContext context) {
return SizedBox.square(
dimension: size,
child: DecoratedBox(
decoration: filled
? const BoxDecoration(
shape: BoxShape.circle, color: Colors.white)
: const BoxDecoration(),
decoration: const BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
child: Center(
child: AwaitingButton(
onTap: onTap,
child: Icon(
Icons.play_arrow,
color: filled ? Colors.black : Colors.white,
shadows: filled
? null
: const [
Shadow(blurRadius: 2.0, color: Colors.black)
],
color: Colors.black,
size: size / 1.5,
)))));
}

View file

@ -26,7 +26,7 @@ import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
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"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin"))

View file

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

View file

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