From 73468c5c6d890afe4c3b445180482c2ed1fdb847 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 21 Dec 2024 11:56:18 +0800 Subject: [PATCH] :sparkles: iOS background widget fetching --- ios/Podfile.lock | 12 ++- ios/Runner.xcodeproj/project.pbxproj | 8 +- ios/Runner/AppDelegate.swift | 8 ++ ios/Runner/Info.plist | 26 +++--- ios/SolarWidget/CheckInWidget.swift | 5 +- ...ostWidget.swift => RandomPostWidget.swift} | 83 +++++++++---------- ios/SolarWidget/SolarWidgetBundle.swift | 2 +- lib/main.dart | 38 ++++++++- lib/providers/sn_network.dart | 37 ++++++++- lib/providers/widget.dart | 20 ++++- lib/screens/home.dart | 4 +- pubspec.lock | 52 +++++++----- pubspec.yaml | 1 + 13 files changed, 202 insertions(+), 94 deletions(-) rename ios/SolarWidget/{FeaturedPostWidget.swift => RandomPostWidget.swift} (73%) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 73996e1..273048c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -56,7 +56,7 @@ PODS: - Firebase/Analytics (= 11.4.0) - firebase_core - Flutter - - firebase_core (3.8.1): + - firebase_core (3.9.0): - Firebase/CoreOnly (= 11.4.0) - Flutter - firebase_messaging (15.1.6): @@ -216,6 +216,8 @@ PODS: - wakelock_plus (0.0.1): - Flutter - WebRTC-SDK (125.6422.06) + - workmanager (0.0.1): + - Flutter DEPENDENCIES: - connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`) @@ -249,6 +251,7 @@ DEPENDENCIES: - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - volume_controller (from `.symlinks/plugins/volume_controller/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) + - workmanager (from `.symlinks/plugins/workmanager/ios`) SPEC REPOS: trunk: @@ -333,6 +336,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/volume_controller/ios" wakelock_plus: :path: ".symlinks/plugins/wakelock_plus/ios" + workmanager: + :path: ".symlinks/plugins/workmanager/ios" SPEC CHECKSUMS: connectivity_plus: 18382e7311ba19efcaee94442b23b32507b20695 @@ -344,7 +349,7 @@ SPEC CHECKSUMS: file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808 Firebase: cf1b19f21410b029b6786a54e9764a0cacad3c99 firebase_analytics: 2815af29d49c1a994652abd37a5b001a88bc7b75 - firebase_core: 418aed674e9a0b8b6088aec16cde82a811f6261f + firebase_core: b62a5080210edad3f2934314a8b2c6f5124e8e10 firebase_messaging: 98619a0572d82cfb3668e78859ba9f1110e268c9 FirebaseAnalytics: 3feef9ae8733c567866342a1000691baaa7cad49 FirebaseCore: e0510f1523bc0eb21653cac00792e1e2bd6f1771 @@ -381,8 +386,9 @@ SPEC CHECKSUMS: SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 - wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 + wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56 WebRTC-SDK: 79942c006ea64f6fb48d7da8a4786dfc820bc1db + workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6 PODFILE CHECKSUM: 23d35ad686cacf9103d1e85035ee4f3e9750630d diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 0f3b7bf..a5694dc 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 77; objects = { /* Begin PBXBuildFile section */ @@ -879,7 +879,7 @@ INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Solian; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1433,7 +1433,7 @@ INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Solian; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1461,7 +1461,7 @@ INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Solian; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 1493a27..007814d 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,6 +1,8 @@ import Flutter import UIKit +import workmanager + @main @objc class AppDelegate: FlutterAppDelegate { override func application( @@ -9,6 +11,12 @@ import UIKit ) -> Bool { GeneratedPluginRegistrant.register(with: self) + WorkmanagerPlugin.setPluginRegistrantCallback { registry in + GeneratedPluginRegistrant.register(with: registry) + } + + UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60*5)) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 6d8c793..f13faaa 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + AppGroupId + group.solsynth.solian CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion @@ -27,6 +29,17 @@ $(FLUTTER_BUILD_NAME) CFBundleSignature ???? + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER) + + + CFBundleVersion $(FLUTTER_BUILD_NUMBER) ITSAppUsesNonExemptEncryption @@ -66,8 +79,6 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - AppGroupId - group.solsynth.solian UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait @@ -75,16 +86,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLSchemes - - ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER) - - - diff --git a/ios/SolarWidget/CheckInWidget.swift b/ios/SolarWidget/CheckInWidget.swift index d98eb5d..1f283c6 100644 --- a/ios/SolarWidget/CheckInWidget.swift +++ b/ios/SolarWidget/CheckInWidget.swift @@ -29,10 +29,13 @@ struct CheckInProvider: TimelineProvider { user = try! jsonDecoder.decode(SolarUser.self, from: userRaw.data(using: .utf8)!) } - let checkInRaw = prefs?.string(forKey: "today_check_in") + let checkInRaw = prefs?.string(forKey: "pas_check_in_record") var checkIn: SolarCheckInRecord? if let checkInRaw = checkInRaw { checkIn = try! jsonDecoder.decode(SolarCheckInRecord.self, from: checkInRaw.data(using: .utf8)!) + if checkIn != nil && Calendar.current.isDate(checkIn!.createdAt, inSameDayAs: Date()) { + checkIn = nil + } } let entry = CheckInEntry( diff --git a/ios/SolarWidget/FeaturedPostWidget.swift b/ios/SolarWidget/RandomPostWidget.swift similarity index 73% rename from ios/SolarWidget/FeaturedPostWidget.swift rename to ios/SolarWidget/RandomPostWidget.swift index c5c8528..81990c8 100644 --- a/ios/SolarWidget/FeaturedPostWidget.swift +++ b/ios/SolarWidget/RandomPostWidget.swift @@ -1,5 +1,5 @@ // -// FeaturedPostWidget.swift +// RandomPostWidget.swift // Runner // // Created by LittleSheep on 2024/12/14. @@ -8,12 +8,12 @@ import SwiftUI import WidgetKit -struct FeaturedPostProvider: TimelineProvider { - func placeholder(in context: Context) -> FeaturedPostEntry { - FeaturedPostEntry(date: Date(), user: nil, featuredPost: nil, family: .systemMedium) +struct RandomPostProvider: TimelineProvider { + func placeholder(in context: Context) -> RandomPostEntry { + RandomPostEntry(date: Date(), user: nil, randomPost: nil, family: .systemMedium) } - func getSnapshot(in context: Context, completion: @escaping (FeaturedPostEntry) -> ()) { + func getSnapshot(in context: Context, completion: @escaping (RandomPostEntry) -> ()) { let prefs = UserDefaults(suiteName: "group.solsynth.solian") let dateFormatter = DateFormatter() @@ -29,16 +29,17 @@ struct FeaturedPostProvider: TimelineProvider { user = try! jsonDecoder.decode(SolarUser.self, from: userRaw.data(using: .utf8)!) } - let featuredPostRaw = prefs?.string(forKey: "post_featured") - var featuredPosts: [SolarPost]? - if let featuredPostRaw = featuredPostRaw { - featuredPosts = try! jsonDecoder.decode([SolarPost].self, from: featuredPostRaw.data(using: .utf8)!) + let randomPostRaw = prefs?.string(forKey: "int_random_post") + var randomPost: SolarPost? + if let randomPostRaw = randomPostRaw { + randomPost = try! jsonDecoder.decode(SolarPost.self, from: randomPostRaw.data(using: .utf8)!) } - let entry = FeaturedPostEntry( + + let entry = RandomPostEntry( date: Date(), user: user, - featuredPost: featuredPosts?.first, + randomPost: randomPost, family: context.family ) completion(entry) @@ -52,24 +53,22 @@ struct FeaturedPostProvider: TimelineProvider { } } -struct FeaturedPostEntry: TimelineEntry { +struct RandomPostEntry: TimelineEntry { let date: Date let user: SolarUser? - let featuredPost: SolarPost? + let randomPost: SolarPost? let family: WidgetFamily } -struct FeaturedPostWidgetEntryView : View { - var entry: FeaturedPostProvider.Entry - - private let resultTierSymbols: [String] = ["大凶", "凶", "中平", "大吉", "吉"] +struct RandomPostWidgetEntryView : View { + var entry: RandomPostProvider.Entry var body: some View { VStack(alignment: .leading, spacing: 0) { - if let featuredPost = entry.featuredPost { + if let randomPost = entry.randomPost { HStack(alignment: .center) { - if let avatar = featuredPost.publisher.avatar { + if let avatar = randomPost.publisher.avatar { let avatarUrl = getAttachmentUrl(for: avatar) let size: CGFloat = 24 @@ -90,28 +89,28 @@ struct FeaturedPostWidgetEntryView : View { } } - Text("@\(featuredPost.publisher.name)") + Text("@\(randomPost.publisher.name)") .font(.system(size: 13, design: .monospaced)) .opacity(0.9) Spacer() }.frame(maxWidth: .infinity).padding(.bottom, 12) - if featuredPost.body.title != nil || featuredPost.body.description != nil { + if randomPost.body.title != nil || randomPost.body.description != nil { VStack(alignment: .leading) { - if let title = featuredPost.body.title { + if let title = randomPost.body.title { Text(title) .font(.system(size: 17)) } - if let description = featuredPost.body.description { + if let description = randomPost.body.description { Text(description) .font(.system(size: 15)) } }.padding(.bottom, 8) } - if let content = featuredPost.body.content { - if (featuredPost.body.title == nil && featuredPost.body.description == nil) || entry.family == .systemLarge || entry.family == .systemExtraLarge { + if let content = randomPost.body.content { + if (randomPost.body.title == nil && randomPost.body.description == nil) || entry.family == .systemLarge || entry.family == .systemExtraLarge { Text( (entry.family == .systemLarge || entry.family == .systemExtraLarge) ? content : content.replacingOccurrences(of: "\n", with: " ") ) @@ -124,7 +123,7 @@ struct FeaturedPostWidgetEntryView : View { } } - if let attachment = featuredPost.body.attachments { + if let attachment = randomPost.body.attachments { if attachment.count == 1 { Text("\(Image(systemName: "document.fill")) \(attachment.count) attachment") .font(.system(size: 11, design: .monospaced)) @@ -140,14 +139,14 @@ struct FeaturedPostWidgetEntryView : View { Spacer() - Text(featuredPost.publishedAt!, format: .dateTime) + Text(randomPost.publishedAt!, format: .dateTime) .font(.system(size: 11)) - Text("Solar Network Featured Posts") + Text("#\(randomPost.id)") .font(.system(size: 9)) } else { VStack(alignment: .center) { Text("No Recommendations").font(.system(size: 19, weight: .bold)) - Text("Click the widget to open the app to load featured posts") + Text("Open the app to load some random post") .font(.system(size: 15)) .multilineTextAlignment(.center) }.frame(alignment: .center) @@ -156,34 +155,34 @@ struct FeaturedPostWidgetEntryView : View { } } -struct FeaturedPostWidget: Widget { - let kind: String = "SolarFeaturedPostWidget" +struct RandomPostWidget: Widget { + let kind: String = "SolarRandomPostWidget" var body: some WidgetConfiguration { - StaticConfiguration(kind: kind, provider: FeaturedPostProvider()) { entry in + StaticConfiguration(kind: kind, provider: RandomPostProvider()) { entry in if #available(iOS 17.0, *) { - FeaturedPostWidgetEntryView(entry: entry) + RandomPostWidgetEntryView(entry: entry) .containerBackground(.fill.tertiary, for: .widget) } else { - FeaturedPostWidgetEntryView(entry: entry) + RandomPostWidgetEntryView(entry: entry) .padding() .background() } } - .configurationDisplayName("Featured Posts") - .description("View the featured posts on the Solar Network") + .configurationDisplayName("Random Post") + .description("View the random post on the Solar Network") .supportedFamilies([.systemSmall, .systemMedium, .systemLarge, .systemExtraLarge]) } } #Preview(as: .systemSmall) { - FeaturedPostWidget() + RandomPostWidget() } timeline: { - FeaturedPostEntry(date: Date.now, user: nil, featuredPost: nil, family: .systemLarge) - FeaturedPostEntry( + RandomPostEntry(date: Date.now, user: nil, randomPost: nil, family: .systemLarge) + RandomPostEntry( date: .now, user: SolarUser(id: 1, name: "demo", nick: "Deemo"), - featuredPost: SolarPost( + randomPost: SolarPost( id: 1, body: SolarPostBody( content: "Hello, World", @@ -209,10 +208,10 @@ struct FeaturedPostWidget: Widget { ), family: .systemSmall ) - FeaturedPostEntry( + RandomPostEntry( date: .now, user: SolarUser(id: 1, name: "demo", nick: "Deemo"), - featuredPost: SolarPost( + randomPost: SolarPost( id: 1, body: SolarPostBody( content: "Hello, World\nOh wow", diff --git a/ios/SolarWidget/SolarWidgetBundle.swift b/ios/SolarWidget/SolarWidgetBundle.swift index 0a64017..907e282 100644 --- a/ios/SolarWidget/SolarWidgetBundle.swift +++ b/ios/SolarWidget/SolarWidgetBundle.swift @@ -12,6 +12,6 @@ import SwiftUI struct SolarWidgetBundle: WidgetBundle { var body: some Widget { CheckInWidget() - FeaturedPostWidget() + RandomPostWidget() } } diff --git a/lib/main.dart b/lib/main.dart index ca618ee..c9a942d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -37,6 +37,24 @@ import 'package:surface/types/realm.dart'; import 'package:flutter_web_plugins/url_strategy.dart' show usePathUrlStrategy; import 'package:surface/widgets/dialog.dart'; import 'package:surface/widgets/version_label.dart'; +import 'package:workmanager/workmanager.dart'; + +@pragma('vm:entry-point') +void appBackgroundDispatcher() { + Workmanager().executeTask((task, inputData) async { + print("Native called background task: $task"); + switch (task) { + case Workmanager.iOSBackgroundTask: + await Future.wait([widgetUpdateRandomPost()]); + return true; + case "WidgetUpdateRandomPost": + await widgetUpdateRandomPost(); + return true; + default: + return true; + } + }); +} void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -64,6 +82,20 @@ void main() async { }); } + if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) { + Workmanager().initialize( + appBackgroundDispatcher, + isInDebugMode: kDebugMode, + ); + Workmanager().registerPeriodicTask( + "widget-update-random-post", + "WidgetUpdateRandomPost", + frequency: Duration(minutes: 1), + constraints: Constraints(networkType: NetworkType.connected), + tag: "widget-update", + ); + } + runApp(const SolianApp()); } @@ -193,10 +225,14 @@ class _AppSplashScreenState extends State<_AppSplashScreen> { } } + Future _postInitialization() async { + await widgetUpdateRandomPost(); + } + @override void initState() { super.initState(); - _initialize(); + _initialize().then((_) => _postInitialization()); } @override diff --git a/lib/providers/sn_network.dart b/lib/providers/sn_network.dart index d8edde7..f11d364 100644 --- a/lib/providers/sn_network.dart +++ b/lib/providers/sn_network.dart @@ -71,7 +71,36 @@ class SnNetworkProvider { }); } - Future initializeUserAgent() async { + static Future createOffContextClient() async { + final prefs = await SharedPreferences.getInstance(); + final client = Dio(); + client.interceptors.add(RetryInterceptor( + dio: client, + retries: 3, + retryDelays: const [ + Duration(milliseconds: 300), + Duration(milliseconds: 1000), + Duration(milliseconds: 3000), + ], + )); + final ua = await _getUserAgent(); + client.interceptors.add( + InterceptorsWrapper( + onRequest: ( + RequestOptions options, + RequestInterceptorHandler handler, + ) async { + options.headers['User-Agent'] = ua; + return handler.next(options); + }, + ), + ); + client.options.baseUrl = prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault; + + return client; + } + + static Future _getUserAgent() async { final String platformInfo; if (kIsWeb) { final deviceInfo = await DeviceInfoPlugin().webBrowserInfo; @@ -97,7 +126,11 @@ class SnNetworkProvider { final packageInfo = await PackageInfo.fromPlatform(); - _userAgent = 'Solian/${packageInfo.version}+${packageInfo.buildNumber} ($platformInfo)'; + return 'Solian/${packageInfo.version}+${packageInfo.buildNumber} ($platformInfo)'; + } + + Future initializeUserAgent() async { + _userAgent = await _getUserAgent(); } final tkLock = Lock(); diff --git a/lib/providers/widget.dart b/lib/providers/widget.dart index 96cc551..53492e3 100644 --- a/lib/providers/widget.dart +++ b/lib/providers/widget.dart @@ -4,6 +4,8 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:home_widget/home_widget.dart'; +import 'package:surface/providers/sn_network.dart'; +import 'package:surface/types/post.dart'; class HomeWidgetProvider { HomeWidgetProvider(BuildContext context); @@ -15,8 +17,7 @@ class HomeWidgetProvider { } } - Future saveWidgetData(String id, dynamic data, - {bool update = true}) async { + Future saveWidgetData(String id, dynamic data, {bool update = true}) async { if (kIsWeb || !(Platform.isAndroid || Platform.isIOS)) return; await HomeWidget.saveWidgetData(id, jsonEncode(data)); if (update) await updateWidget(); @@ -25,7 +26,7 @@ class HomeWidgetProvider { Future updateWidget() async { if (kIsWeb || !(Platform.isAndroid || Platform.isIOS)) return; if (Platform.isIOS) { - const widgets = ["SolarFeaturedPostWidget", "SolarCheckInWidget"]; + const widgets = ["SolarRandomPostWidget", "SolarCheckInWidget"]; for (final widget in widgets) { await HomeWidget.updateWidget( name: widget, @@ -43,3 +44,16 @@ class HomeWidgetProvider { } } } + +Future widgetUpdateRandomPost() async { + final snc = await SnNetworkProvider.createOffContextClient(); + final resp = await snc.get('/cgi/co/recommendations/shuffle?take=1'); + final post = SnPost.fromJson(resp.data['data'][0]); + await HomeWidget.saveWidgetData("int_random_post", jsonEncode(post.toJson())); + await HomeWidget.updateWidget( + name: "SolarRandomPostWidget", + iOSName: "SolarRandomPostWidget", + androidName: "FeaturedPostWidgetReceiver", + qualifiedAndroidName: "dev.solsynth.solian.widgets.FeaturedPostWidgetReceiver", + ); +} diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 37f0d54..671fdc6 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -151,7 +151,7 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> { final home = context.read(); final resp = await sn.client.get('/cgi/id/check-in/today'); _todayRecord = SnCheckInRecord.fromJson(resp.data); - home.saveWidgetData('today_check_in', _todayRecord!.toJson()); + home.saveWidgetData('pas_check_in_record', _todayRecord!.toJson()); } finally { setState(() => _isBusy = false); } @@ -164,7 +164,7 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> { final home = context.read(); final resp = await sn.client.post('/cgi/id/check-in'); _todayRecord = SnCheckInRecord.fromJson(resp.data); - home.saveWidgetData('today_check_in', _todayRecord!.toJson()); + home.saveWidgetData('pas_check_in_record', _todayRecord!.toJson()); } catch (err) { if (!mounted) return; context.showErrorDialog(err); diff --git a/pubspec.lock b/pubspec.lock index 3859e81..b81c854 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: eae3133cbb06de9205899b822e3897fc6a8bc278ad4c944b4ce612689369694b + sha256: daa1d780fdecf8af925680c06c86563cdd445deea995d5c9176f1302a2b10bbe url: "https://pub.dev" source: hosted - version: "1.3.47" + version: "1.3.48" _macros: dependency: transitive description: dart @@ -50,10 +50,10 @@ packages: dependency: transitive description: name: archive - sha256: "08064924cbf0ab88280a0c3f60db9dd24fec693927e725ecb176f16c629d1cb8" + sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a" url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" args: dependency: transitive description: @@ -562,26 +562,26 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: fef81a53ba1ca618def1f8bef4361df07968434e62cb204c1fb90bb880a03da2 + sha256: "15d761b95dfa2906dfcc31b7fc6fe293188533d1a3ffe78389ba9e69bd7fdbde" url: "https://pub.dev" source: hosted - version: "3.8.1" + version: "3.9.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: b94b217e3ad745e784960603d33d99471621ecca151c99c670869b76e50ad2a6 + sha256: d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "5.4.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: "9e69806bb3d905aeec3c1242e0e1475de6ea6d48f456af29d598fb229a2b4e5e" + sha256: fbc008cf390d909b823763064b63afefe9f02d8afdb13eb3f485b871afee956b url: "https://pub.dev" source: hosted - version: "2.18.2" + version: "2.19.0" firebase_messaging: dependency: "direct main" description: @@ -894,10 +894,10 @@ packages: dependency: transitive description: name: image - sha256: b50b415345578583de0f1cf4c7bd389f164de0b316d890c707b41133047dbc2a + sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6" url: "https://pub.dev" source: hosted - version: "4.5.1" + version: "4.5.2" image_picker: dependency: "direct main" description: @@ -1038,10 +1038,10 @@ packages: dependency: transitive description: name: lints - sha256: "4a16b3f03741e1252fda5de3ce712666d010ba2122f8e912c94f9f7b90e1a4c3" + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "5.1.1" livekit_client: dependency: "direct main" description: @@ -1454,10 +1454,10 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" qr: dependency: transitive description: @@ -2003,18 +2003,18 @@ packages: dependency: "direct main" description: name: wakelock_plus - sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484 + sha256: "1aeab49f24aec1e5ab417d7cdfc47c7bbcb815353f1840667ffe68c89a0cd2e6" url: "https://pub.dev" source: hosted - version: "1.2.8" + version: "1.2.9" wakelock_plus_platform_interface: dependency: transitive description: name: wakelock_plus_platform_interface - sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16" + sha256: "70e780bc99796e1db82fe764b1e7dcb89a86f1e5b3afb1db354de50f2e41eb7a" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" watcher: dependency: transitive description: @@ -2071,6 +2071,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.5" + workmanager: + dependency: "direct main" + description: + name: workmanager + sha256: ed13530cccd28c5c9959ad42d657cd0666274ca74c56dea0ca183ddd527d3a00 + url: "https://pub.dev" + source: hosted + version: "0.5.2" xdg_directories: dependency: transitive description: @@ -2091,10 +2099,10 @@ packages: dependency: transitive description: name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" sdks: dart: ">=3.6.0 <4.0.0" flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 790d488..3998aa5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -107,6 +107,7 @@ dependencies: flutter_svg: ^2.0.16 home_widget: ^0.7.0 receive_sharing_intent: ^1.8.1 + workmanager: ^0.5.2 dev_dependencies: flutter_test: