[mob][photos] refactor home widget (#5389)
## Description Refactor home widget and separate memory home widget services. ## Tests
@@ -143,12 +143,12 @@
|
||||
android:value="https://2235e5c99219488ea93da34b9ac1cb68@sentry.ente.io/4" />
|
||||
<meta-data android:name="firebase_analytics_collection_deactivated"
|
||||
android:value="true" />
|
||||
<receiver android:name="SlideshowWidgetProvider" android:label="Memories" android:exported="true">
|
||||
<receiver android:name="EnteMemoryWidgetProvider" android:label="Memories" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.appwidget.provider"
|
||||
android:resource="@xml/slideshow_widget" />
|
||||
android:resource="@xml/memory_widget" />
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
package io.ente.photos
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import androidx.core.content.ContextCompat
|
||||
import es.antonborri.home_widget.HomeWidgetLaunchIntent
|
||||
import es.antonborri.home_widget.HomeWidgetProvider
|
||||
import java.io.File
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
@Serializable
|
||||
data class MemoryFileData(val title: String?, val subText: String?, val generatedId: Int?)
|
||||
|
||||
class EnteMemoryWidgetProvider : HomeWidgetProvider() {
|
||||
override fun onUpdate(
|
||||
context: Context,
|
||||
appWidgetManager: AppWidgetManager,
|
||||
appWidgetIds: IntArray,
|
||||
widgetData: SharedPreferences
|
||||
) {
|
||||
appWidgetIds.forEach { widgetId ->
|
||||
val views =
|
||||
RemoteViews(context.packageName, R.layout.memory_widget_layout)
|
||||
.apply {
|
||||
val totalMemories =
|
||||
widgetData.getInt("totalMemories", 0)
|
||||
var randomNumber = -1
|
||||
var imagePath: String? = null
|
||||
if (totalMemories > 0) {
|
||||
randomNumber =
|
||||
(0 until totalMemories!!).random()
|
||||
imagePath =
|
||||
widgetData.getString(
|
||||
"memory_widget_" +
|
||||
randomNumber,
|
||||
null
|
||||
)
|
||||
}
|
||||
var imageExists: Boolean = false
|
||||
if (imagePath != null) {
|
||||
val imageFile = File(imagePath)
|
||||
imageExists = imageFile.exists()
|
||||
}
|
||||
if (imageExists) {
|
||||
val data =
|
||||
widgetData.getString(
|
||||
"memory_widget_${randomNumber}_data",
|
||||
null
|
||||
)
|
||||
val decoded: MemoryFileData? =
|
||||
data?.let {
|
||||
Json.decodeFromString<
|
||||
MemoryFileData>(it)
|
||||
}
|
||||
val title = decoded?.title
|
||||
val subText = decoded?.subText
|
||||
val generatedId = decoded?.generatedId
|
||||
|
||||
val deepLinkUri =
|
||||
Uri.parse(
|
||||
"memorywidget://message?generatedId=${generatedId}&homeWidget"
|
||||
)
|
||||
|
||||
val pendingIntent =
|
||||
HomeWidgetLaunchIntent.getActivity(
|
||||
context,
|
||||
MainActivity::class.java,
|
||||
deepLinkUri
|
||||
)
|
||||
|
||||
setOnClickPendingIntent(
|
||||
R.id.widget_container,
|
||||
pendingIntent
|
||||
)
|
||||
|
||||
Log.d(
|
||||
"EnteMemoryWidgetProvider",
|
||||
"Image exists: $imagePath"
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_img,
|
||||
View.VISIBLE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_placeholder_container,
|
||||
View.VISIBLE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_subtitle,
|
||||
View.VISIBLE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_title,
|
||||
View.VISIBLE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_overlay,
|
||||
View.VISIBLE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_placeholder,
|
||||
View.GONE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_placeholder_text,
|
||||
View.GONE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_placeholder_container,
|
||||
View.GONE
|
||||
)
|
||||
|
||||
val bitmap: Bitmap =
|
||||
BitmapFactory.decodeFile(imagePath)
|
||||
setImageViewBitmap(R.id.widget_img, bitmap)
|
||||
setTextViewText(R.id.widget_title, title)
|
||||
setTextViewText(
|
||||
R.id.widget_subtitle,
|
||||
subText
|
||||
)
|
||||
} else {
|
||||
// Open App on Widget Click
|
||||
val pendingIntent =
|
||||
HomeWidgetLaunchIntent.getActivity(
|
||||
context,
|
||||
MainActivity::class.java
|
||||
)
|
||||
setOnClickPendingIntent(
|
||||
R.id.widget_container,
|
||||
pendingIntent
|
||||
)
|
||||
|
||||
Log.d(
|
||||
"EnteMemoryWidgetProvider",
|
||||
"Image doesn't exists"
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_img,
|
||||
View.GONE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_placeholder_container,
|
||||
View.GONE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_subtitle,
|
||||
View.GONE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_title,
|
||||
View.GONE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_overlay,
|
||||
View.GONE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_placeholder,
|
||||
View.VISIBLE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_placeholder_text,
|
||||
View.VISIBLE
|
||||
)
|
||||
setViewVisibility(
|
||||
R.id.widget_placeholder_container,
|
||||
View.VISIBLE
|
||||
)
|
||||
|
||||
val drawable =
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable
|
||||
.ic_home_widget_default
|
||||
)
|
||||
val bitmap =
|
||||
(drawable as BitmapDrawable).bitmap
|
||||
setImageViewBitmap(
|
||||
R.id.widget_placeholder,
|
||||
bitmap
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
appWidgetManager.updateAppWidget(widgetId, views)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package io.ente.photos
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import androidx.core.content.ContextCompat
|
||||
import es.antonborri.home_widget.HomeWidgetLaunchIntent
|
||||
import es.antonborri.home_widget.HomeWidgetProvider
|
||||
import java.io.File
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
@Serializable
|
||||
data class MemoryFileData(val title: String?, val subText: String?, val generatedId: Int?)
|
||||
|
||||
class SlideshowWidgetProvider : HomeWidgetProvider() {
|
||||
override fun onUpdate(
|
||||
context: Context,
|
||||
appWidgetManager: AppWidgetManager,
|
||||
appWidgetIds: IntArray,
|
||||
widgetData: SharedPreferences
|
||||
) {
|
||||
appWidgetIds.forEach { widgetId ->
|
||||
val views =
|
||||
RemoteViews(context.packageName, R.layout.slideshow_layout).apply {
|
||||
val totalSet = widgetData.getInt("totalSet", 0)
|
||||
var randomNumber = -1
|
||||
var imagePath: String? = null
|
||||
if (totalSet > 0) {
|
||||
randomNumber = (0 until totalSet!!).random()
|
||||
imagePath = widgetData.getString("slideshow_" + randomNumber, null)
|
||||
}
|
||||
var imageExists: Boolean = false
|
||||
if (imagePath != null) {
|
||||
val imageFile = File(imagePath)
|
||||
imageExists = imageFile.exists()
|
||||
}
|
||||
if (imageExists) {
|
||||
val data = widgetData.getString("slideshow_${randomNumber}_data", null)
|
||||
val decoded: MemoryFileData? =
|
||||
data?.let { Json.decodeFromString<MemoryFileData>(it) }
|
||||
val title = decoded?.title
|
||||
val subText = decoded?.subText
|
||||
val generatedId = decoded?.generatedId
|
||||
|
||||
val deepLinkUri =
|
||||
Uri.parse(
|
||||
"memoryWidget://message?generatedId=${generatedId}&homeWidget"
|
||||
)
|
||||
|
||||
val pendingIntent =
|
||||
HomeWidgetLaunchIntent.getActivity(
|
||||
context,
|
||||
MainActivity::class.java,
|
||||
deepLinkUri
|
||||
)
|
||||
|
||||
setOnClickPendingIntent(R.id.widget_container, pendingIntent)
|
||||
|
||||
Log.d("SlideshowWidgetProvider", "Image exists: $imagePath")
|
||||
setViewVisibility(R.id.widget_img, View.VISIBLE)
|
||||
setViewVisibility(R.id.widget_placeholder_container, View.VISIBLE)
|
||||
setViewVisibility(R.id.widget_subtitle, View.VISIBLE)
|
||||
setViewVisibility(R.id.widget_title, View.VISIBLE)
|
||||
setViewVisibility(R.id.widget_overlay, View.VISIBLE)
|
||||
setViewVisibility(R.id.widget_placeholder, View.GONE)
|
||||
setViewVisibility(R.id.widget_placeholder_text, View.GONE)
|
||||
setViewVisibility(R.id.widget_placeholder_container, View.GONE)
|
||||
|
||||
val bitmap: Bitmap = BitmapFactory.decodeFile(imagePath)
|
||||
setImageViewBitmap(R.id.widget_img, bitmap)
|
||||
setTextViewText(R.id.widget_title, title)
|
||||
setTextViewText(R.id.widget_subtitle, subText)
|
||||
} else {
|
||||
// Open App on Widget Click
|
||||
val pendingIntent =
|
||||
HomeWidgetLaunchIntent.getActivity(
|
||||
context,
|
||||
MainActivity::class.java
|
||||
)
|
||||
setOnClickPendingIntent(R.id.widget_container, pendingIntent)
|
||||
|
||||
Log.d("SlideshowWidgetProvider", "Image doesn't exists")
|
||||
setViewVisibility(R.id.widget_img, View.GONE)
|
||||
setViewVisibility(R.id.widget_placeholder_container, View.GONE)
|
||||
setViewVisibility(R.id.widget_subtitle, View.GONE)
|
||||
setViewVisibility(R.id.widget_title, View.GONE)
|
||||
setViewVisibility(R.id.widget_overlay, View.GONE)
|
||||
setViewVisibility(R.id.widget_placeholder, View.VISIBLE)
|
||||
setViewVisibility(R.id.widget_placeholder_text, View.VISIBLE)
|
||||
setViewVisibility(R.id.widget_placeholder_container, View.VISIBLE)
|
||||
|
||||
val drawable =
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.ic_home_widget_default
|
||||
)
|
||||
val bitmap = (drawable as BitmapDrawable).bitmap
|
||||
setImageViewBitmap(R.id.widget_placeholder, bitmap)
|
||||
}
|
||||
}
|
||||
|
||||
appWidgetManager.updateAppWidget(widgetId, views)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 125 KiB |
@@ -3,8 +3,8 @@
|
||||
android:minWidth="100dp"
|
||||
android:minHeight="100dp"
|
||||
android:updatePeriodMillis="900000"
|
||||
android:initialLayout="@layout/slideshow_layout"
|
||||
android:previewImage="@drawable/slideshow_preview"
|
||||
android:initialLayout="@layout/memory_widget_layout"
|
||||
android:previewImage="@drawable/memory_widget_preview"
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:widgetCategory="home_screen">
|
||||
</appwidget-provider>
|
||||
@@ -1,17 +1,17 @@
|
||||
//
|
||||
// SlideshowWidgetBundle.swift
|
||||
// SlideshowWidget
|
||||
// EnteMemoryWidgetBundle.swift
|
||||
// EnteMemoryWidget
|
||||
//
|
||||
// Created by Prateek Sunal on 3/7/25.
|
||||
// Copyright © 2025 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
|
||||
@main
|
||||
struct SlideshowWidgetBundle: WidgetBundle {
|
||||
struct EnteMemoryWidgetBundle: WidgetBundle {
|
||||
var body: some Widget {
|
||||
SlideshowWidget()
|
||||
EnteMemoryWidget()
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.io.ente.frame.SlideshowWidget</string>
|
||||
<string>group.io.ente.frame.EnteMemoryWidget</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -4,7 +4,7 @@
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.io.ente.frame.SlideshowWidget</string>
|
||||
<string>group.io.ente.frame.EnteMemoryWidget</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -447,83 +447,83 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
background_fetch: 39f11371c0dce04b001c4bfd5e782bcccb0a85e2
|
||||
battery_info: b6c551049266af31556b93c9d9b9452cfec0219f
|
||||
connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
|
||||
cupertino_http: 947a233f40cfea55167a49f2facc18434ea117ba
|
||||
dart_ui_isolate: d5bcda83ca4b04f129d70eb90110b7a567aece14
|
||||
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
||||
background_fetch: 94b36ee293e82972852dba8ede1fbcd3bd3d9d57
|
||||
battery_info: 83f3aae7be2fccefab1d2bf06b8aa96f11c8bcdd
|
||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||
cupertino_http: 94ac07f5ff090b8effa6c5e2c47871d48ab7c86c
|
||||
dart_ui_isolate: 46f6714abe6891313267153ef6f9748d8ecfcab1
|
||||
device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
|
||||
ffmpeg-kit-ios-full-gpl: 80adc341962e55ef709e36baa8ed9a70cf4ea62b
|
||||
ffmpeg_kit_flutter_full_gpl: 8d15c14c0c3aba616fac04fe44b3d27d02e3c330
|
||||
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
|
||||
ffmpeg_kit_flutter_full_gpl: ce18b888487c05c46ed252cd2e7956812f2e3bd1
|
||||
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
||||
Firebase: d80354ed7f6df5f9aca55e9eb47cc4b634735eaf
|
||||
firebase_core: 6e223dfa350b2edceb729cea505eaaef59330682
|
||||
firebase_messaging: 07fde77ae28c08616a1d4d870450efc2b38cf40d
|
||||
firebase_core: 6cbed78b4f298ed103a9fd034e6dbc846320480f
|
||||
firebase_messaging: 5e0adf2eb18b0ee59aa0c109314c091a0497ecac
|
||||
FirebaseCore: 99fe0c4b44a39f37d99e6404e02009d2db5d718d
|
||||
FirebaseCoreInternal: df24ce5af28864660ecbd13596fc8dd3a8c34629
|
||||
FirebaseInstallations: 6c963bd2a86aca0481eef4f48f5a4df783ae5917
|
||||
FirebaseMessaging: 487b634ccdf6f7b7ff180fdcb2a9935490f764e8
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_app_icon_changer: e633ce623d36db4dd63c01e4b63fc8a5d44ed48d
|
||||
flutter_email_sender: e03bdda7637bcd3539bfe718fddd980e9508efaa
|
||||
flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e
|
||||
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
|
||||
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
||||
flutter_native_splash: f71420956eb811e6d310720fee915f1d42852e7a
|
||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||
flutter_sodium: a00383520fc689c688b66fd3092984174712493e
|
||||
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
|
||||
flutter_app_icon_changer: 7b04b45ddc58854f06df562f1e013c54ec40da6e
|
||||
flutter_email_sender: aa1e9772696691d02cd91fea829856c11efb8e58
|
||||
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
|
||||
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
||||
flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100
|
||||
flutter_native_splash: 6cad9122ea0fad137d23137dd14b937f3e90b145
|
||||
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
|
||||
flutter_sodium: 7e4621538491834eba53bd524547854bcbbd6987
|
||||
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
|
||||
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
|
||||
image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43
|
||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||
in_app_purchase_storekit: a1ce04056e23eecc666b086040239da7619cd783
|
||||
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
|
||||
launcher_icon_switcher: 8e0ad2131a20c51c1dd939896ee32e70cd845b37
|
||||
home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f
|
||||
image_editor_common: 3de87e7c4804f4ae24c8f8a998362b98c105cac1
|
||||
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
|
||||
in_app_purchase_storekit: d1a48cb0f8b29dbf5f85f782f5dd79b21b90a5e6
|
||||
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
|
||||
launcher_icon_switcher: 84c218d233505aa7d8655d8fa61a3ba802c022da
|
||||
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
|
||||
local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
|
||||
local_auth_ios: 5046a18c018dd973247a0564496c8898dbb5adf9
|
||||
local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391
|
||||
local_auth_ios: f7a1841beef3151d140a967c2e46f30637cdf451
|
||||
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
|
||||
maps_launcher: 2e5b6a2d664ec6c27f82ffa81b74228d770ab203
|
||||
media_extension: 6618f07abd762cdbfaadf1b0c56a287e820f0c84
|
||||
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
||||
motion_sensors: 03f55b7c637a7e365a0b5f9697a449f9059d5d91
|
||||
motionphoto: 8b65ce50c7d7ff3c767534fc3768b2eed9ac24e4
|
||||
move_to_background: cd3091014529ec7829e342ad2d75c0a11f4378a5
|
||||
maps_launcher: edf829809ba9e894d70e569bab11c16352dedb45
|
||||
media_extension: 671e2567880d96c95c65c9a82ccceed8f2e309fd
|
||||
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
|
||||
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
||||
motion_sensors: 741e702c17467b9569a92165dda8d4d88c6167f1
|
||||
motionphoto: 23e2aeb5c6380112f69468d71f970fa7438e5ed1
|
||||
move_to_background: 7e3467dd2a1d1013e98c9c1cb93fd53cd7ef9d84
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
native_video_player: 5d36066807b680e181473e6890dde643ac85380d
|
||||
objective_c: 77e887b5ba1827970907e10e832eec1683f3431d
|
||||
onnxruntime: e7c2ae44385191eaad5ae64c935a72debaddc997
|
||||
native_video_player: e363dd14f6a498ad8a8f7e6486a0db046ad19f13
|
||||
objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
|
||||
onnxruntime: f9b296392c96c42882be020a59dbeac6310d81b2
|
||||
onnxruntime-c: a909204639a1f035f575127ac406f781ac797c9c
|
||||
onnxruntime-objc: b6fab0f1787aa6f7190c2013f03037df4718bd8b
|
||||
open_mail_app: 70273c53f768beefdafbe310c3d9086e4da3cb02
|
||||
open_mail_app: 7314a609e88eed22d53671279e189af7a0ab0f11
|
||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
|
||||
privacy_screen: 1a131c052ceb3c3659934b003b0d397c2381a24e
|
||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||
photo_manager: d2fbcc0f2d82458700ee6256a15018210a81d413
|
||||
privacy_screen: 3159a541f5d3a31bea916cfd4e58f9dc722b3fd4
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
receive_sharing_intent: 79c848f5b045674ad60b9fea3bafea59962ad2c1
|
||||
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||
SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
|
||||
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
|
||||
Sentry: 0f9bc9adfc0b960e7f3bb5ec67e9a3d8193f3bdb
|
||||
sentry_flutter: 64a43fb39ab4c7f67d8a4cad52b49e22439e58b7
|
||||
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
||||
sentry_flutter: f4a0466dc8855998ffd59378ec33507c7dc32d7b
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||
sqlite3: fc1400008a9b3525f5914ed715a5d1af0b8f4983
|
||||
sqlite3_flutter_libs: 069c435986dd4b63461aecd68f4b30be4a9e9daa
|
||||
system_info_plus: 5393c8da281d899950d751713575fbf91c7709aa
|
||||
ua_client_hints: aeabd123262c087f0ce151ef96fa3ab77bfc8b38
|
||||
uni_links: 103d3319e3383ed8bce559b96b1e219fbf02ba96
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
|
||||
video_thumbnail: 94ba6705afbaa120b77287080424930f23ea0c40
|
||||
volume_controller: 2e3de73d6e7e81a0067310d17fb70f2f86d71ac7
|
||||
wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56
|
||||
sqlite3_flutter_libs: 3c323550ef3b928bc0aa9513c841e45a7d242832
|
||||
system_info_plus: 555ce7047fbbf29154726db942ae785c29211740
|
||||
ua_client_hints: 92fe0d139619b73ec9fcb46cc7e079a26178f586
|
||||
uni_links: f191d616c4db8750f74c72c988e79a83dd297fac
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
|
||||
video_thumbnail: 584ccfa55d8fd2f3d5507218b0a18d84c839c620
|
||||
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
|
||||
wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
|
||||
|
||||
PODFILE CHECKSUM: 20e086e6008977d43a3d40260f3f9bffcac748dd
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
CEE6BE702D7AE7FD00E4048B /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6DACD83C2B755B0600BA9516 /* WidgetKit.framework */; };
|
||||
CEE6BE712D7AE7FD00E4048B /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6DACD83E2B755B0600BA9516 /* SwiftUI.framework */; };
|
||||
CEE6BE7C2D7AE7FE00E4048B /* SlideshowWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = CEE6BE6F2D7AE7FD00E4048B /* SlideshowWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
CEE6BE7C2D7AE7FE00E4048B /* EnteMemoryWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = CEE6BE6F2D7AE7FD00E4048B /* EnteMemoryWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
DA6BE5E826B3BC8600656280 /* (null) in Resources */ = {isa = PBXBuildFile; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = CEE6BE6E2D7AE7FD00E4048B;
|
||||
remoteInfo = SlideshowWidgetExtension;
|
||||
remoteInfo = EnteMemoryWidgetExtension;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
CEE6BE7C2D7AE7FE00E4048B /* SlideshowWidgetExtension.appex in Embed Foundation Extensions */,
|
||||
CEE6BE7C2D7AE7FE00E4048B /* EnteMemoryWidgetExtension.appex in Embed Foundation Extensions */,
|
||||
);
|
||||
name = "Embed Foundation Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -78,9 +78,9 @@
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
A78E51A260432466D4C456A9 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
BB097BB5EB0EEB41344338D2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
CE93A9062D808893005CD942 /* SlideshowWidgetExtensionDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SlideshowWidgetExtensionDebug.entitlements; sourceTree = "<group>"; };
|
||||
CEE6BE6F2D7AE7FD00E4048B /* SlideshowWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SlideshowWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
CEE6BE822D7AE8C700E4048B /* SlideshowWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SlideshowWidgetExtension.entitlements; sourceTree = "<group>"; };
|
||||
CE93A9062D808893005CD942 /* EnteMemoryWidgetExtensionDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EnteMemoryWidgetExtensionDebug.entitlements; sourceTree = "<group>"; };
|
||||
CEE6BE6F2D7AE7FD00E4048B /* EnteMemoryWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = EnteMemoryWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
CEE6BE822D7AE8C700E4048B /* EnteMemoryWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EnteMemoryWidgetExtension.entitlements; sourceTree = "<group>"; };
|
||||
DA8D6672273BBB59007651D4 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
F82DAEEB9A7D9FD00E0FFA1E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
@@ -91,12 +91,12 @@
|
||||
membershipExceptions = (
|
||||
Info.plist,
|
||||
);
|
||||
target = CEE6BE6E2D7AE7FD00E4048B /* SlideshowWidgetExtension */;
|
||||
target = CEE6BE6E2D7AE7FD00E4048B /* EnteMemoryWidgetExtension */;
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
CEE6BE722D7AE7FD00E4048B /* SlideshowWidget */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (CEE6BE802D7AE7FE00E4048B /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = SlideshowWidget; sourceTree = "<group>"; };
|
||||
CEE6BE722D7AE7FD00E4048B /* EnteMemoryWidget */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (CEE6BE802D7AE7FE00E4048B /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = EnteMemoryWidget; sourceTree = "<group>"; };
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -135,12 +135,12 @@
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CE93A9062D808893005CD942 /* SlideshowWidgetExtensionDebug.entitlements */,
|
||||
CEE6BE822D7AE8C700E4048B /* SlideshowWidgetExtension.entitlements */,
|
||||
CE93A9062D808893005CD942 /* EnteMemoryWidgetExtensionDebug.entitlements */,
|
||||
CEE6BE822D7AE8C700E4048B /* EnteMemoryWidgetExtension.entitlements */,
|
||||
2772189F270F596900FFE3CC /* GoogleService-Info.plist */,
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
CEE6BE722D7AE7FD00E4048B /* SlideshowWidget */,
|
||||
CEE6BE722D7AE7FD00E4048B /* EnteMemoryWidget */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
AC6CA265BB505D982CB00391 /* Pods */,
|
||||
C6A22658E77FF012720BEDDA /* Frameworks */,
|
||||
@@ -151,7 +151,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
CEE6BE6F2D7AE7FD00E4048B /* SlideshowWidgetExtension.appex */,
|
||||
CEE6BE6F2D7AE7FD00E4048B /* EnteMemoryWidgetExtension.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -230,9 +230,9 @@
|
||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
CEE6BE6E2D7AE7FD00E4048B /* SlideshowWidgetExtension */ = {
|
||||
CEE6BE6E2D7AE7FD00E4048B /* EnteMemoryWidgetExtension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = CEE6BE812D7AE7FE00E4048B /* Build configuration list for PBXNativeTarget "SlideshowWidgetExtension" */;
|
||||
buildConfigurationList = CEE6BE812D7AE7FE00E4048B /* Build configuration list for PBXNativeTarget "EnteMemoryWidgetExtension" */;
|
||||
buildPhases = (
|
||||
CEE6BE6B2D7AE7FD00E4048B /* Sources */,
|
||||
CEE6BE6C2D7AE7FD00E4048B /* Frameworks */,
|
||||
@@ -243,13 +243,13 @@
|
||||
dependencies = (
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
CEE6BE722D7AE7FD00E4048B /* SlideshowWidget */,
|
||||
CEE6BE722D7AE7FD00E4048B /* EnteMemoryWidget */,
|
||||
);
|
||||
name = SlideshowWidgetExtension;
|
||||
name = EnteMemoryWidgetExtension;
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = SlideshowWidgetExtension;
|
||||
productReference = CEE6BE6F2D7AE7FD00E4048B /* SlideshowWidgetExtension.appex */;
|
||||
productName = EnteMemoryWidgetExtension;
|
||||
productReference = CEE6BE6F2D7AE7FD00E4048B /* EnteMemoryWidgetExtension.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
@@ -286,7 +286,7 @@
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
CEE6BE6E2D7AE7FD00E4048B /* SlideshowWidgetExtension */,
|
||||
CEE6BE6E2D7AE7FD00E4048B /* EnteMemoryWidgetExtension */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -614,7 +614,7 @@
|
||||
/* Begin PBXTargetDependency section */
|
||||
CEE6BE7B2D7AE7FE00E4048B /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = CEE6BE6E2D7AE7FD00E4048B /* SlideshowWidgetExtension */;
|
||||
target = CEE6BE6E2D7AE7FD00E4048B /* EnteMemoryWidgetExtension */;
|
||||
targetProxy = CEE6BE7A2D7AE7FE00E4048B /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
@@ -955,7 +955,7 @@
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = SlideshowWidgetExtensionDebug.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = EnteMemoryWidgetExtensionDebug.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@@ -963,8 +963,8 @@
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SlideshowWidget/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SlideshowWidget;
|
||||
INFOPLIST_FILE = EnteMemoryWidget/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = EnteMemoryWidget;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 The Chromium Authors. All rights reserved.";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 18.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -976,7 +976,7 @@
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.debug.SlideshowWidget;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.debug.EnteMemoryWidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
@@ -997,7 +997,7 @@
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = SlideshowWidgetExtension.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = EnteMemoryWidgetExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@@ -1005,8 +1005,8 @@
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SlideshowWidget/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SlideshowWidget;
|
||||
INFOPLIST_FILE = EnteMemoryWidget/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = EnteMemoryWidget;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 The Chromium Authors. All rights reserved.";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 18.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -1017,7 +1017,7 @@
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.SlideshowWidget;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.EnteMemoryWidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -1037,7 +1037,7 @@
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = SlideshowWidgetExtension.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = EnteMemoryWidgetExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@@ -1045,8 +1045,8 @@
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SlideshowWidget/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SlideshowWidget;
|
||||
INFOPLIST_FILE = EnteMemoryWidget/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = EnteMemoryWidget;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 The Chromium Authors. All rights reserved.";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 18.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -1057,7 +1057,7 @@
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.SlideshowWidget;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.EnteMemoryWidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -1089,7 +1089,7 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
CEE6BE812D7AE7FE00E4048B /* Build configuration list for PBXNativeTarget "SlideshowWidgetExtension" */ = {
|
||||
CEE6BE812D7AE7FE00E4048B /* Build configuration list for PBXNativeTarget "EnteMemoryWidgetExtension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
CEE6BE7D2D7AE7FE00E4048B /* Debug */,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</array>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.io.ente.frame.SlideshowWidget</string>
|
||||
<string>group.io.ente.frame.EnteMemoryWidget</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"images":[{"size":"20x20","idiom":"iphone","filename":"IconGreen-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"IconGreen-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"IconGreen-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"IconGreen-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"IconGreen-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"IconGreen-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"IconGreen-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"IconGreen-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"IconGreen-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"IconGreen-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"IconGreen-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"IconGreen-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"IconGreen-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"IconGreen-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"IconGreen-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"IconGreen-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"IconGreen-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"IconGreen-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"IconGreen-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"IconGreen-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"IconGreen-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"IconGreen-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"IconGreen-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"IconGreen-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"IconGreen-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
|
||||
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
@@ -18,6 +18,7 @@ import "package:photos/l10n/l10n.dart";
|
||||
import "package:photos/service_locator.dart";
|
||||
import 'package:photos/services/app_lifecycle_service.dart';
|
||||
import "package:photos/services/home_widget_service.dart";
|
||||
import "package:photos/services/memory_home_widget_service.dart";
|
||||
import 'package:photos/services/sync/sync_service.dart';
|
||||
import 'package:photos/ui/tabs/home_widget.dart';
|
||||
import "package:photos/ui/viewer/actions/file_viewer.dart";
|
||||
@@ -65,10 +66,7 @@ class _EnteAppState extends State<EnteApp> with WidgetsBindingObserver {
|
||||
_memoriesChangedSubscription =
|
||||
Bus.instance.on<MemoriesChangedEvent>().listen(
|
||||
(event) async {
|
||||
await HomeWidgetService.instance.updateMemoryChanged(true);
|
||||
await HomeWidgetService.instance.initHomeWidget(
|
||||
forceFetchNewMemories: true,
|
||||
);
|
||||
await MemoryHomeWidgetService.instance.memoryChanged();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -209,6 +209,7 @@ class Configuration {
|
||||
await UploadLocksDB.instance.clearTable();
|
||||
await IgnoredFilesService.instance.reset();
|
||||
await TrashDB.instance.clearTable();
|
||||
unawaited(HomeWidgetService.instance.clearWidget(autoLogout));
|
||||
if (!autoLogout) {
|
||||
// Following services won't be initialized if it's the case of autoLogout
|
||||
FileUploader.instance.clearCachedUploadURLs();
|
||||
@@ -216,7 +217,6 @@ class Configuration {
|
||||
FavoritesService.instance.clearCache();
|
||||
SearchService.instance.clearCache();
|
||||
PersonService.instance.clearCache();
|
||||
unawaited(HomeWidgetService.instance.clearHomeWidget());
|
||||
Bus.instance.fire(UserLoggedOutEvent());
|
||||
} else {
|
||||
await _preferences.setBool("auto_logout", true);
|
||||
|
||||
@@ -73,7 +73,7 @@ const kSearchSectionLimit = 9;
|
||||
|
||||
const maxPickAssetLimit = 50;
|
||||
|
||||
const iOSGroupID = "group.io.ente.frame.SlideshowWidget";
|
||||
const iOSGroupID = "group.io.ente.frame.EnteMemoryWidget";
|
||||
|
||||
const blackThumbnailBase64 = '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEB'
|
||||
'AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQ'
|
||||
|
||||
@@ -124,7 +124,7 @@ Future<void> _homeWidgetSync() async {
|
||||
try {
|
||||
await HomeWidgetService.instance.initHomeWidget();
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error in initSlideshowWidget", e, s);
|
||||
_logger.severe("Error in syncing home widget", e, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import "dart:convert";
|
||||
import "dart:io";
|
||||
|
||||
import "package:figma_squircle/figma_squircle.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter/scheduler.dart";
|
||||
import "package:fluttertoast/fluttertoast.dart";
|
||||
import 'package:home_widget/home_widget.dart' as hw;
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/core/configuration.dart";
|
||||
import "package:path_provider/path_provider.dart";
|
||||
import "package:path_provider_foundation/path_provider_foundation.dart";
|
||||
import "package:photos/core/constants.dart";
|
||||
import "package:photos/models/file/file.dart";
|
||||
import "package:photos/service_locator.dart";
|
||||
import "package:photos/services/memory_home_widget_service.dart";
|
||||
import "package:photos/services/smart_memories_service.dart";
|
||||
import "package:photos/utils/preload_util.dart";
|
||||
import "package:photos/utils/thumbnail_util.dart";
|
||||
import "package:shared_preferences/shared_preferences.dart";
|
||||
|
||||
@@ -25,83 +22,37 @@ class HomeWidgetService {
|
||||
HomeWidgetService._privateConstructor();
|
||||
|
||||
init(SharedPreferences prefs) {
|
||||
hw.HomeWidget.setAppGroupId(iOSGroupID).ignore();
|
||||
_prefs = prefs;
|
||||
setAppGroupID(iOSGroupID);
|
||||
MemoryHomeWidgetService.instance.init(prefs);
|
||||
}
|
||||
|
||||
static const memoryChangedKey = "memoryChanged.widget";
|
||||
|
||||
bool _hasSyncedMemory = false;
|
||||
|
||||
late final SharedPreferences _prefs;
|
||||
|
||||
Future<void> checkPendingMemorySync() async {
|
||||
await Future.delayed(const Duration(seconds: 5), () {});
|
||||
|
||||
final memoryChanged = _prefs.getBool(memoryChangedKey);
|
||||
final total = await _getTotal();
|
||||
|
||||
final forceFetchNewMemories =
|
||||
memoryChanged == true || total == 0 || total == null;
|
||||
|
||||
if (_hasSyncedMemory && !forceFetchNewMemories) {
|
||||
_logger.info(">>> Memory already synced");
|
||||
return;
|
||||
}
|
||||
await initHomeWidget(forceFetchNewMemories: forceFetchNewMemories);
|
||||
void setAppGroupID(String id) {
|
||||
hw.HomeWidget.setAppGroupId(id).ignore();
|
||||
}
|
||||
|
||||
Future<void> updateMemoryChanged(bool value) async {
|
||||
await _prefs.setBool(memoryChangedKey, value);
|
||||
Future<void> initHomeWidget() async {
|
||||
await MemoryHomeWidgetService.instance.initMemoryHW(null);
|
||||
}
|
||||
|
||||
Future<void> initHomeWidget({
|
||||
bool forceFetchNewMemories = false,
|
||||
Future<bool?> updateWidget({
|
||||
required String androidClass,
|
||||
required String iOSClass,
|
||||
}) async {
|
||||
final isLoggedIn = Configuration.instance.isLoggedIn();
|
||||
if (!isLoggedIn) {
|
||||
_logger.warning("user not logged in");
|
||||
return;
|
||||
}
|
||||
|
||||
final areMemoriesShown = memoriesCacheService.showAnyMemories;
|
||||
if (!areMemoriesShown) {
|
||||
_logger.warning("memories not enabled");
|
||||
await clearHomeWidget();
|
||||
return;
|
||||
}
|
||||
|
||||
if (forceFetchNewMemories) {
|
||||
await _forceMemoryUpdate();
|
||||
} else {
|
||||
final total = await _getTotal();
|
||||
if (total == 0 || total == null) {
|
||||
_logger.warning(
|
||||
"sync stopped because no memory is cached yet, so nothing to sync",
|
||||
);
|
||||
return;
|
||||
}
|
||||
await _memorySync();
|
||||
}
|
||||
return await hw.HomeWidget.updateWidget(
|
||||
name: androidClass,
|
||||
androidName: androidClass,
|
||||
qualifiedAndroidName: 'io.ente.photos.$androidClass',
|
||||
iOSName: iOSClass,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _forceMemoryUpdate() async {
|
||||
await _lockAndLoadMemories();
|
||||
await updateMemoryChanged(false);
|
||||
}
|
||||
Future<T?> getData<T>(String key) async =>
|
||||
await hw.HomeWidget.getWidgetData<T>(key);
|
||||
|
||||
Future<void> _memorySync() async {
|
||||
final homeWidgetCount = await HomeWidgetService.instance.countHomeWidgets();
|
||||
if (homeWidgetCount == 0) {
|
||||
_logger.warning("no home widget active");
|
||||
return;
|
||||
}
|
||||
Future<bool?> setData<T>(String key, T? data) async =>
|
||||
await hw.HomeWidget.saveWidgetData<T>(key, data);
|
||||
|
||||
await _updateWidget(text: "[i] refreshing from same set");
|
||||
_logger.info(">>> Refreshing memory from same set");
|
||||
}
|
||||
|
||||
Future<Size?> _renderFile(
|
||||
Future<Size?> renderFile(
|
||||
EnteFile randomFile,
|
||||
String key,
|
||||
String title,
|
||||
@@ -121,19 +72,6 @@ class HomeWidgetService {
|
||||
return (await hw.HomeWidget.getInstalledWidgets()).length;
|
||||
}
|
||||
|
||||
Future<void> clearHomeWidget() async {
|
||||
final total = await _getTotal();
|
||||
if (total == 0 || total == null) return;
|
||||
|
||||
_logger.info("Clearing SlideshowWidget");
|
||||
|
||||
await _setTotal(0);
|
||||
_hasSyncedMemory = false;
|
||||
|
||||
await _updateWidget(text: "[i] SlideshowWidget cleared & updated");
|
||||
_logger.info(">>> SlideshowWidget cleared");
|
||||
}
|
||||
|
||||
Future<bool> _captureFile(
|
||||
EnteFile ogFile,
|
||||
String key,
|
||||
@@ -142,40 +80,26 @@ class HomeWidgetService {
|
||||
try {
|
||||
final thumbnail = await getThumbnail(ogFile);
|
||||
|
||||
final decoded = await decodeImageFromList(thumbnail!);
|
||||
final double width = decoded.width.toDouble();
|
||||
final double height = decoded.height.toDouble();
|
||||
late final String? directory;
|
||||
|
||||
final Image img = Image.memory(
|
||||
thumbnail,
|
||||
fit: BoxFit.cover,
|
||||
cacheWidth: width.toInt(),
|
||||
cacheHeight: height.toInt(),
|
||||
);
|
||||
// coverage:ignore-start
|
||||
if (Platform.isIOS) {
|
||||
final PathProviderFoundation provider = PathProviderFoundation();
|
||||
directory = await provider.getContainerPath(
|
||||
appGroupIdentifier: iOSGroupID,
|
||||
);
|
||||
} else {
|
||||
directory = (await getApplicationSupportDirectory()).path;
|
||||
}
|
||||
|
||||
await PreloadImage.loadImage(img.image);
|
||||
final String path = '$directory/home_widget/$key.png';
|
||||
final File file = File(path);
|
||||
if (!await file.exists()) {
|
||||
await file.create(recursive: true);
|
||||
}
|
||||
await file.writeAsBytes(thumbnail!);
|
||||
|
||||
final platformBrightness =
|
||||
SchedulerBinding.instance.platformDispatcher.platformBrightness;
|
||||
|
||||
final widget = ClipSmoothRect(
|
||||
radius: SmoothBorderRadius(cornerRadius: 32, cornerSmoothing: 1),
|
||||
child: Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: platformBrightness == Brightness.light
|
||||
? const Color.fromRGBO(251, 251, 251, 1)
|
||||
: const Color.fromRGBO(27, 27, 27, 1),
|
||||
image: DecorationImage(image: img.image, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
);
|
||||
await hw.HomeWidget.renderFlutterWidget(
|
||||
widget,
|
||||
logicalSize: Size(width, height),
|
||||
key: key,
|
||||
);
|
||||
await setData(key, path);
|
||||
|
||||
final data = {
|
||||
"title": title,
|
||||
@@ -202,115 +126,32 @@ class HomeWidgetService {
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> clearWidget(bool autoLogout) async {
|
||||
if (autoLogout) {
|
||||
setAppGroupID(iOSGroupID);
|
||||
}
|
||||
await MemoryHomeWidgetService.instance.clearWidget();
|
||||
}
|
||||
|
||||
Future<void> onLaunchFromWidget(Uri? uri, BuildContext context) async {
|
||||
if (uri == null) {
|
||||
_logger.warning("onLaunchFromWidget: uri is null");
|
||||
return;
|
||||
}
|
||||
|
||||
_hasSyncedMemory = true;
|
||||
// sync the memories
|
||||
initHomeWidget().ignore();
|
||||
|
||||
final generatedId = int.tryParse(uri.queryParameters["generatedId"] ?? "");
|
||||
_logger.info("onLaunchFromWidget: $uri, $generatedId");
|
||||
|
||||
if (generatedId == null) {
|
||||
_logger.warning("onLaunchFromWidget: generatedId is null");
|
||||
return;
|
||||
}
|
||||
|
||||
await memoriesCacheService.goToMemoryFromGeneratedFileID(
|
||||
context,
|
||||
generatedId,
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, Iterable<EnteFile>>> _getMemories() async {
|
||||
// if (fetchMemory) {
|
||||
final memories = await memoriesCacheService.getMemories();
|
||||
if (memories.isEmpty) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// flatten the list to list of ente files
|
||||
final files = memories.asMap().map(
|
||||
(k, v) => MapEntry(
|
||||
v.title,
|
||||
v.memories.map((e) => e.file),
|
||||
),
|
||||
);
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
Future<void> _updateWidget({String? text}) async {
|
||||
await hw.HomeWidget.updateWidget(
|
||||
name: 'SlideshowWidgetProvider',
|
||||
androidName: 'SlideshowWidgetProvider',
|
||||
qualifiedAndroidName: 'io.ente.photos.SlideshowWidgetProvider',
|
||||
iOSName: 'SlideshowWidget',
|
||||
);
|
||||
if (flagService.internalUser) {
|
||||
await Fluttertoast.showToast(
|
||||
msg: text ?? "[i] SlideshowWidget updated",
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
timeInSecForIosWeb: 1,
|
||||
backgroundColor: Colors.black,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
if (uri.scheme == "memorywidget") {
|
||||
_logger.info("onLaunchFromWidget: redirecting to memory widget");
|
||||
await MemoryHomeWidgetService.instance.onLaunchFromWidget(
|
||||
generatedId,
|
||||
context,
|
||||
);
|
||||
}
|
||||
_logger.info(">>> Home Widget updated");
|
||||
}
|
||||
|
||||
Future<int?> _getTotal() async {
|
||||
return await hw.HomeWidget.getWidgetData<int>("totalSet");
|
||||
}
|
||||
|
||||
Future<void> _setTotal(int total) async {
|
||||
await hw.HomeWidget.saveWidgetData("totalSet", total);
|
||||
}
|
||||
|
||||
Future<void> _lockAndLoadMemories() async {
|
||||
final files = await _getMemories();
|
||||
|
||||
if (files.isEmpty) {
|
||||
_logger.warning("No files found, clearing everything");
|
||||
await clearHomeWidget();
|
||||
return;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (final i in files.entries) {
|
||||
for (final file in i.value) {
|
||||
final value =
|
||||
await _renderFile(file, "slideshow_$index", i.key).catchError(
|
||||
(e, sT) {
|
||||
_logger.severe("Error rendering widget", e, sT);
|
||||
return null;
|
||||
},
|
||||
);
|
||||
|
||||
if (value != null) {
|
||||
await _setTotal(index);
|
||||
if (index == 1) {
|
||||
await _updateWidget(
|
||||
text: "[i] First memory fetched. updating widget",
|
||||
);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
await _updateWidget();
|
||||
_logger.info(">>> Switching to next memory set");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,6 +370,10 @@ class MemoriesCacheService {
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<SmartMemory>?> getCachedMemories() async {
|
||||
return _cachedMemories;
|
||||
}
|
||||
|
||||
Future<void> goToMemoryFromGeneratedFileID(
|
||||
BuildContext context,
|
||||
int generatedFileID,
|
||||
|
||||
253
mobile/lib/services/memory_home_widget_service.dart
Normal file
@@ -0,0 +1,253 @@
|
||||
import "package:flutter/material.dart";
|
||||
import "package:fluttertoast/fluttertoast.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/models/file/file.dart";
|
||||
import "package:photos/service_locator.dart";
|
||||
import "package:photos/services/home_widget_service.dart";
|
||||
import "package:photos/services/sync/local_sync_service.dart";
|
||||
import "package:shared_preferences/shared_preferences.dart";
|
||||
import "package:synchronized/synchronized.dart";
|
||||
|
||||
class MemoryHomeWidgetService {
|
||||
final Logger _logger = Logger((MemoryHomeWidgetService).toString());
|
||||
|
||||
MemoryHomeWidgetService._privateConstructor();
|
||||
|
||||
static final MemoryHomeWidgetService instance =
|
||||
MemoryHomeWidgetService._privateConstructor();
|
||||
|
||||
late final SharedPreferences _prefs;
|
||||
|
||||
final _memoryForceRefreshLock = Lock();
|
||||
bool _hasSyncedMemory = false;
|
||||
|
||||
static const memoryChangedKey = "memoryChanged.widget";
|
||||
static const totalMemories = "totalMemories";
|
||||
|
||||
init(SharedPreferences prefs) {
|
||||
_prefs = prefs;
|
||||
}
|
||||
|
||||
Future<void> _forceMemoryUpdate() async {
|
||||
await _lockAndLoadMemories();
|
||||
await updateMemoryChanged(false);
|
||||
}
|
||||
|
||||
Future<void> _memorySync() async {
|
||||
final homeWidgetCount = await HomeWidgetService.instance.countHomeWidgets();
|
||||
if (homeWidgetCount == 0) {
|
||||
_logger.warning("no home widget active");
|
||||
return;
|
||||
}
|
||||
|
||||
await _updateWidget(text: "refreshing from same set");
|
||||
}
|
||||
|
||||
Future<bool> hasAnyBlockers() async {
|
||||
final hasCompletedFirstImport =
|
||||
LocalSyncService.instance.hasCompletedFirstImport();
|
||||
if (!hasCompletedFirstImport) {
|
||||
_logger.warning("first import not completed");
|
||||
return true;
|
||||
}
|
||||
|
||||
final areMemoriesShown = memoriesCacheService.showAnyMemories;
|
||||
if (!areMemoriesShown) {
|
||||
_logger.warning("memories not enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<void> initMemoryHW(bool? forceFetchNewMemories) async {
|
||||
final result = await hasAnyBlockers();
|
||||
if (result) {
|
||||
await clearWidget();
|
||||
return;
|
||||
}
|
||||
|
||||
await _memoryForceRefreshLock.synchronized(() async {
|
||||
final isTotalEmpty = await _checkIfTotalEmpty();
|
||||
forceFetchNewMemories ??= await getForceFetchCondition(isTotalEmpty);
|
||||
|
||||
_logger.warning(
|
||||
"init memory hw: forceFetch: $forceFetchNewMemories, isTotalEmpty: $isTotalEmpty",
|
||||
);
|
||||
|
||||
if (forceFetchNewMemories!) {
|
||||
await _forceMemoryUpdate();
|
||||
} else if (!isTotalEmpty) {
|
||||
await _memorySync();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> clearWidget() async {
|
||||
final isTotalEmpty = await _checkIfTotalEmpty();
|
||||
if (isTotalEmpty) {
|
||||
_logger.info(">>> Nothing to clear");
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.info("Clearing MemoryHomeWidget");
|
||||
|
||||
await _setTotal(null);
|
||||
_hasSyncedMemory = false;
|
||||
|
||||
await _updateWidget(text: "MemoryHomeWidget cleared & updated");
|
||||
}
|
||||
|
||||
Future<void> updateMemoryChanged(bool value) async {
|
||||
_logger.info("Updating memory changed to $value");
|
||||
await _prefs.setBool(memoryChangedKey, value);
|
||||
}
|
||||
|
||||
Future<bool> _checkIfTotalEmpty() async {
|
||||
final total = await _getTotal();
|
||||
return total == 0 || total == null;
|
||||
}
|
||||
|
||||
Future<bool> getForceFetchCondition(bool isTotalEmpty) async {
|
||||
final memoryChanged = _prefs.getBool(memoryChangedKey);
|
||||
if (memoryChanged == true) return true;
|
||||
|
||||
final cachedMemories = await memoriesCacheService.getCachedMemories();
|
||||
|
||||
final forceFetchNewMemories =
|
||||
isTotalEmpty && (cachedMemories?.isNotEmpty ?? false);
|
||||
return forceFetchNewMemories;
|
||||
}
|
||||
|
||||
Future<void> checkPendingMemorySync() async {
|
||||
await Future.delayed(const Duration(seconds: 5), () {});
|
||||
|
||||
final isTotalEmpty = await _checkIfTotalEmpty();
|
||||
final forceFetchNewMemories = await getForceFetchCondition(isTotalEmpty);
|
||||
|
||||
if (_hasSyncedMemory && !forceFetchNewMemories) {
|
||||
_logger.info(">>> Memory already synced");
|
||||
return;
|
||||
}
|
||||
await HomeWidgetService.instance.initHomeWidget();
|
||||
}
|
||||
|
||||
Future<Map<String, Iterable<EnteFile>>> _getMemories() async {
|
||||
final memories = await memoriesCacheService.getMemories();
|
||||
if (memories.isEmpty) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// flatten the memories to a list of files and take first 50
|
||||
final files = memories.take(50).toList().asMap().map(
|
||||
(k, v) => MapEntry(
|
||||
v.title,
|
||||
v.memories.map((e) => e.file),
|
||||
),
|
||||
);
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
Future<void> _updateWidget({String? text}) async {
|
||||
await HomeWidgetService.instance.updateWidget(
|
||||
androidClass: "EnteMemoryWidgetProvider",
|
||||
iOSClass: "EnteMemoryWidget",
|
||||
);
|
||||
if (flagService.internalUser) {
|
||||
await Fluttertoast.showToast(
|
||||
msg: "[i] ${text ?? "MemoryHomeWidget updated"}",
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
timeInSecForIosWeb: 1,
|
||||
backgroundColor: Colors.black,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
_logger.info(">>> Home Widget updated, type: ${text ?? "normal"}");
|
||||
}
|
||||
|
||||
Future<void> memoryChanged() async {
|
||||
final cachedMemories = await memoriesCacheService.getCachedMemories();
|
||||
final currentTotal = cachedMemories?.length ?? 0;
|
||||
|
||||
final int total = await _getTotal() ?? 0;
|
||||
|
||||
if (total == currentTotal && total == 0) {
|
||||
_logger.info(">>> Memories not changed, doing nothing");
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.info(">>> Memories changed, updating widget");
|
||||
await updateMemoryChanged(true);
|
||||
await initMemoryHW(true);
|
||||
}
|
||||
|
||||
Future<int?> _getTotal() async {
|
||||
return HomeWidgetService.instance.getData<int>(totalMemories);
|
||||
}
|
||||
|
||||
Future<void> _setTotal(int? total) async =>
|
||||
await HomeWidgetService.instance.setData(totalMemories, total);
|
||||
|
||||
Future<void> _lockAndLoadMemories() async {
|
||||
final files = await _getMemories();
|
||||
|
||||
if (files.isEmpty) {
|
||||
_logger.warning("No files found, clearing everything");
|
||||
await clearWidget();
|
||||
return;
|
||||
}
|
||||
|
||||
final total = await _getTotal();
|
||||
_logger.info(">>> Total memories before: $total");
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (final i in files.entries) {
|
||||
for (final file in i.value) {
|
||||
final value = await HomeWidgetService.instance
|
||||
.renderFile(file, "memory_widget_$index", i.key)
|
||||
.catchError(
|
||||
(e, sT) {
|
||||
_logger.severe("Error rendering widget", e, sT);
|
||||
return null;
|
||||
},
|
||||
);
|
||||
|
||||
if (value != null) {
|
||||
final result = await hasAnyBlockers();
|
||||
if (result) {
|
||||
return;
|
||||
}
|
||||
await _setTotal(index);
|
||||
if (index == 1) {
|
||||
await _updateWidget(
|
||||
text: "First memory fetched. updating widget",
|
||||
);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
await _updateWidget(
|
||||
text: ">>> Switching to next memory set, total: $index",
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> onLaunchFromWidget(int generatedId, BuildContext context) async {
|
||||
_hasSyncedMemory = true;
|
||||
await _memorySync();
|
||||
|
||||
await memoriesCacheService.goToMemoryFromGeneratedFileID(
|
||||
context,
|
||||
generatedId,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,11 @@ import "package:photos/db/ml/db.dart";
|
||||
import "package:photos/events/people_changed_event.dart";
|
||||
import "package:photos/models/ml/face/person.dart";
|
||||
import "package:photos/service_locator.dart";
|
||||
import "package:photos/services/home_widget_service.dart";
|
||||
import "package:photos/services/machine_learning/face_ml/person/person_service.dart";
|
||||
import "package:photos/services/machine_learning/ml_indexing_isolate.dart";
|
||||
import 'package:photos/services/machine_learning/ml_service.dart';
|
||||
import "package:photos/services/machine_learning/semantic_search/semantic_search_service.dart";
|
||||
import "package:photos/services/memory_home_widget_service.dart";
|
||||
import 'package:photos/theme/ente_theme.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
@@ -322,13 +322,13 @@ class _MLDebugSectionWidgetState extends State<MLDebugSectionWidget> {
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Force sync memory widget",
|
||||
title: "Force memory widget data refresh",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async => await HomeWidgetService.instance
|
||||
.initHomeWidget(forceFetchNewMemories: true),
|
||||
onTap: () async =>
|
||||
await MemoryHomeWidgetService.instance.initMemoryHW(true),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
@@ -338,7 +338,8 @@ class _MLDebugSectionWidgetState extends State<MLDebugSectionWidget> {
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async => await HomeWidgetService.instance.initHomeWidget(),
|
||||
onTap: () async =>
|
||||
await MemoryHomeWidgetService.instance.initMemoryHW(false),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
|
||||
@@ -5,7 +5,7 @@ import "package:photos/core/event_bus.dart";
|
||||
import "package:photos/events/hide_shared_items_from_home_gallery_event.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/service_locator.dart";
|
||||
import "package:photos/services/home_widget_service.dart";
|
||||
import "package:photos/services/memory_home_widget_service.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
||||
import "package:photos/ui/components/captioned_text_widget.dart";
|
||||
@@ -109,7 +109,8 @@ class _GallerySettingsScreenState extends State<GallerySettingsScreen> {
|
||||
),
|
||||
);
|
||||
unawaited(
|
||||
HomeWidgetService.instance.initHomeWidget(),
|
||||
MemoryHomeWidgetService.instance
|
||||
.initMemoryHW(true),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -37,8 +37,8 @@ import "package:photos/service_locator.dart";
|
||||
import 'package:photos/services/account/user_service.dart';
|
||||
import 'package:photos/services/app_lifecycle_service.dart';
|
||||
import 'package:photos/services/collections_service.dart';
|
||||
import "package:photos/services/home_widget_service.dart";
|
||||
import "package:photos/services/machine_learning/face_ml/person/person_service.dart";
|
||||
import "package:photos/services/memory_home_widget_service.dart";
|
||||
import "package:photos/services/notification_service.dart";
|
||||
import "package:photos/services/sync/diff_fetcher.dart";
|
||||
import 'package:photos/services/sync/local_sync_service.dart';
|
||||
@@ -124,7 +124,9 @@ class _HomeWidgetState extends State<HomeWidget> {
|
||||
_logger.info("Building initstate");
|
||||
super.initState();
|
||||
|
||||
HomeWidgetService.instance.checkPendingMemorySync();
|
||||
if (LocalSyncService.instance.hasCompletedFirstImport()) {
|
||||
MemoryHomeWidgetService.instance.checkPendingMemorySync();
|
||||
}
|
||||
_tabChangedEventSubscription =
|
||||
Bus.instance.on<TabChangedEvent>().listen((event) {
|
||||
_selectedTabIndex = event.selectedIndex;
|
||||
@@ -184,13 +186,11 @@ class _HomeWidgetState extends State<HomeWidget> {
|
||||
}
|
||||
Future.delayed(
|
||||
delayInRefresh,
|
||||
() => {
|
||||
if (mounted)
|
||||
{
|
||||
setState(
|
||||
() {},
|
||||
),
|
||||
},
|
||||
() {
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
MemoryHomeWidgetService.instance.checkPendingMemorySync();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ description: ente photos application
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
|
||||
version: 0.9.118+1028
|
||||
version: 0.9.119+1029
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
@@ -189,7 +189,7 @@ dependencies:
|
||||
styled_text: ^8.1.0
|
||||
syncfusion_flutter_core: ^25.2.5
|
||||
syncfusion_flutter_sliders: ^25.2.5
|
||||
synchronized: ^3.1.0
|
||||
synchronized: ^3.3.0+3
|
||||
system_info_plus: ^0.0.6
|
||||
tuple: ^2.0.0
|
||||
ua_client_hints: ^1.4.0
|
||||
|
||||