refactor: extract shared mixins and helpers, drop dead abstractions

Introduces shared seams for paginated views, D-pad reorder, media control
routing, async singletons and the device method channel, then points the
open-coded copies at them.

Also removes unused models and duplicated provider/server plumbing, folds
the twice-implemented artifact store in the server, and factors the
repeated Flutter toolchain prologue in CI into a composite action.
This commit is contained in:
edde746
2026-07-26 06:09:48 +02:00
parent 61344f7862
commit 352b88109b
217 changed files with 6813 additions and 8773 deletions
@@ -1,31 +1,13 @@
part of '../../jellyfin_client.dart';
mixin _JellyfinPlaylistMethods on MediaServerCacheMixin {
JellyfinConnection get connection;
FailoverHttpClient get _http;
String? _absolutizeImagePath(String? path);
List<MediaItem> _mapItems(Iterable<Map<String, dynamic>> items);
mixin _JellyfinPlaylistMethods on _JellyfinClientInternals {
static const int _playlistsPageSize = 200;
@override
Future<List<MediaPlaylist>> fetchPlaylists({String playlistType = 'video', bool? smart}) async {
final all = <MediaPlaylist>[];
var start = 0;
while (true) {
final page = await fetchPlaylistsPage(
playlistType: playlistType,
smart: smart,
start: start,
size: _playlistsPageSize,
);
if (page.items.isEmpty) break;
all.addAll(page.items);
start += page.items.length;
if (start >= page.totalCount) break;
}
return all;
}
Future<List<MediaPlaylist>> fetchPlaylists({String playlistType = 'video', bool? smart}) => drainPages<MediaPlaylist>(
(start, size) => fetchPlaylistsPage(playlistType: playlistType, smart: smart, start: start, size: size),
pageSize: _playlistsPageSize,
);
@override
Future<LibraryPage<MediaPlaylist>> fetchPlaylistsPage({
@@ -70,15 +52,11 @@ mixin _JellyfinPlaylistMethods on MediaServerCacheMixin {
abort: abort,
);
throwIfHttpError(response);
final items = _itemsArray(response.data).map(_playlistFromJson).toList();
final rawTotal = response.data is Map<String, dynamic>
? (response.data as Map<String, dynamic>)['TotalRecordCount']
: null;
final fallbackTotal = fallbackPageTotal(offset: offset, itemCount: items.length, requestedSize: pageSize);
return LibraryPage<MediaPlaylist>(
items: items,
totalCount: rawTotal is int ? rawTotal : fallbackTotal,
return _pagedItems(
response.data,
offset: offset,
requestedSize: pageSize,
map: (raw) => raw.map(_playlistFromJson).toList(),
);
}
@@ -125,16 +103,7 @@ mixin _JellyfinPlaylistMethods on MediaServerCacheMixin {
abort: abort,
);
throwIfHttpError(response);
final items = _itemsArray(response.data);
final rawTotal = response.data is Map<String, dynamic>
? (response.data as Map<String, dynamic>)['TotalRecordCount']
: null;
final fallbackTotal = fallbackPageTotal(offset: offset, itemCount: items.length, requestedSize: pageSize);
return LibraryPage<MediaItem>(
items: _mapItems(items),
totalCount: rawTotal is int ? rawTotal : fallbackTotal,
offset: offset,
);
return _pagedItems(response.data, offset: offset, requestedSize: pageSize, map: _mapItems);
}
@override