Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,9 @@ dependencies {

implementation "com.squareup.okhttp3:okhttp:5.3.2"
implementation "io.github.g00fy2:versioncompare:1.5.0"

def work_version = "2.9.1"
implementation "androidx.work:work-runtime-ktx:$work_version"

implementation 'com.github.bumptech.glide:glide:4.16.0'
}
14 changes: 14 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>

<receiver
android:name=".widget.MemoriesWidget"
android:exported="true"
android:label="@string/widget_title">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="gallery.memories.widget.ACTION_REFRESH" />
</intent-filter>

<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>
</application>

</manifest>
15 changes: 15 additions & 0 deletions android/app/src/main/java/gallery/memories/dao/PhotoDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,24 @@ interface PhotoDao {
@Query("SELECT 1")
fun ping(): Int

@Query("SELECT COUNT(*) FROM photos")
fun getCount(): Int

@Query("SELECT dayid, COUNT(local_id) AS count FROM photos WHERE bucket_id IN (:bucketIds) AND has_remote = 0 GROUP BY dayid ORDER BY dayid DESC")
fun getDays(bucketIds: List<String>): List<Day>

@Query("SELECT * FROM photos WHERE bucket_id IN (:bucketIds) ORDER BY RANDOM() LIMIT 1")
fun getRandomPhoto(bucketIds: List<String>): Photo?

@Query("SELECT * FROM photos WHERE strftime('%m-%d', date_taken, 'unixepoch') = :date AND bucket_id IN (:bucketIds) ORDER BY date_taken DESC")
fun getOnThisDayPhotos(date: String, bucketIds: List<String>): List<Photo>

@Query("SELECT * FROM photos ORDER BY RANDOM() LIMIT 1")
fun getRandomPhotoAny(): Photo?

@Query("SELECT * FROM photos WHERE strftime('%m-%d', date_taken, 'unixepoch') = :date ORDER BY date_taken DESC")
fun getOnThisDayPhotosAny(date: String): List<Photo>

@Query("SELECT * FROM photos WHERE dayid=:dayId AND bucket_id IN (:buckets) AND has_remote = 0 ORDER BY date_taken DESC")
fun getPhotosByDay(dayId: Long, buckets: List<String>): List<Photo>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package gallery.memories.widget

import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.widget.RemoteViews
import androidx.work.*
import gallery.memories.MainActivity
import gallery.memories.R
import java.util.concurrent.TimeUnit

class MemoriesWidget : AppWidgetProvider() {

override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
scheduleWidgetUpdate(context)
}

override fun onEnabled(context: Context) {
scheduleWidgetUpdate(context)
}

override fun onDisabled(context: Context) {
WorkManager.getInstance(context).cancelUniqueWork(WORK_NAME)
}

override fun onReceive(context: Context, intent: Intent) {
super.onReceive(context, intent)
if (intent.action == ACTION_REFRESH) {
// User tapped refresh — enqueue a one-time immediate update
val oneTimeRequest = OneTimeWorkRequestBuilder<WidgetWorker>().build()
WorkManager.getInstance(context).enqueue(oneTimeRequest)
}
}

private fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
val views = RemoteViews(context.packageName, R.layout.widget_memories)

// Click root to open app
val openIntent = Intent(context, MainActivity::class.java)
val openPending = PendingIntent.getActivity(
context, 0, openIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
views.setOnClickPendingIntent(R.id.widget_root, openPending)

// Refresh button
val refreshIntent = Intent(context, MemoriesWidget::class.java).apply {
action = ACTION_REFRESH
}
val refreshPending = PendingIntent.getBroadcast(
context, 0, refreshIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
views.setOnClickPendingIntent(R.id.widget_refresh_btn, refreshPending)

appWidgetManager.updateAppWidget(appWidgetId, views)
}

private fun scheduleWidgetUpdate(context: Context) {
val workRequest = PeriodicWorkRequestBuilder<WidgetWorker>(
30, TimeUnit.MINUTES
)
.setConstraints(
Constraints.Builder()
.setRequiresBatteryNotLow(true)

Copilot AI Feb 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WorkManager constraints only check for battery not being low, but don't check for network connectivity. Since the widget's primary function is to fetch photos from the server, consider adding a network constraint (setRequiredNetworkType(NetworkType.CONNECTED)) to avoid unnecessary work attempts when offline. This would make the battery constraint more effective and prevent the worker from running when it's guaranteed to fall back to cached/local photos.

Suggested change
.setRequiresBatteryNotLow(true)
.setRequiresBatteryNotLow(true)
.setRequiredNetworkType(NetworkType.CONNECTED)

Copilot uses AI. Check for mistakes.
.build()
)
.build()

WorkManager.getInstance(context).enqueueUniquePeriodicWork(
WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
workRequest
)

// Also trigger an immediate one-time update
val oneTimeRequest = OneTimeWorkRequestBuilder<WidgetWorker>().build()
WorkManager.getInstance(context).enqueue(oneTimeRequest)
}

companion object {
const val ACTION_REFRESH = "gallery.memories.widget.ACTION_REFRESH"
private const val WORK_NAME = "MemoriesWidgetUpdate"
}
}
Loading
Loading