Refactor
parent
0eee69bacb
commit
2f065e6d12
|
@ -24,21 +24,6 @@ import java.net.URLDecoder
|
||||||
val image = ImageService(mCtx, query)
|
val image = ImageService(mCtx, query)
|
||||||
val account = AccountService(mCtx)
|
val account = AccountService(mCtx)
|
||||||
|
|
||||||
object API {
|
|
||||||
val DAYS = Regex("^/api/days$")
|
|
||||||
val DAY = Regex("^/api/days/\\d+$")
|
|
||||||
|
|
||||||
val IMAGE_INFO = Regex("^/api/image/info/\\d+$")
|
|
||||||
val IMAGE_DELETE = Regex("^/api/image/delete/\\d+(,\\d+)*$")
|
|
||||||
|
|
||||||
val IMAGE_PREVIEW = Regex("^/image/preview/\\d+$")
|
|
||||||
val IMAGE_FULL = Regex("^/image/full/\\d+$")
|
|
||||||
|
|
||||||
val SHARE_URL = Regex("^/api/share/url/.+$")
|
|
||||||
val SHARE_BLOB = Regex("^/api/share/blob/.+$")
|
|
||||||
val SHARE_LOCAL = Regex("^/api/share/local/\\d+$")
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
dlService = DownloadService(mCtx, query)
|
dlService = DownloadService(mCtx, query)
|
||||||
}
|
}
|
||||||
|
@ -52,38 +37,19 @@ import java.net.URLDecoder
|
||||||
query.destroy()
|
query.destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleRequest(request: WebResourceRequest): WebResourceResponse {
|
object API {
|
||||||
val path = request.url.path ?: return makeErrorResponse()
|
val DAYS = Regex("^/api/days$")
|
||||||
|
val DAY = Regex("^/api/days/\\d+$")
|
||||||
|
|
||||||
val response = try {
|
val IMAGE_INFO = Regex("^/api/image/info/\\d+$")
|
||||||
when (request.method) {
|
val IMAGE_DELETE = Regex("^/api/image/delete/\\d+(,\\d+)*$")
|
||||||
"GET" -> {
|
|
||||||
routerGet(request)
|
|
||||||
}
|
|
||||||
"OPTIONS" -> {
|
|
||||||
WebResourceResponse("text/plain", "UTF-8", ByteArrayInputStream("".toByteArray()))
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
throw Exception("Method Not Allowed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.w(TAG, "handleRequest: ", e)
|
|
||||||
makeErrorResponse()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow CORS from all origins
|
val IMAGE_PREVIEW = Regex("^/image/preview/\\d+$")
|
||||||
response.responseHeaders = mutableMapOf(
|
val IMAGE_FULL = Regex("^/image/full/\\d+$")
|
||||||
"Access-Control-Allow-Origin" to "*",
|
|
||||||
"Access-Control-Allow-Headers" to "*"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Cache image responses for 7 days
|
val SHARE_URL = Regex("^/api/share/url/.+$")
|
||||||
if (path.matches(API.IMAGE_PREVIEW) || path.matches(API.IMAGE_FULL)) {
|
val SHARE_BLOB = Regex("^/api/share/blob/.+$")
|
||||||
response.responseHeaders["Cache-Control"] = "max-age=604800"
|
val SHARE_LOCAL = Regex("^/api/share/local/\\d+$")
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
|
@ -188,6 +154,40 @@ import java.net.URLDecoder
|
||||||
return query.localFolders.toString()
|
return query.localFolders.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun handleRequest(request: WebResourceRequest): WebResourceResponse {
|
||||||
|
val path = request.url.path ?: return makeErrorResponse()
|
||||||
|
|
||||||
|
val response = try {
|
||||||
|
when (request.method) {
|
||||||
|
"GET" -> {
|
||||||
|
routerGet(request)
|
||||||
|
}
|
||||||
|
"OPTIONS" -> {
|
||||||
|
WebResourceResponse("text/plain", "UTF-8", ByteArrayInputStream("".toByteArray()))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
throw Exception("Method Not Allowed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "handleRequest: ", e)
|
||||||
|
makeErrorResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow CORS from all origins
|
||||||
|
response.responseHeaders = mutableMapOf(
|
||||||
|
"Access-Control-Allow-Origin" to "*",
|
||||||
|
"Access-Control-Allow-Headers" to "*"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cache image responses for 7 days
|
||||||
|
if (path.matches(API.IMAGE_PREVIEW) || path.matches(API.IMAGE_FULL)) {
|
||||||
|
response.responseHeaders["Cache-Control"] = "max-age=604800"
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
private fun routerGet(request: WebResourceRequest): WebResourceResponse {
|
private fun routerGet(request: WebResourceRequest): WebResourceResponse {
|
||||||
val path = request.url.path ?: return makeErrorResponse()
|
val path = request.url.path ?: return makeErrorResponse()
|
||||||
|
@ -196,7 +196,7 @@ import java.net.URLDecoder
|
||||||
return if (path.matches(API.DAYS)) {
|
return if (path.matches(API.DAYS)) {
|
||||||
makeResponse(query.getDays())
|
makeResponse(query.getDays())
|
||||||
} else if (path.matches(API.DAY)) {
|
} else if (path.matches(API.DAY)) {
|
||||||
makeResponse(query.getByDayId(parts[3].toLong()))
|
makeResponse(query.getDay(parts[3].toLong()))
|
||||||
} else if (path.matches(API.IMAGE_INFO)) {
|
} else if (path.matches(API.IMAGE_INFO)) {
|
||||||
makeResponse(query.getImageInfo(parts[4].toLong()))
|
makeResponse(query.getImageInfo(parts[4].toLong()))
|
||||||
} else if (path.matches(API.IMAGE_DELETE)) {
|
} else if (path.matches(API.IMAGE_DELETE)) {
|
||||||
|
|
|
@ -26,12 +26,11 @@ class AccountService(private val mCtx: MainActivity) {
|
||||||
var authHeader: String? = null
|
var authHeader: String? = null
|
||||||
var memoriesUrl: String? = null
|
var memoriesUrl: String? = null
|
||||||
|
|
||||||
private fun toast(message: String) {
|
/**
|
||||||
mCtx.runOnUiThread {
|
* Login to a server
|
||||||
Toast.makeText(mCtx, message, Toast.LENGTH_LONG).show()
|
* @param baseUrl The base URL of the server
|
||||||
}
|
* @param loginFlowUrl The login flow URL
|
||||||
}
|
*/
|
||||||
|
|
||||||
fun login(baseUrl: String, loginFlowUrl: String) {
|
fun login(baseUrl: String, loginFlowUrl: String) {
|
||||||
// Make POST request to login flow URL
|
// Make POST request to login flow URL
|
||||||
val client = OkHttpClient()
|
val client = OkHttpClient()
|
||||||
|
@ -84,6 +83,12 @@ class AccountService(private val mCtx: MainActivity) {
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Poll the login flow URL until we get a login token
|
||||||
|
* @param pollUrl The login flow URL
|
||||||
|
* @param pollToken The login token
|
||||||
|
* @param baseUrl The base URL of the server
|
||||||
|
*/
|
||||||
private fun pollLogin(pollUrl: String, pollToken: String, baseUrl: String) {
|
private fun pollLogin(pollUrl: String, pollToken: String, baseUrl: String) {
|
||||||
mCtx.binding.webview.post {
|
mCtx.binding.webview.post {
|
||||||
mCtx.binding.webview.loadUrl("file:///android_asset/sync.html")
|
mCtx.binding.webview.loadUrl("file:///android_asset/sync.html")
|
||||||
|
@ -141,6 +146,10 @@ class AccountService(private val mCtx: MainActivity) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the credentials are valid and the server version is supported
|
||||||
|
* Makes a toast to the user if something is wrong
|
||||||
|
*/
|
||||||
fun checkCredentialsAndVersion() {
|
fun checkCredentialsAndVersion() {
|
||||||
if (memoriesUrl == null) return
|
if (memoriesUrl == null) return
|
||||||
|
|
||||||
|
@ -192,6 +201,9 @@ class AccountService(private val mCtx: MainActivity) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a logout. Delete the stored credentials and go back to the login screen.
|
||||||
|
*/
|
||||||
fun loggedOut() {
|
fun loggedOut() {
|
||||||
toast(mCtx.getString(R.string.err_logged_out))
|
toast(mCtx.getString(R.string.err_logged_out))
|
||||||
deleteCredentials()
|
deleteCredentials()
|
||||||
|
@ -200,6 +212,12 @@ class AccountService(private val mCtx: MainActivity) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the credentials
|
||||||
|
* @param url The URL to store
|
||||||
|
* @param user The username to store
|
||||||
|
* @param password The password to store
|
||||||
|
*/
|
||||||
fun storeCredentials(url: String, user: String, password: String) {
|
fun storeCredentials(url: String, user: String, password: String) {
|
||||||
mCtx.getSharedPreferences("credentials", 0).edit()
|
mCtx.getSharedPreferences("credentials", 0).edit()
|
||||||
.putString("memoriesUrl", url)
|
.putString("memoriesUrl", url)
|
||||||
|
@ -210,6 +228,10 @@ class AccountService(private val mCtx: MainActivity) {
|
||||||
setAuthHeader(Pair(user, password))
|
setAuthHeader(Pair(user, password))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the stored credentials
|
||||||
|
* @return The stored credentials
|
||||||
|
*/
|
||||||
fun getCredentials(): Pair<String, String>? {
|
fun getCredentials(): Pair<String, String>? {
|
||||||
val prefs = mCtx.getSharedPreferences("credentials", 0)
|
val prefs = mCtx.getSharedPreferences("credentials", 0)
|
||||||
memoriesUrl = prefs.getString("memoriesUrl", null)
|
memoriesUrl = prefs.getString("memoriesUrl", null)
|
||||||
|
@ -219,6 +241,9 @@ class AccountService(private val mCtx: MainActivity) {
|
||||||
return Pair(user, password)
|
return Pair(user, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the stored credentials
|
||||||
|
*/
|
||||||
fun deleteCredentials() {
|
fun deleteCredentials() {
|
||||||
authHeader = null
|
authHeader = null
|
||||||
memoriesUrl = null
|
memoriesUrl = null
|
||||||
|
@ -229,10 +254,17 @@ class AccountService(private val mCtx: MainActivity) {
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the authorization header
|
||||||
|
*/
|
||||||
fun refreshAuthHeader() {
|
fun refreshAuthHeader() {
|
||||||
setAuthHeader(getCredentials())
|
setAuthHeader(getCredentials())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the authorization header
|
||||||
|
* @param credentials The credentials to use
|
||||||
|
*/
|
||||||
private fun setAuthHeader(credentials: Pair<String, String>?) {
|
private fun setAuthHeader(credentials: Pair<String, String>?) {
|
||||||
if (credentials != null) {
|
if (credentials != null) {
|
||||||
val auth = "${credentials.first}:${credentials.second}"
|
val auth = "${credentials.first}:${credentials.second}"
|
||||||
|
@ -241,4 +273,14 @@ class AccountService(private val mCtx: MainActivity) {
|
||||||
}
|
}
|
||||||
authHeader = null
|
authHeader = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a toast on the UI thread
|
||||||
|
* @param message The message to show
|
||||||
|
*/
|
||||||
|
private fun toast(message: String) {
|
||||||
|
mCtx.runOnUiThread {
|
||||||
|
Toast.makeText(mCtx, message, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -8,6 +8,10 @@ class ConfigService(private val mCtx: Context) {
|
||||||
private var mEnabledBuckets: List<String>? = null
|
private var mEnabledBuckets: List<String>? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of enabled local folders
|
||||||
|
* @return The list of enabled local folders
|
||||||
|
*/
|
||||||
var enabledBucketIds: List<String>
|
var enabledBucketIds: List<String>
|
||||||
get() {
|
get() {
|
||||||
if (mEnabledBuckets != null) return mEnabledBuckets!!
|
if (mEnabledBuckets != null) return mEnabledBuckets!!
|
||||||
|
|
|
@ -3,9 +3,13 @@ package gallery.memories.service
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
import gallery.memories.NativeX
|
import gallery.memories.NativeX
|
||||||
|
|
||||||
class DownloadBroadcastReceiver : BroadcastReceiver() {
|
@UnstableApi class DownloadBroadcastReceiver : BroadcastReceiver() {
|
||||||
|
/**
|
||||||
|
* Callback when download is complete
|
||||||
|
*/
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
NativeX.dlService?.runDownloadCallback(intent)
|
NativeX.dlService?.runDownloadCallback(intent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,16 @@ import android.webkit.CookieManager
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.collection.ArrayMap
|
import androidx.collection.ArrayMap
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
|
|
||||||
class DownloadService(private val mActivity: AppCompatActivity, private val query: TimelineQuery) {
|
@UnstableApi class DownloadService(private val mActivity: AppCompatActivity, private val query: TimelineQuery) {
|
||||||
private val mDownloads: MutableMap<Long, () -> Unit> = ArrayMap()
|
private val mDownloads: MutableMap<Long, () -> Unit> = ArrayMap()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback when download is complete
|
||||||
|
* @param intent The intent that triggered the callback
|
||||||
|
*/
|
||||||
fun runDownloadCallback(intent: Intent) {
|
fun runDownloadCallback(intent: Intent) {
|
||||||
if (mActivity.isDestroyed) return
|
if (mActivity.isDestroyed) return
|
||||||
|
|
||||||
|
@ -31,6 +36,12 @@ class DownloadService(private val mActivity: AppCompatActivity, private val quer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue a download
|
||||||
|
* @param url The URL to download
|
||||||
|
* @param filename The filename to save the download as
|
||||||
|
* @return The download ID
|
||||||
|
*/
|
||||||
fun queue(url: String, filename: String): Long {
|
fun queue(url: String, filename: String): Long {
|
||||||
val uri = Uri.parse(url)
|
val uri = Uri.parse(url)
|
||||||
val manager = mActivity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
val manager = mActivity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
@ -52,6 +63,11 @@ class DownloadService(private val mActivity: AppCompatActivity, private val quer
|
||||||
return manager.enqueue(request)
|
return manager.enqueue(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Share a URL as a string
|
||||||
|
* @param url The URL to share
|
||||||
|
* @return True if the URL was shared
|
||||||
|
*/
|
||||||
fun shareUrl(url: String): Boolean {
|
fun shareUrl(url: String): Boolean {
|
||||||
val intent = Intent(Intent.ACTION_SEND)
|
val intent = Intent(Intent.ACTION_SEND)
|
||||||
intent.type = "text/plain"
|
intent.type = "text/plain"
|
||||||
|
@ -60,6 +76,11 @@ class DownloadService(private val mActivity: AppCompatActivity, private val quer
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Share a URL as a blob
|
||||||
|
* @param url The URL to share
|
||||||
|
* @return True if the URL was shared
|
||||||
|
*/
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun shareBlobFromUrl(url: String): Boolean {
|
fun shareBlobFromUrl(url: String): Boolean {
|
||||||
val id = queue(url, "")
|
val id = queue(url, "")
|
||||||
|
@ -81,6 +102,11 @@ class DownloadService(private val mActivity: AppCompatActivity, private val quer
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Share a local image
|
||||||
|
* @param auid The AUID of the image to share
|
||||||
|
* @return True if the image was shared
|
||||||
|
*/
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun shareLocal(auid: Long): Boolean {
|
fun shareLocal(auid: Long): Boolean {
|
||||||
val sysImgs = query.getSystemImagesByAUIDs(listOf(auid))
|
val sysImgs = query.getSystemImagesByAUIDs(listOf(auid))
|
||||||
|
@ -95,6 +121,11 @@ class DownloadService(private val mActivity: AppCompatActivity, private val quer
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the URI of a downloaded file from download ID
|
||||||
|
* @param downloadId The download ID
|
||||||
|
* @return The URI of the downloaded file
|
||||||
|
*/
|
||||||
private fun getDownloadedFileURI(downloadId: Long): String? {
|
private fun getDownloadedFileURI(downloadId: Long): String? {
|
||||||
val downloadManager =
|
val downloadManager =
|
||||||
mActivity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
mActivity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
|
|
@ -6,9 +6,15 @@ import android.graphics.Bitmap
|
||||||
import android.graphics.ImageDecoder
|
import android.graphics.ImageDecoder
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
|
|
||||||
class ImageService(private val mCtx: Context, private val query: TimelineQuery) {
|
@UnstableApi class ImageService(private val mCtx: Context, private val query: TimelineQuery) {
|
||||||
|
/**
|
||||||
|
* Get a preview image for a given image ID
|
||||||
|
* @param id The image ID
|
||||||
|
* @return The preview image as a JPEG byte array
|
||||||
|
*/
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun getPreview(id: Long): ByteArray {
|
fun getPreview(id: Long): ByteArray {
|
||||||
val bitmap =
|
val bitmap =
|
||||||
|
@ -36,6 +42,11 @@ class ImageService(private val mCtx: Context, private val query: TimelineQuery)
|
||||||
return stream.toByteArray()
|
return stream.toByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a full image for a given image ID
|
||||||
|
* @param id The image ID
|
||||||
|
* @return The full image as a JPEG byte array
|
||||||
|
*/
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun getFull(auid: Long): ByteArray {
|
fun getFull(auid: Long): ByteArray {
|
||||||
val sysImgs = query.getSystemImagesByAUIDs(listOf(auid))
|
val sysImgs = query.getSystemImagesByAUIDs(listOf(auid))
|
||||||
|
|
|
@ -105,14 +105,36 @@ class TimelineQuery(private val mCtx: MainActivity) {
|
||||||
return observer
|
return observer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get system images by AUIDs
|
||||||
|
* @param auids List of AUIDs
|
||||||
|
*/
|
||||||
fun getSystemImagesByAUIDs(auids: List<Long>): List<SystemImage> {
|
fun getSystemImagesByAUIDs(auids: List<Long>): List<SystemImage> {
|
||||||
val photos = mPhotoDao.getPhotosByAUIDs(auids)
|
val photos = mPhotoDao.getPhotosByAUIDs(auids)
|
||||||
if (photos.isEmpty()) return listOf()
|
if (photos.isEmpty()) return listOf()
|
||||||
return SystemImage.getByIds(mCtx, photos.map { it.localId })
|
return SystemImage.getByIds(mCtx, photos.map { it.localId })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the days response for local files.
|
||||||
|
* @return JSON response
|
||||||
|
*/
|
||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
fun getByDayId(dayId: Long): JSONArray {
|
fun getDays(): JSONArray {
|
||||||
|
return mPhotoDao.getDays(mConfigService.enabledBucketIds).map {
|
||||||
|
JSONObject()
|
||||||
|
.put(Fields.Day.DAYID, it.dayId)
|
||||||
|
.put(Fields.Day.COUNT, it.count)
|
||||||
|
}.let { JSONArray(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the day response for local files.
|
||||||
|
* @param dayId Day ID
|
||||||
|
* @return JSON response
|
||||||
|
*/
|
||||||
|
@Throws(JSONException::class)
|
||||||
|
fun getDay(dayId: Long): JSONArray {
|
||||||
// Get the photos for the day from DB
|
// Get the photos for the day from DB
|
||||||
val fileIds = mPhotoDao.getPhotosByDay(dayId, mConfigService.enabledBucketIds)
|
val fileIds = mPhotoDao.getPhotosByDay(dayId, mConfigService.enabledBucketIds)
|
||||||
.map { it.localId }.toMutableList()
|
.map { it.localId }.toMutableList()
|
||||||
|
@ -133,15 +155,6 @@ class TimelineQuery(private val mCtx: MainActivity) {
|
||||||
return photos
|
return photos
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
|
||||||
fun getDays(): JSONArray {
|
|
||||||
return mPhotoDao.getDays(mConfigService.enabledBucketIds).map {
|
|
||||||
JSONObject()
|
|
||||||
.put(Fields.Day.DAYID, it.dayId)
|
|
||||||
.put(Fields.Day.COUNT, it.count)
|
|
||||||
}.let { JSONArray(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun getImageInfo(id: Long): JSONObject {
|
fun getImageInfo(id: Long): JSONObject {
|
||||||
val photos = mPhotoDao.getPhotosByFileIds(listOf(id))
|
val photos = mPhotoDao.getPhotosByFileIds(listOf(id))
|
||||||
|
@ -176,6 +189,12 @@ class TimelineQuery(private val mCtx: MainActivity) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete images from local database and system store.
|
||||||
|
* @param auids List of AUIDs
|
||||||
|
* @param dry Dry run (returns whether confirmation will be needed)
|
||||||
|
* @return JSON response
|
||||||
|
*/
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun delete(auids: List<Long>, dry: Boolean): JSONObject {
|
fun delete(auids: List<Long>, dry: Boolean): JSONObject {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
|
@ -237,6 +256,11 @@ class TimelineQuery(private val mCtx: MainActivity) {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync local database with system store.
|
||||||
|
* @param startTime Only sync files modified after this time
|
||||||
|
* @return Number of updated files
|
||||||
|
*/
|
||||||
private fun syncDb(startTime: Long): Int {
|
private fun syncDb(startTime: Long): Int {
|
||||||
// Date modified is in seconds, not millis
|
// Date modified is in seconds, not millis
|
||||||
val syncTime = Instant.now().toEpochMilli() / 1000;
|
val syncTime = Instant.now().toEpochMilli() / 1000;
|
||||||
|
@ -287,6 +311,10 @@ class TimelineQuery(private val mCtx: MainActivity) {
|
||||||
return updates
|
return updates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync local database with system store.
|
||||||
|
* @return Number of updated files
|
||||||
|
*/
|
||||||
fun syncDeltaDb(): Int {
|
fun syncDeltaDb(): Int {
|
||||||
// Get last sync time
|
// Get last sync time
|
||||||
val syncTime = mCtx.getSharedPreferences(mCtx.getString(R.string.preferences_key), 0)
|
val syncTime = mCtx.getSharedPreferences(mCtx.getString(R.string.preferences_key), 0)
|
||||||
|
@ -294,6 +322,11 @@ class TimelineQuery(private val mCtx: MainActivity) {
|
||||||
return syncDb(syncTime)
|
return syncDb(syncTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync local database with system store.
|
||||||
|
* Runs a full synchronization pass, flagging all files for removal.
|
||||||
|
* @return Number of updated files
|
||||||
|
*/
|
||||||
fun syncFullDb() {
|
fun syncFullDb() {
|
||||||
// Flag all images for removal
|
// Flag all images for removal
|
||||||
mPhotoDao.flagAll()
|
mPhotoDao.flagAll()
|
||||||
|
@ -305,6 +338,10 @@ class TimelineQuery(private val mCtx: MainActivity) {
|
||||||
mPhotoDao.deleteFlagged()
|
mPhotoDao.deleteFlagged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert item into local database.
|
||||||
|
* @param image SystemImage
|
||||||
|
*/
|
||||||
@SuppressLint("SimpleDateFormat")
|
@SuppressLint("SimpleDateFormat")
|
||||||
private fun insertItemDb(image: SystemImage) {
|
private fun insertItemDb(image: SystemImage) {
|
||||||
val fileId = image.fileId
|
val fileId = image.fileId
|
||||||
|
@ -325,7 +362,10 @@ class TimelineQuery(private val mCtx: MainActivity) {
|
||||||
Log.v(TAG, "Inserted file to local DB: $fileId / $baseName")
|
Log.v(TAG, "Inserted file to local DB: $fileId / $baseName")
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This is in timeline query because it calls the database service */
|
/**
|
||||||
|
* Active local folders response.
|
||||||
|
* This is in timeline query because it calls the database service.
|
||||||
|
*/
|
||||||
var localFolders: JSONArray
|
var localFolders: JSONArray
|
||||||
get() {
|
get() {
|
||||||
return mPhotoDao.getBuckets().map {
|
return mPhotoDao.getBuckets().map {
|
||||||
|
|
Loading…
Reference in New Issue