feat: workmanager
This commit is contained in:
parent
0cd1a54c0d
commit
a18dc7feb0
7 changed files with 158 additions and 84 deletions
|
@ -2,7 +2,7 @@
|
|||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:minWidth="100dp"
|
||||
android:minHeight="100dp"
|
||||
android:updatePeriodMillis="600000"
|
||||
android:updatePeriodMillis="900000"
|
||||
android:initialLayout="@layout/slideshow_layout"
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:widgetCategory="home_screen">
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import UIKit
|
||||
import Flutter
|
||||
import UIKit
|
||||
import workmanager
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
|
@ -9,20 +10,22 @@ import Flutter
|
|||
) -> Bool {
|
||||
var flutter_native_splash = 1
|
||||
UIApplication.shared.isStatusBarHidden = false
|
||||
UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60 * 15))
|
||||
|
||||
if #available(iOS 10.0, *) {
|
||||
UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
|
||||
}
|
||||
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
WorkmanagerPlugin.registerTask(withIdentifier: "slideshow-widget")
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
override func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
override func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
signal(SIGPIPE, SIG_IGN)
|
||||
}
|
||||
|
||||
override func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
}
|
||||
override func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
signal(SIGPIPE, SIG_IGN)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>com.transistorsoft.fetch</string>
|
||||
<string>slideshow-widget</string>
|
||||
</array>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
|
|
|
@ -68,3 +68,5 @@ const galleryGridSpacing = 2.0;
|
|||
const searchSectionLimit = 7;
|
||||
|
||||
bool isInternalUser = false;
|
||||
|
||||
const iOSGroupID = "group.io.ente.frame.SlideshowWidget";
|
||||
|
|
100
lib/main.dart
100
lib/main.dart
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import "dart:math";
|
||||
|
||||
import "package:adaptive_theme/adaptive_theme.dart";
|
||||
import 'package:background_fetch/background_fetch.dart';
|
||||
|
@ -9,6 +10,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import "package:flutter/rendering.dart";
|
||||
import "package:flutter_displaymode/flutter_displaymode.dart";
|
||||
import 'package:home_widget/home_widget.dart' as hw;
|
||||
import 'package:logging/logging.dart';
|
||||
import "package:media_kit/media_kit.dart";
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
@ -18,6 +20,7 @@ import 'package:photos/core/constants.dart';
|
|||
import 'package:photos/core/error-reporting/super_logging.dart';
|
||||
import 'package:photos/core/errors.dart';
|
||||
import 'package:photos/core/network/network.dart';
|
||||
import "package:photos/db/files_db.dart";
|
||||
import 'package:photos/db/upload_locks_db.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
import "package:photos/l10n/l10n.dart";
|
||||
|
@ -46,7 +49,10 @@ import 'package:photos/ui/tools/lock_screen.dart';
|
|||
import 'package:photos/utils/crypto_util.dart';
|
||||
import 'package:photos/utils/file_uploader.dart';
|
||||
import 'package:photos/utils/local_settings.dart';
|
||||
import "package:photos/utils/preload_util.dart";
|
||||
import "package:photos/utils/thumbnail_util.dart";
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import "package:workmanager/workmanager.dart";
|
||||
|
||||
final _logger = Logger("main");
|
||||
|
||||
|
@ -60,10 +66,103 @@ const kBGPushTimeout = Duration(seconds: 28);
|
|||
const kFGTaskDeathTimeoutInMicroseconds = 5000000;
|
||||
const kBackgroundLockLatency = Duration(seconds: 3);
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
void initSlideshowWidget() {
|
||||
Workmanager().executeTask(
|
||||
(taskName, inputData) async {
|
||||
await _init(true, via: 'runViaSlideshowWidget');
|
||||
|
||||
final collectionID =
|
||||
await FavoritesService.instance.getFavoriteCollectionID();
|
||||
if (collectionID == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await hw.HomeWidget.setAppGroupId(iOSGroupID);
|
||||
final res = await FilesDB.instance.getFilesInCollection(
|
||||
collectionID,
|
||||
galleryLoadStartTime,
|
||||
galleryLoadEndTime,
|
||||
);
|
||||
|
||||
final previousGeneratedId =
|
||||
await hw.HomeWidget.getWidgetData<int>("home_widget_last_img");
|
||||
final files = res.files
|
||||
.where((element) => element.generatedID != previousGeneratedId);
|
||||
final randomNumber = Random().nextInt(files.length);
|
||||
final randomFile = files.elementAt(randomNumber);
|
||||
final cachedThumbnail = await getThumbnailFromServer(randomFile);
|
||||
|
||||
var img = Image.memory(cachedThumbnail);
|
||||
var imgProvider = img.image;
|
||||
await PreloadImage.loadImage(imgProvider);
|
||||
|
||||
img = Image.memory(cachedThumbnail);
|
||||
imgProvider = img.image;
|
||||
final image = await decodeImageFromList(cachedThumbnail);
|
||||
final width = image.width.toDouble();
|
||||
final height = image.height.toDouble();
|
||||
final size = min(width, height);
|
||||
|
||||
final widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(32),
|
||||
child: Container(
|
||||
width: size,
|
||||
height: size,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black,
|
||||
image: DecorationImage(image: imgProvider, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await hw.HomeWidget.renderFlutterWidget(
|
||||
widget,
|
||||
logicalSize: Size(size, size),
|
||||
key: "slideshow",
|
||||
);
|
||||
|
||||
await hw.HomeWidget.updateWidget(
|
||||
name: 'SlideshowWidgetProvider',
|
||||
androidName: 'SlideshowWidgetProvider',
|
||||
qualifiedAndroidName: 'io.ente.photos.SlideshowWidgetProvider',
|
||||
iOSName: 'SlideshowWidget',
|
||||
);
|
||||
|
||||
if (randomFile.generatedID != null) {
|
||||
await hw.HomeWidget.saveWidgetData<int>(
|
||||
"home_widget_last_img",
|
||||
randomFile.generatedID!,
|
||||
);
|
||||
}
|
||||
|
||||
_logger.info(
|
||||
">>> SlideshowWidget rendered with size ${width}x$height",
|
||||
);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void main() async {
|
||||
debugRepaintRainbowEnabled = false;
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
MediaKit.ensureInitialized();
|
||||
|
||||
try {
|
||||
await Workmanager()
|
||||
.initialize(initSlideshowWidget, isInDebugMode: kDebugMode);
|
||||
await Workmanager().registerPeriodicTask(
|
||||
"slideshow-widget",
|
||||
"updateSlideshowWidget",
|
||||
frequency: const Duration(minutes: 15),
|
||||
);
|
||||
} catch (_) {}
|
||||
|
||||
final savedThemeMode = await AdaptiveTheme.getThemeMode();
|
||||
await _runInForeground(savedThemeMode);
|
||||
unawaited(BackgroundFetch.registerHeadlessTask(_headlessTaskHandler));
|
||||
|
@ -76,6 +175,7 @@ Future<void> _runInForeground(AdaptiveThemeMode? savedThemeMode) async {
|
|||
await _init(false, via: 'mainMethod');
|
||||
final Locale locale = await getLocale();
|
||||
unawaited(_scheduleFGSync('appStart in FG'));
|
||||
|
||||
runApp(
|
||||
AppLock(
|
||||
builder: (args) =>
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import "dart:math";
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import "package:flutter_animate/flutter_animate.dart";
|
||||
import "package:flutter_local_notifications/flutter_local_notifications.dart";
|
||||
import 'package:home_widget/home_widget.dart' as hw;
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:media_extension/media_extension_action_types.dart';
|
||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||
import 'package:move_to_background/move_to_background.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import "package:photos/core/constants.dart";
|
||||
import 'package:photos/core/event_bus.dart';
|
||||
import "package:photos/db/files_db.dart";
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
import 'package:photos/events/account_configured_event.dart';
|
||||
import 'package:photos/events/backup_folders_updated_event.dart';
|
||||
|
@ -33,7 +29,6 @@ import 'package:photos/models/selected_files.dart';
|
|||
import 'package:photos/services/app_lifecycle_service.dart';
|
||||
import 'package:photos/services/collections_service.dart';
|
||||
import "package:photos/services/entity_service.dart";
|
||||
import "package:photos/services/favorites_service.dart";
|
||||
import 'package:photos/services/local_sync_service.dart';
|
||||
import "package:photos/services/notification_service.dart";
|
||||
import 'package:photos/services/update_service.dart';
|
||||
|
@ -61,7 +56,6 @@ import "package:photos/ui/viewer/gallery/collection_page.dart";
|
|||
import 'package:photos/ui/viewer/search/search_widget.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import "package:photos/utils/navigation_util.dart";
|
||||
import "package:photos/utils/thumbnail_util.dart";
|
||||
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
||||
import "package:shared_preferences/shared_preferences.dart";
|
||||
import 'package:uni_links/uni_links.dart';
|
||||
|
@ -115,11 +109,6 @@ class _HomeWidgetState extends State<HomeWidget> {
|
|||
@override
|
||||
void initState() {
|
||||
_logger.info("Building initstate");
|
||||
if (FavoritesService.instance.hasFavorites()) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
initHomeWidget();
|
||||
});
|
||||
}
|
||||
_tabChangedEventSubscription =
|
||||
Bus.instance.on<TabChangedEvent>().listen((event) {
|
||||
_selectedTabIndex = event.selectedIndex;
|
||||
|
@ -243,70 +232,6 @@ class _HomeWidgetState extends State<HomeWidget> {
|
|||
super.initState();
|
||||
}
|
||||
|
||||
Future<void> initHomeWidget() async {
|
||||
await hw.HomeWidget.setAppGroupId("group.io.ente.frame.SlideshowWidget");
|
||||
final collectionID =
|
||||
await FavoritesService.instance.getFavoriteCollectionID();
|
||||
final res = await FilesDB.instance.getFilesInCollection(
|
||||
collectionID!,
|
||||
galleryLoadStartTime,
|
||||
galleryLoadEndTime,
|
||||
);
|
||||
|
||||
final previousGeneratedId =
|
||||
await hw.HomeWidget.getWidgetData<int>("home_widget_last_img");
|
||||
final files = res.files
|
||||
.where((element) => element.generatedID != previousGeneratedId);
|
||||
final randomNumber = Random().nextInt(files.length);
|
||||
final randomFile = files.elementAt(randomNumber);
|
||||
final cachedThumbnail = await getThumbnailFromServer(randomFile);
|
||||
|
||||
var img = Image.memory(cachedThumbnail);
|
||||
var imgProvider = img.image;
|
||||
await precacheImage(imgProvider, context);
|
||||
img = Image.memory(cachedThumbnail);
|
||||
imgProvider = img.image;
|
||||
final image = await decodeImageFromList(cachedThumbnail);
|
||||
final width = image.width.toDouble();
|
||||
final height = image.height.toDouble();
|
||||
final size = min(width, height);
|
||||
|
||||
final widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(32),
|
||||
child: Container(
|
||||
width: size,
|
||||
height: size,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black,
|
||||
image: DecorationImage(image: imgProvider, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await hw.HomeWidget.renderFlutterWidget(
|
||||
widget,
|
||||
logicalSize: Size(size, size),
|
||||
key: "slideshow",
|
||||
);
|
||||
|
||||
await hw.HomeWidget.updateWidget(
|
||||
name: 'SlideshowWidgetProvider',
|
||||
androidName: 'SlideshowWidgetProvider',
|
||||
qualifiedAndroidName: 'io.ente.photos.SlideshowWidgetProvider',
|
||||
iOSName: 'SlideshowWidget',
|
||||
);
|
||||
|
||||
if (randomFile.generatedID != null) {
|
||||
await hw.HomeWidget.saveWidgetData<int>(
|
||||
"home_widget_last_img",
|
||||
randomFile.generatedID!,
|
||||
);
|
||||
}
|
||||
|
||||
_logger
|
||||
.info(">>> HomeWidget rendered with size ${img.width}x${img.height}");
|
||||
}
|
||||
|
||||
Future<void> _autoLogoutAlert() async {
|
||||
final AlertDialog alert = AlertDialog(
|
||||
title: Text(S.of(context).sessionExpired),
|
||||
|
|
43
lib/utils/preload_util.dart
Normal file
43
lib/utils/preload_util.dart
Normal file
|
@ -0,0 +1,43 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class PreloadImage {
|
||||
static Future<void> loadImage(ImageProvider provider) {
|
||||
final config = ImageConfiguration(
|
||||
bundle: rootBundle,
|
||||
devicePixelRatio: 1,
|
||||
platform: defaultTargetPlatform,
|
||||
);
|
||||
final Completer<void> completer = Completer();
|
||||
final ImageStream stream = provider.resolve(config);
|
||||
|
||||
late final ImageStreamListener listener;
|
||||
|
||||
listener = ImageStreamListener(
|
||||
(ImageInfo image, bool sync) {
|
||||
debugPrint("Image ${image.debugLabel} finished loading");
|
||||
completer.complete();
|
||||
stream.removeListener(listener);
|
||||
},
|
||||
onError: (dynamic exception, StackTrace? stackTrace) {
|
||||
completer.complete();
|
||||
stream.removeListener(listener);
|
||||
FlutterError.reportError(
|
||||
FlutterErrorDetails(
|
||||
context: ErrorDescription('image failed to load'),
|
||||
library: 'image resource service',
|
||||
exception: exception,
|
||||
stack: stackTrace,
|
||||
silent: true,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
stream.addListener(listener);
|
||||
return completer.future;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue