Skip to content

Commit a666209

Browse files
authored
chore: linux video and cached network image (#1630)
1 parent 84a212c commit a666209

12 files changed

Lines changed: 129 additions & 54 deletions

File tree

lib/common/view/clean_up_caches.dart

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:cached_network_image_ce/cached_network_image.dart';
12
import 'package:flutter/rendering.dart';
23
import 'package:flutter_it/flutter_it.dart';
34

@@ -16,8 +17,11 @@ void clearLocalCovers() {
1617
);
1718
}
1819

19-
void clearImageCache() {
20-
PaintingBinding.instance.imageCache.clear();
21-
22-
PaintingBinding.instance.imageCache.clearLiveImages();
20+
Future<void> clearNetworkImageCache() async {
21+
// Evict the in-memory image cache.
22+
PaintingBinding.instance.imageCache
23+
..clear()
24+
..clearLiveImages();
25+
// Empty the on-disk cache used by CachedNetworkImage.
26+
await CachedNetworkImageProvider.defaultCacheManager.emptyCache();
2327
}

lib/common/view/safe_network_image.dart

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:cached_network_image_ce/cached_network_image.dart';
12
import 'package:flutter/material.dart';
23
import 'package:flutter_it/flutter_it.dart';
34

@@ -58,12 +59,6 @@ class SafeNetworkImage extends StatelessWidget with WatchItMixin {
5859
Icon(Iconz.musicNote, size: height != null ? height! * 0.7 : null),
5960
);
6061

61-
if (url == null ||
62-
url!.isEmpty ||
63-
_failedUrls.contains(url!) ||
64-
(Uri.tryParse(url!)?.host.isEmpty ?? false))
65-
return fallBack;
66-
6762
final errorWidget = Center(
6863
child:
6964
this.errorWidget ??
@@ -74,29 +69,35 @@ class SafeNetworkImage extends StatelessWidget with WatchItMixin {
7469
),
7570
);
7671

77-
return Image.network(
78-
url!,
72+
if (url == null ||
73+
url!.isEmpty ||
74+
_failedUrls.contains(url!) ||
75+
(Uri.tryParse(url!)?.host.isEmpty ?? false))
76+
return errorWidget;
77+
78+
return CachedNetworkImage(
79+
cacheManager: _cacheManager,
80+
imageUrl: url!,
7981
height: height,
8082
width: width,
81-
cacheHeight: cacheHeight,
82-
cacheWidth: cacheWidth,
83+
memCacheHeight: cacheHeight,
84+
memCacheWidth: cacheWidth,
85+
maxWidthDiskCache: cacheWidth,
86+
maxHeightDiskCache: cacheHeight,
8387
fit: fit,
8488
filterQuality: filterQuality,
85-
headers: httpHeaders,
86-
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
87-
if (frame != null) {
88-
onImageLoaded?.call(NetworkImage(url!));
89-
}
90-
if (wasSynchronouslyLoaded) {
91-
return child;
92-
}
93-
return AnimatedOpacity(
94-
opacity: frame == null ? 0 : 1,
95-
duration: const Duration(milliseconds: 300),
96-
curve: Curves.easeInOut,
97-
child: child,
89+
httpHeaders: httpHeaders,
90+
imageBuilder: (context, imageProvider) {
91+
onImageLoaded?.call(imageProvider);
92+
return Image(
93+
image: imageProvider,
94+
height: height,
95+
width: width,
96+
fit: fit,
97+
filterQuality: filterQuality,
9898
);
9999
},
100+
placeholder: (context, url) => fallbackWidget ?? fallBack,
100101
errorBuilder: (context, error, _) {
101102
final message = switch (error.runtimeType) {
102103
final NetworkImageLoadException e => switch (e.statusCode) {
@@ -121,3 +122,12 @@ class SafeNetworkImage extends StatelessWidget with WatchItMixin {
121122
);
122123
}
123124
}
125+
126+
final _cacheManager = DefaultCacheManager(
127+
stalePeriod: const Duration(days: 1),
128+
maxNrOfCacheObjects: 100,
129+
connectionParameters: ConnectionParameters(
130+
connectionTimeout: const Duration(seconds: 10),
131+
requestTimeout: const Duration(seconds: 30),
132+
),
133+
);

lib/common/view/sliver_local_audio_page.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'adaptive_multi_layout_body.dart';
1313
import 'audio_page_header.dart';
1414
import 'audio_page_type.dart';
1515
import 'avatar_play_button.dart';
16+
import 'clean_up_caches.dart';
1617
import 'header_bar.dart';
1718
import 'no_search_result_page.dart';
1819
import 'progress.dart';
@@ -60,6 +61,7 @@ class SliverLocalAudioPage extends StatelessWidget {
6061

6162
@override
6263
Widget build(BuildContext context) {
64+
callOnceAfterThisBuild((context) => clearNetworkImageCache());
6365
return Scaffold(
6466
appBar: HeaderBar(
6567
title: isMobile ? null : Text(pageTitle ?? ''),

lib/extensions/object_x.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:io';
22

33
import 'package:dio/dio.dart';
4+
import 'package:flutter/material.dart';
45
import 'package:podcast_search/podcast_search.dart';
56

67
import '../app/app_config.dart';
@@ -17,6 +18,9 @@ extension ObjectX on Object? {
1718
AppLocalizations l10n, {
1819
String? title,
1920
}) => switch (this) {
21+
NetworkImageLoadException() => l10n.errorDetails(
22+
(this as NetworkImageLoadException).statusCode.toString(),
23+
),
2024
FindRadioBrowserHostsTimeoutException() =>
2125
l10n.lookUpRadioBrowserHostsTimouted,
2226
LookUpRadioBrowserHostsException() => l10n.lookUpRadioBrowserHostsFailed,

lib/local_audio/view/local_audio_page.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class LocalAudioPage extends StatelessWidget with WatchItMixin {
3434

3535
@override
3636
Widget build(BuildContext context) {
37-
callOnceAfterThisBuild((context) => clearImageCache());
37+
callOnceAfterThisBuild((context) => clearNetworkImageCache());
3838

3939
registerHandler(
4040
select: (LocalAudioManager m) => m.areTracksSyncedCommand.results,

lib/local_audio/view/playlist_page.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import '../../common/data/audio_type.dart';
1111
import '../../common/view/adaptive_multi_layout_body.dart';
1212
import '../../common/view/audio_page_header.dart';
1313
import '../../common/view/audio_page_type.dart';
14+
import '../../common/view/clean_up_caches.dart';
1415
import '../../common/view/local_audio_tile.dart';
1516
import '../../common/view/genre_bar.dart';
1617
import '../../common/view/header_bar.dart';
@@ -40,6 +41,7 @@ class PlaylistPage extends StatelessWidget with WatchItMixin {
4041

4142
@override
4243
Widget build(BuildContext context) {
44+
callOnceAfterThisBuild((context) => clearNetworkImageCache());
4345
final isInitializing = watchValue(
4446
(LocalAudioManager m) => m.initAudiosCommand.isRunning,
4547
);

lib/lyrics/view/lyrics_viewer.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import '../../common/data/retry_capsule.dart';
1111
import '../../common/manager/retry_manager.dart';
1212
import '../../common/view/common_widgets.dart';
1313
import '../../common/view/error_retry_body.dart';
14+
import '../../common/view/progress.dart';
1415
import '../../common/view/theme.dart';
1516
import '../../common/view/ui_constants.dart';
1617
import '../../extensions/build_context_x.dart';
@@ -115,7 +116,7 @@ class _PlayerLyricsState extends State<_PlayerLyrics> {
115116
Expanded(
116117
child: watchValue((LyricsManager m) => m.command.results).toWidget(
117118
whileRunning: (lastResult, param) =>
118-
const Center(child: CircularProgressIndicator()),
119+
const Center(child: Progress()),
119120
onError: (error, lastResult, param) => Center(
120121
child: ErrorRetryBody(
121122
error: error,

lib/player/view/full_window_video_player.dart

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import '../../common/view/ui_constants.dart';
1010
import '../../extensions/build_context_x.dart';
1111
import '../../extensions/platform_x.dart';
1212
import '../manager/player_manager.dart';
13-
import 'full_window_player_top_controls.dart';
1413
import 'player_main_controls.dart';
1514
import 'player_track.dart';
1615
import 'player_view.dart';
@@ -152,20 +151,6 @@ class _LinuxFullWindowVideoPlayerState
152151
avatarColor: Colors.black.withAlpha(150),
153152
),
154153
),
155-
Positioned(
156-
top: 0,
157-
right: 0,
158-
child: AnimatedOpacity(
159-
duration: const Duration(milliseconds: 200),
160-
opacity: _hovered ? 1 : 0,
161-
child: OverlayContainer(
162-
child: FullWindowPlayerTopControls(
163-
iconColor: widget.iconColor,
164-
video: true,
165-
),
166-
),
167-
),
168-
),
169154
if (isFullscreen(context))
170155
Positioned(
171156
bottom: 0,
@@ -186,6 +171,25 @@ class _LinuxFullWindowVideoPlayerState
186171
),
187172
),
188173
),
174+
Positioned(
175+
bottom: 0,
176+
child: AnimatedOpacity(
177+
duration: const Duration(milliseconds: 200),
178+
opacity: _hovered ? 1 : 0,
179+
child: const Padding(
180+
padding: EdgeInsets.only(
181+
bottom: kLargestSpace,
182+
left: kLargestSpace,
183+
right: kLargestSpace,
184+
),
185+
child: SizedBox(
186+
height: kLargestSpace,
187+
width: 600,
188+
child: PlayerTrack(),
189+
),
190+
),
191+
),
192+
),
189193
],
190194
),
191195
);

lib/podcasts/view/podcast_collection_card.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ class PodcastCollectionCard extends StatelessWidget with WatchItMixin {
3636
fit: BoxFit.cover,
3737
height: audioCardDimension,
3838
width: audioCardDimension,
39-
fallbackWidget: Icon(Iconz.podcast, size: 70),
39+
fallbackWidget: const Center(),
40+
errorWidget: Center(
41+
child: Icon(Iconz.podcast, size: audioCardDimension * 0.7),
42+
),
4043
),
4144
bottom: AudioCardBottom(
4245
style: hasUpdated

lib/search/view/podcast_card.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import '../../app/routing_manager.dart';
99
import '../../common/view/audio_card.dart';
1010
import '../../common/view/audio_card_bottom.dart';
1111
import '../../common/view/audio_page_type.dart';
12+
import '../../common/view/icons.dart';
1213
import '../../common/view/safe_network_image.dart';
1314
import '../../common/view/theme.dart';
1415
import '../../extensions/build_context_x.dart';
@@ -33,6 +34,10 @@ class PodcastCard extends StatelessWidget with WatchItMixin {
3334
width: audioCardDimension,
3435
cacheHeight: audioCardDimension.toInt(),
3536
cacheWidth: audioCardDimension.toInt(),
37+
fallbackWidget: const Center(),
38+
errorWidget: Center(
39+
child: Icon(Iconz.podcast, size: audioCardDimension * 0.7),
40+
),
3641
),
3742
onPlay: feedUrl == null
3843
? null

0 commit comments

Comments
 (0)