improve download handling

This commit is contained in:
Fabian Freund
2026-05-26 06:23:31 +02:00
parent 038cb3dffc
commit da90d07318
13 changed files with 3803 additions and 2425 deletions
@@ -36,6 +36,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission-sdk-23 android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!-- Needed for uploading media files on devices with Android 13 and later. -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
@@ -45,6 +45,7 @@ import 'package:weblibre/presentation/hooks/menu_controller.dart';
import 'package:weblibre/presentation/widgets/failure_widget.dart';
import 'package:weblibre/presentation/widgets/uri_breadcrumb.dart';
import 'package:weblibre/presentation/widgets/url_icon.dart';
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
class Section extends MultiSliver {
static final _datePattern = DateFormat.MMMd().addPattern('Hm');
@@ -499,6 +500,34 @@ class HistoryScreen extends HookConsumerWidget {
onTap: (item) async {
if (selectedItems.value.isNotEmpty) {
toggleSelected(item);
} else if (isDownloadsMode) {
final filePath = item.title;
final file = filePath.mapNotNull(File.new);
if (file == null ||
await file.exists() != true) {
if (context.mounted) {
ui_helper.showErrorMessage(
context,
'Downloaded file not found',
);
}
return;
}
final opened = await GeckoDownloadsService()
.openDownloadedFile(
fileName: p.basename(file.path),
directoryPath: file.parent.path,
contentType: item.previewImageUrl,
);
if (!opened && context.mounted) {
ui_helper.showErrorMessage(
context,
'Could not open downloaded file',
);
}
} else {
await ref
.read(tabRepositoryProvider.notifier)
@@ -441,7 +441,7 @@ final class UnifiedPreferenceSettingsRepositoryProvider
}
String _$unifiedPreferenceSettingsRepositoryHash() =>
r'c544b5815ec676ddb6cde1ffeb8c9ef4a7dc4469';
r'f2153c826e2cba308cf3e8bdfe371e0b6b3e7dbd';
final class UnifiedPreferenceSettingsRepositoryFamily extends $Family
with
@@ -554,7 +554,7 @@ final class PreferenceSettingsGroupRepositoryProvider
}
String _$preferenceSettingsGroupRepositoryHash() =>
r'c8335b39c4c9fa95c4d415231b103a2feff97d26';
r'ae2b8553b895945d2a5c44a8ed24b8bbb00bb985';
final class PreferenceSettingsGroupRepositoryFamily extends $Family
with
+65 -1
View File
@@ -18,9 +18,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:weblibre/core/providers/router.dart';
import 'package:weblibre/domain/services/app_initialization.dart';
import 'package:weblibre/features/geckoview/domain/providers.dart';
import 'package:weblibre/features/sync/domain/entities/sync_repository_state.dart';
import 'package:weblibre/features/sync/domain/repositories/sync.dart';
import 'package:weblibre/features/web_search/domain/controllers/sandbox_capture_controller.dart';
@@ -99,7 +102,9 @@ class MainApp extends HookConsumerWidget {
disableAnimations: disableAnimations,
child: _SyncEventListener(
child: _SandboxCaptureErrorListener(
child: child ?? const SizedBox.shrink(),
child: _DownloadStoppedListener(
child: child ?? const SizedBox.shrink(),
),
),
),
);
@@ -142,6 +147,65 @@ class MainApp extends HookConsumerWidget {
}
}
class _DownloadStoppedListener extends HookConsumerWidget {
final Widget child;
const _DownloadStoppedListener({required this.child});
@override
Widget build(BuildContext context, WidgetRef ref) {
final downloadStoppedEvents = ref.watch(
eventServiceProvider.select((service) => service.downloadStoppedEvents),
);
useOnStreamChange(
downloadStoppedEvents,
onData: (download) {
switch (download.status) {
case DownloadStatus.completed:
ui_helper.showInfoMessage(
context,
'Download completed',
duration: const Duration(seconds: 6),
action: SnackBarAction(
label: 'Open',
onPressed: () async {
final opened = await GeckoDownloadsService()
.openDownloadedFile(
fileName: download.fileName ?? '',
directoryPath: download.directoryPath ?? '',
contentType: download.contentType,
);
if (!opened && context.mounted) {
ui_helper.showErrorMessage(
context,
'Could not open downloaded file',
);
}
},
),
);
case DownloadStatus.failed:
ui_helper.showErrorMessage(
context,
'Download failed: ${download.fileName ?? download.url}',
persist: true,
);
case DownloadStatus.initiated:
case DownloadStatus.downloading:
case DownloadStatus.paused:
case DownloadStatus.cancelled:
case null:
break;
}
},
);
return child;
}
}
MediaQueryData applyAppMediaQueryOverrides({
required MediaQueryData mediaQuery,
required double uiScaleFactor,