Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
13 changes: 12 additions & 1 deletion app/src/main/java/org/cssnr/remotewallpaper/db/RemoteDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.Transaction
import androidx.room.Upsert
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import java.util.concurrent.Executors

Expand Down Expand Up @@ -68,17 +69,26 @@ data class Remote(
//@PrimaryKey(autoGenerate = true) val id: Long = 0,
@PrimaryKey val url: String,
val active: Boolean = false,
val etag: String? = null,
val lastModified: String? = null,
)


@Database(entities = [Remote::class], version = 1, exportSchema = false)
@Database(entities = [Remote::class], version = 2, exportSchema = false)
abstract class RemoteDatabase : RoomDatabase() {
abstract fun remoteDao(): RemoteDao

companion object {
@Volatile
private var instance: RemoteDatabase? = null

private val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Remote ADD COLUMN etag TEXT DEFAULT NULL")
db.execSQL("ALTER TABLE Remote ADD COLUMN lastModified TEXT DEFAULT NULL")
}
}

private val defaultData: List<Remote> = listOf(
Remote("https://picsum.photos/4800/2400", active = true),
Remote("https://picsum.photos/4800/2400?blur=10", active = false),
Expand All @@ -103,6 +113,7 @@ abstract class RemoteDatabase : RoomDatabase() {
}
}
})
.addMigrations(MIGRATION_1_2)
.build().also { instance = it }
}
}
Expand Down
52 changes: 41 additions & 11 deletions app/src/main/java/org/cssnr/remotewallpaper/ui/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import org.cssnr.remotewallpaper.R
import org.cssnr.remotewallpaper.databinding.FragmentHomeBinding
import org.cssnr.remotewallpaper.db.HistoryDatabase
import org.cssnr.remotewallpaper.db.HistoryItem
import org.cssnr.remotewallpaper.db.Remote
import org.cssnr.remotewallpaper.db.RemoteDatabase
import java.io.File
import java.io.FileOutputStream
Expand Down Expand Up @@ -188,7 +189,7 @@ fun Context.showAddDialog() {
if (url.isNotEmpty()) {
CoroutineScope(Dispatchers.IO).launch {
try {
downloadImage(url)
downloadImage(Remote(url = url))
withContext(Dispatchers.Main) {
Toast.makeText(this@showAddDialog, "Done.", Toast.LENGTH_SHORT).show()
dialog.dismiss()
Expand All @@ -208,6 +209,11 @@ fun Context.showAddDialog() {
dialog.show()
}

sealed class DownloadResult {
data class Downloaded(val response: Response) : DownloadResult()
data object NotModified : DownloadResult()
}

// TODO: updateWallpaper is used globally to update the wallpaper and should be a package
// The rest of the functions are only used by updateWallpaper and are internal to updateWallpaper
suspend fun Context.updateWallpaper(): Boolean {
Expand All @@ -220,10 +226,19 @@ suspend fun Context.updateWallpaper(): Boolean {
Log.d("updateWallpaper", "remote: $remote")
if (remote != null) {
history.remote = remote.url
val response = withContext(Dispatchers.IO) { downloadImage(remote.url) }
history.status = response.code
history.url = response.request.url.toString()
Log.d("updateWallpaper", "response: $response")
val result = withContext(Dispatchers.IO) { downloadImage(remote) }
when (result) {
is DownloadResult.Downloaded -> {
history.status = result.response.code
history.url = result.response.request.url.toString()
Log.d("updateWallpaper", "response: ${result.response}")
}
is DownloadResult.NotModified -> {
history.status = 304
history.url = remote.url
Log.i("updateWallpaper", "Image not modified, skipping wallpaper update")
}
}
// TODO: Replace timestamp with history.timestamp
val timestamp: String =
ZonedDateTime.now().format(DateTimeFormatter.ISO_ZONED_DATE_TIME)
Expand All @@ -246,19 +261,34 @@ suspend fun Context.updateWallpaper(): Boolean {
}
}

fun Context.downloadImage(url: String): Response {
suspend fun Context.downloadImage(remote: Remote): DownloadResult {
val client = OkHttpClient.Builder()
.followRedirects(true)
.build()

val request = Request.Builder()
.url(url)
.build()
val requestBuilder = Request.Builder().url(remote.url)
remote.etag?.let { requestBuilder.header("If-None-Match", it) }
remote.lastModified?.let { requestBuilder.header("If-Modified-Since", it) }

val response = client.newCall(request).execute()
val response = client.newCall(requestBuilder.build()).execute()

response.use {
if (it.code == 304) {
Log.d("downloadImage", "304 Not Modified for ${remote.url}")
return DownloadResult.NotModified
}
if (!it.isSuccessful) throw Exception("Failed to download image: $it")

val newEtag = it.header("ETag")
val newLastModified = it.header("Last-Modified")
if (newEtag != null || newLastModified != null) {
val dao = RemoteDatabase.getInstance(this).remoteDao()
withContext(Dispatchers.IO) {
dao.addOrUpdate(remote.copy(etag = newEtag, lastModified = newLastModified))
}
Log.d("downloadImage", "Saved cache headers: etag=$newEtag, lastModified=$newLastModified")
}

val body = it.body
val imageFile = File(filesDir, "wallpaper.img")

Expand All @@ -270,7 +300,7 @@ fun Context.downloadImage(url: String): Response {

setAutoCroppedWallpaper(imageFile)
}
return response
return DownloadResult.Downloaded(response)
}

fun Context.setAutoCroppedWallpaper(imageFile: File) {
Expand Down
Loading