Skip to content

Commit 19bbf11

Browse files
committed
feat: pull to refresh m3u playlists
for main playlists page and m3u playlist subpage ref #125
1 parent 4177354 commit 19bbf11

File tree

5 files changed

+486
-330
lines changed

5 files changed

+486
-330
lines changed

lib/base/pull_to_refresh.dart

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:get/get.dart';
3+
4+
import 'package:namida/core/icon_fonts/broken_icons.dart';
5+
6+
mixin PullToRefreshMixin<T extends StatefulWidget> on State<T> implements TickerProvider {
7+
final turnsTween = Tween<double>(begin: 0.0, end: 1.0);
8+
late final animation = AnimationController(vsync: this, duration: Duration.zero);
9+
AnimationController get animation2;
10+
11+
final _minTrigger = 20;
12+
13+
num get pullNormalizer => 20;
14+
15+
bool onScrollNotification(ScrollMetricsNotification notification) {
16+
final pixels = notification.metrics.pixels;
17+
if (pixels < -_minTrigger) {
18+
animation.animateTo(((pixels + _minTrigger).abs() / pullNormalizer).clamp(0, 1));
19+
} else if (animation.value > 0) {
20+
animation.animateTo(0);
21+
}
22+
return true;
23+
}
24+
25+
double _distanceDragged = 0;
26+
bool onVerticalDragUpdate(double dy) {
27+
_distanceDragged -= dy;
28+
if (_distanceDragged < -_minTrigger) {
29+
animation.animateTo(((_distanceDragged + _minTrigger).abs() / pullNormalizer).clamp(0, 1));
30+
} else if (animation.value > 0) {
31+
animation.animateTo(0);
32+
}
33+
return true;
34+
}
35+
36+
void onVerticalDragFinish() {
37+
animation.animateTo(0, duration: const Duration(milliseconds: 100));
38+
_distanceDragged = 0;
39+
}
40+
41+
Future<void> showRefreshingAnimation(Future<void> Function() whileExecuting) async {
42+
animation2.repeat();
43+
await whileExecuting();
44+
await animation2.fling();
45+
animation2.stop();
46+
}
47+
48+
Widget get pullToRefreshWidget {
49+
return Positioned(
50+
left: 0,
51+
right: 0,
52+
child: AnimatedBuilder(
53+
animation: animation,
54+
child: CircleAvatar(
55+
radius: 24.0,
56+
backgroundColor: context.theme.colorScheme.secondaryContainer,
57+
child: const Icon(Broken.refresh_2),
58+
),
59+
builder: (context, circleAvatar) {
60+
final p = animation.value;
61+
if (!animation2.isAnimating && p == 0) return const SizedBox();
62+
const multiplier = 4.5;
63+
const minus = multiplier / 3;
64+
return Padding(
65+
padding: EdgeInsets.only(top: 12.0 + p * 128.0),
66+
child: Transform.rotate(
67+
angle: (p * multiplier) - minus,
68+
child: AnimatedBuilder(
69+
animation: animation2,
70+
child: circleAvatar,
71+
builder: (context, circleAvatar) {
72+
return Opacity(
73+
opacity: animation2.status == AnimationStatus.forward ? 1.0 : p,
74+
child: RotationTransition(
75+
key: const Key('rotatie'),
76+
turns: turnsTween.animate(animation2),
77+
child: circleAvatar,
78+
),
79+
);
80+
},
81+
),
82+
),
83+
);
84+
},
85+
),
86+
);
87+
}
88+
89+
@override
90+
void dispose() {
91+
animation.dispose();
92+
super.dispose();
93+
}
94+
}

lib/controller/playlist_controller.dart

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ class PlaylistController extends PlaylistManager<TrackWithDate> {
249249
// -- similar name exists, so m3u overrides it
250250
// -- this can produce in an outdated playlist version in cache
251251
// -- which will be seen if the m3u file got deleted/renamed
252-
await _prepareM3UPlaylists();
252+
await prepareM3UPlaylists();
253253
}
254254

255255
Future<List<Track>> readM3UFiles(Set<String> filesPaths) async {
@@ -270,19 +270,23 @@ class PlaylistController extends PlaylistManager<TrackWithDate> {
270270
return listy;
271271
}
272272

273-
Future<void> _prepareM3UPlaylists() async {
273+
Future<void> prepareM3UPlaylists({Set<String> forPaths = const {}}) async {
274274
final allAvailableDirectories = await Indexer.inst.getAvailableDirectories(strictNoMedia: false);
275275

276-
final parameters = {
277-
'allAvailableDirectories': allAvailableDirectories,
278-
'directoriesToExclude': <String>[],
279-
'extensions': kM3UPlaylistsExtensions,
280-
'respectNoMedia': false,
281-
};
282-
283-
final mapResult = await getFilesTypeIsolate.thready(parameters);
276+
late final Set<String> allPaths;
277+
if (forPaths.isNotEmpty) {
278+
allPaths = forPaths;
279+
} else {
280+
final parameters = {
281+
'allAvailableDirectories': allAvailableDirectories,
282+
'directoriesToExclude': <String>[],
283+
'extensions': kM3UPlaylistsExtensions,
284+
'respectNoMedia': false,
285+
};
286+
final mapResult = await getFilesTypeIsolate.thready(parameters);
287+
allPaths = mapResult['allPaths'] as Set<String>;
288+
}
284289

285-
final allPaths = mapResult['allPaths'] as Set<String>;
286290
final resBoth = await _parseM3UPlaylistFiles.thready({
287291
'paths': allPaths,
288292
'libraryTracks': allTracksInLibrary,

0 commit comments

Comments
 (0)