Reformat code

pull/653/merge
Varun Patil 2023-08-21 12:38:55 -07:00
parent 3fb209a994
commit 4e89b101b2
11 changed files with 155 additions and 110 deletions

View File

@ -26,7 +26,8 @@ import androidx.media3.exoplayer.hls.HlsMediaSource
import androidx.media3.exoplayer.source.ProgressiveMediaSource import androidx.media3.exoplayer.source.ProgressiveMediaSource
import gallery.memories.databinding.ActivityMainBinding import gallery.memories.databinding.ActivityMainBinding
@UnstableApi class MainActivity : AppCompatActivity() { @UnstableApi
class MainActivity : AppCompatActivity() {
companion object { companion object {
val TAG = MainActivity::class.java.simpleName val TAG = MainActivity::class.java.simpleName
} }
@ -124,7 +125,10 @@ import gallery.memories.databinding.ActivityMainBinding
private fun initializeWebView() { private fun initializeWebView() {
// Intercept local APIs // Intercept local APIs
binding.webview.webViewClient = object : WebViewClient() { binding.webview.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { override fun shouldOverrideUrlLoading(
view: WebView,
request: WebResourceRequest
): Boolean {
val pathMatches = request.url.path?.matches(memoriesRegex) == true val pathMatches = request.url.path?.matches(memoriesRegex) == true
val hostMatches = request.url.host.equals(host) val hostMatches = request.url.host.equals(host)
if (pathMatches && hostMatches) { if (pathMatches && hostMatches) {
@ -137,7 +141,10 @@ import gallery.memories.databinding.ActivityMainBinding
return true return true
} }
override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? { override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest
): WebResourceResponse? {
return if (request.url.host == "127.0.0.1") { return if (request.url.host == "127.0.0.1") {
nativex.handleRequest(request) nativex.handleRequest(request)
} else null } else null
@ -194,9 +201,11 @@ import gallery.memories.databinding.ActivityMainBinding
host = Uri.parse(memoriesUrl).host host = Uri.parse(memoriesUrl).host
// Set authorization header // Set authorization header
binding.webview.loadUrl(memoriesUrl, mapOf( binding.webview.loadUrl(
"Authorization" to authHeader memoriesUrl, mapOf(
)) "Authorization" to authHeader
)
)
return true return true
} }
@ -207,7 +216,8 @@ import gallery.memories.databinding.ActivityMainBinding
fun ensureStoragePermissions() { fun ensureStoragePermissions() {
val requestPermissionLauncher = registerForActivityResult( val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()) { permissions -> ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
// we need all of these // we need all of these
val isGranted = permissions.all { it.value } val isGranted = permissions.all { it.value }
@ -236,10 +246,12 @@ import gallery.memories.databinding.ActivityMainBinding
// Request media read permission // Request media read permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissionLauncher.launch(arrayOf( requestPermissionLauncher.launch(
android.Manifest.permission.READ_MEDIA_IMAGES, arrayOf(
android.Manifest.permission.READ_MEDIA_VIDEO, android.Manifest.permission.READ_MEDIA_IMAGES,
)) android.Manifest.permission.READ_MEDIA_VIDEO,
)
)
} else { } else {
requestPermissionLauncher.launch(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE)) requestPermissionLauncher.launch(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE))
} }
@ -278,7 +290,8 @@ import gallery.memories.databinding.ActivityMainBinding
DefaultHttpDataSource.Factory() DefaultHttpDataSource.Factory()
.setDefaultRequestProperties(mapOf("cookie" to cookies)) .setDefaultRequestProperties(mapOf("cookie" to cookies))
.setAllowCrossProtocolRedirects(true) .setAllowCrossProtocolRedirects(true)
val dataSourceFactory = DefaultDataSource.Factory(this, httpDataSourceFactory) val dataSourceFactory =
DefaultDataSource.Factory(this, httpDataSourceFactory)
// Check if HLS source from URI (contains .m3u8 anywhere) // Check if HLS source from URI (contains .m3u8 anywhere)
exoPlayer.addMediaSource( exoPlayer.addMediaSource(
@ -355,10 +368,15 @@ import gallery.memories.databinding.ActivityMainBinding
// Set dark mode // Set dark mode
setTheme(if (isDark) android.R.style.Theme_Black else android.R.style.Theme_Light) setTheme(if (isDark) android.R.style.Theme_Black else android.R.style.Theme_Light)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val appearance = WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS or WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS val appearance =
window.insetsController?.setSystemBarsAppearance(if (isDark) 0 else appearance, appearance) WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS or WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
window.insetsController?.setSystemBarsAppearance(
if (isDark) 0 else appearance,
appearance
)
} else { } else {
window.decorView.systemUiVisibility = if (isDark) 0 else View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR window.decorView.systemUiVisibility =
if (isDark) 0 else View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
} }
// Set colors // Set colors
@ -390,8 +408,11 @@ import gallery.memories.databinding.ActivityMainBinding
// Schedule for resume if not active // Schedule for resume if not active
if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) || force) { if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) || force) {
mNeedRefresh = false mNeedRefresh = false
binding.webview.evaluateJavascript("window._nc_event_bus?.emit('files:file:created')", null) binding.webview.evaluateJavascript(
"window._nc_event_bus?.emit('files:file:created')",
null
)
} else { } else {
mNeedRefresh = true mNeedRefresh = true
} }

View File

@ -15,7 +15,8 @@ abstract class AppDatabase : RoomDatabase() {
companion object { companion object {
private val DATABASE_NAME = "memories_room" private val DATABASE_NAME = "memories_room"
@Volatile private var INSTANCE: AppDatabase? = null @Volatile
private var INSTANCE: AppDatabase? = null
fun get(context: Context): AppDatabase { fun get(context: Context): AppDatabase {
if (INSTANCE == null) { if (INSTANCE == null) {

View File

@ -2,7 +2,7 @@ package gallery.memories.mapper
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
data class Bucket ( data class Bucket(
@ColumnInfo(name="bucket_id") val id: String, @ColumnInfo(name = "bucket_id") val id: String,
@ColumnInfo(name="bucket_name") val name: String, @ColumnInfo(name = "bucket_name") val name: String,
) )

View File

@ -2,7 +2,7 @@ package gallery.memories.mapper
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
data class Day ( data class Day(
@ColumnInfo(name="dayid") val dayId: Long, @ColumnInfo(name = "dayid") val dayId: Long,
@ColumnInfo(name="count") val count: Long @ColumnInfo(name = "count") val count: Long
) )

View File

@ -4,8 +4,9 @@ import org.json.JSONObject
class Response { class Response {
companion object { companion object {
val OK get(): JSONObject { val OK
return JSONObject().put("message", "ok") get(): JSONObject {
} return JSONObject().put("message", "ok")
}
} }
} }

View File

@ -28,9 +28,9 @@ class SystemImage {
var videoDuration = 0L var videoDuration = 0L
val uri: Uri val uri: Uri
get() { get() {
return ContentUris.withAppendedId(mCollection, fileId) return ContentUris.withAppendedId(mCollection, fileId)
} }
private var mCollection: Uri = IMAGE_URI private var mCollection: Uri = IMAGE_URI
@ -137,72 +137,77 @@ class SystemImage {
} }
} }
val json get(): JSONObject { val json
val obj = JSONObject() get(): JSONObject {
.put(Fields.Photo.FILEID, fileId) val obj = JSONObject()
.put(Fields.Photo.BASENAME, baseName) .put(Fields.Photo.FILEID, fileId)
.put(Fields.Photo.MIMETYPE, mimeType) .put(Fields.Photo.BASENAME, baseName)
.put(Fields.Photo.HEIGHT, height) .put(Fields.Photo.MIMETYPE, mimeType)
.put(Fields.Photo.WIDTH, width) .put(Fields.Photo.HEIGHT, height)
.put(Fields.Photo.SIZE, size) .put(Fields.Photo.WIDTH, width)
.put(Fields.Photo.ETAG, mtime.toString()) .put(Fields.Photo.SIZE, size)
.put(Fields.Photo.EPOCH, epoch) .put(Fields.Photo.ETAG, mtime.toString())
.put(Fields.Photo.AUID, auid) .put(Fields.Photo.EPOCH, epoch)
.put(Fields.Photo.AUID, auid)
if (isVideo) { if (isVideo) {
obj.put(Fields.Photo.ISVIDEO, 1) obj.put(Fields.Photo.ISVIDEO, 1)
.put(Fields.Photo.VIDEO_DURATION, videoDuration / 1000) .put(Fields.Photo.VIDEO_DURATION, videoDuration / 1000)
}
return obj
}
val epoch get(): Long {
return dateTaken / 1000
}
val utcDate get(): Long {
// Get EXIF date using ExifInterface if image
if (!isVideo) {
try {
val exif = ExifInterface(dataPath)
val exifDate = exif.getAttribute(ExifInterface.TAG_DATETIME)
?: throw IOException()
val sdf = SimpleDateFormat("yyyy:MM:dd HH:mm:ss")
sdf.timeZone = TimeZone.GMT_ZONE
sdf.parse(exifDate).let {
return it.time / 1000
}
} catch (e: Exception) {
Log.e(TAG, "Failed to read EXIF data: " + e.message)
} }
return obj
} }
// No way to get the actual local date, so just assume current timezone val epoch
return (dateTaken + TimeZone.getDefault().getOffset(dateTaken).toLong()) / 1000 get(): Long {
} return dateTaken / 1000
}
val auid get(): Long { val utcDate
val crc = java.util.zip.CRC32() get(): Long {
// Get EXIF date using ExifInterface if image
if (!isVideo) {
try {
val exif = ExifInterface(dataPath)
val exifDate = exif.getAttribute(ExifInterface.TAG_DATETIME)
?: throw IOException()
val sdf = SimpleDateFormat("yyyy:MM:dd HH:mm:ss")
sdf.timeZone = TimeZone.GMT_ZONE
sdf.parse(exifDate).let {
return it.time / 1000
}
} catch (e: Exception) {
Log.e(TAG, "Failed to read EXIF data: " + e.message)
}
}
// pass date taken + size as decimal string // No way to get the actual local date, so just assume current timezone
crc.update((epoch.toString() + size.toString()).toByteArray()) return (dateTaken + TimeZone.getDefault().getOffset(dateTaken).toLong()) / 1000
}
return crc.value val auid
} get(): Long {
val crc = java.util.zip.CRC32()
val photo get(): Photo { // pass date taken + size as decimal string
val dateCache = utcDate crc.update((epoch.toString() + size.toString()).toByteArray())
return Photo(
localId = fileId, return crc.value
auid = auid, }
mtime = mtime,
dateTaken = dateCache, val photo
dayId = dateCache / 86400, get(): Photo {
baseName = baseName, val dateCache = utcDate
bucketId = bucketId, return Photo(
bucketName = bucketName, localId = fileId,
flag = 0, auid = auid,
) mtime = mtime,
} dateTaken = dateCache,
dayId = dateCache / 86400,
baseName = baseName,
bucketId = bucketId,
bucketName = bucketName,
flag = 0,
)
}
} }

View File

@ -17,7 +17,8 @@ import okhttp3.Response
import org.json.JSONObject import org.json.JSONObject
import java.net.SocketTimeoutException import java.net.SocketTimeoutException
@UnstableApi class AccountService(private val mCtx: MainActivity) { @UnstableApi
class AccountService(private val mCtx: MainActivity) {
companion object { companion object {
val TAG = AccountService::class.java.simpleName val TAG = AccountService::class.java.simpleName
} }
@ -89,7 +90,8 @@ import java.net.SocketTimeoutException
} }
val client = OkHttpClient() val client = OkHttpClient()
val rbody = "token=$pollToken".toRequestBody("application/x-www-form-urlencoded".toMediaTypeOrNull()) val rbody =
"token=$pollToken".toRequestBody("application/x-www-form-urlencoded".toMediaTypeOrNull())
var pollCount = 0 var pollCount = 0
while (true) { while (true) {

View File

@ -12,14 +12,18 @@ class ConfigService(private val mCtx: Context) {
get() { get() {
if (mEnabledBuckets != null) return mEnabledBuckets!! if (mEnabledBuckets != null) return mEnabledBuckets!!
mEnabledBuckets = mCtx.getSharedPreferences(mCtx.getString(R.string.preferences_key), 0) mEnabledBuckets = mCtx.getSharedPreferences(mCtx.getString(R.string.preferences_key), 0)
.getStringSet(mCtx.getString(R.string.preferences_enabled_local_folders), null)?.toList() .getStringSet(mCtx.getString(R.string.preferences_enabled_local_folders), null)
?: listOf() ?.toList()
?: listOf()
return mEnabledBuckets!! return mEnabledBuckets!!
} }
set(value) { set(value) {
mEnabledBuckets = value mEnabledBuckets = value
mCtx.getSharedPreferences(mCtx.getString(R.string.preferences_key), 0).edit() mCtx.getSharedPreferences(mCtx.getString(R.string.preferences_key), 0).edit()
.putStringSet(mCtx.getString(R.string.preferences_enabled_local_folders), value.toSet()) .putStringSet(
mCtx.getString(R.string.preferences_enabled_local_folders),
value.toSet()
)
.apply() .apply()
} }
} }

View File

@ -44,7 +44,10 @@ class DownloadService(private val mActivity: AppCompatActivity) {
request.addRequestHeader("cookie", cookies) request.addRequestHeader("cookie", cookies)
if (filename != "") { if (filename != "") {
// Save the file to external storage // Save the file to external storage
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "memories/$filename") request.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
"memories/$filename"
)
} }
// Start the download // Start the download
@ -92,7 +95,8 @@ class DownloadService(private val mActivity: AppCompatActivity) {
} }
private fun getDownloadedFileURI(downloadId: Long): String? { private fun getDownloadedFileURI(downloadId: Long): String? {
val downloadManager = mActivity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager val downloadManager =
mActivity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val query = DownloadManager.Query() val query = DownloadManager.Query()
query.setFilterById(downloadId) query.setFilterById(downloadId)
val cursor = downloadManager.query(query) val cursor = downloadManager.query(query)

View File

@ -14,7 +14,10 @@ class ImageService(private val mCtx: Context) {
val bitmap = val bitmap =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
mCtx.contentResolver.loadThumbnail( mCtx.contentResolver.loadThumbnail(
ContentUris.withAppendedId(MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL), id), ContentUris.withAppendedId(
MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL),
id
),
android.util.Size(2048, 2048), android.util.Size(2048, 2048),
null null
) )
@ -22,10 +25,10 @@ class ImageService(private val mCtx: Context) {
MediaStore.Images.Thumbnails.getThumbnail( MediaStore.Images.Thumbnails.getThumbnail(
mCtx.contentResolver, id, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND, null mCtx.contentResolver, id, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND, null
) )
?: MediaStore.Video.Thumbnails.getThumbnail( ?: MediaStore.Video.Thumbnails.getThumbnail(
mCtx.contentResolver, id, MediaStore.Video.Thumbnails.FULL_SCREEN_KIND, null mCtx.contentResolver, id, MediaStore.Video.Thumbnails.FULL_SCREEN_KIND, null
) )
?: throw Exception("Thumbnail not found") ?: throw Exception("Thumbnail not found")
} }
val stream = ByteArrayOutputStream() val stream = ByteArrayOutputStream()
@ -42,7 +45,7 @@ class ImageService(private val mCtx: Context) {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(mCtx.contentResolver, uri)) ImageDecoder.decodeBitmap(ImageDecoder.createSource(mCtx.contentResolver, uri))
} else { } else {
MediaStore.Images.Media.getBitmap(mCtx.contentResolver, uri) MediaStore.Images.Media.getBitmap(mCtx.contentResolver, uri)
?: throw Exception("Image not found") ?: throw Exception("Image not found")
} }
val stream = ByteArrayOutputStream() val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream) bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream)

View File

@ -26,7 +26,8 @@ import java.io.IOException
import java.time.Instant import java.time.Instant
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
@UnstableApi class TimelineQuery(private val mCtx: MainActivity) { @UnstableApi
class TimelineQuery(private val mCtx: MainActivity) {
private val TAG = TimelineQuery::class.java.simpleName private val TAG = TimelineQuery::class.java.simpleName
private val mConfigService = ConfigService(mCtx) private val mConfigService = ConfigService(mCtx)
@ -46,11 +47,12 @@ import java.util.concurrent.CountDownLatch
init { init {
// Register intent launcher for callback // Register intent launcher for callback
deleteIntentLauncher = mCtx.registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result: ActivityResult? -> deleteIntentLauncher =
synchronized(this) { mCtx.registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result: ActivityResult? ->
deleteCallback?.let { it(result) } synchronized(this) {
deleteCallback?.let { it(result) }
}
} }
}
} }
fun initialize() { fun initialize() {
@ -192,7 +194,9 @@ import java.util.concurrent.CountDownLatch
// Delete file with media store // Delete file with media store
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val intent = MediaStore.createTrashRequest(mCtx.contentResolver, uris, true) val intent = MediaStore.createTrashRequest(mCtx.contentResolver, uris, true)
deleteIntentLauncher.launch(IntentSenderRequest.Builder(intent.intentSender).build()) deleteIntentLauncher.launch(
IntentSenderRequest.Builder(intent.intentSender).build()
)
// Wait for response // Wait for response
val latch = CountDownLatch(1) val latch = CountDownLatch(1)
@ -240,7 +244,7 @@ import java.util.concurrent.CountDownLatch
// Iterate all images and videos from system store // Iterate all images and videos from system store
val files = val files =
SystemImage.query(mCtx, SystemImage.IMAGE_URI, selection, selectionArgs, null) + SystemImage.query(mCtx, SystemImage.IMAGE_URI, selection, selectionArgs, null) +
SystemImage.query(mCtx, SystemImage.VIDEO_URI, selection, selectionArgs, null) SystemImage.query(mCtx, SystemImage.VIDEO_URI, selection, selectionArgs, null)
files.forEach { insertItemDb(it) } files.forEach { insertItemDb(it) }
// Store last sync time // Store last sync time