Fix video deletion

pull/653/merge
Varun Patil 2023-05-13 17:16:39 -07:00
parent 39f2af8dc3
commit c7d2d78619
6 changed files with 244 additions and 69 deletions

View File

@ -0,0 +1,123 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -26,7 +26,7 @@ class MainActivity : AppCompatActivity() {
}
@SuppressLint("SetJavaScriptEnabled")
protected fun initializeWebView() {
private fun initializeWebView() {
binding.webview.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
view.loadUrl(request.url.toString())

View File

@ -48,14 +48,19 @@ class NativeX(private val mActivity: AppCompatActivity) {
}
fun handleRequest(request: WebResourceRequest): WebResourceResponse {
val path = request.url.path
val response: WebResourceResponse = try {
if (request.method == "GET") {
routerGet(path)
} else if (request.method == "OPTIONS") {
WebResourceResponse("text/plain", "UTF-8", ByteArrayInputStream("".toByteArray()))
} else {
throw Exception("Method Not Allowed")
val path = request.url.path ?: return makeErrorResponse()
val response = try {
when (request.method) {
"GET" -> {
routerGet(path)
}
"OPTIONS" -> {
WebResourceResponse("text/plain", "UTF-8", ByteArrayInputStream("".toByteArray()))
}
else -> {
throw Exception("Method Not Allowed")
}
}
} catch (e: Exception) {
Log.e(TAG, "handleRequest: ", e)
@ -89,12 +94,13 @@ class NativeX(private val mActivity: AppCompatActivity) {
@JavascriptInterface
fun downloadFromUrl(url: String?, filename: String?) {
mDlService.queue(url!!, filename!!)
if (url == null || filename == null) return;
mDlService.queue(url, filename)
}
@Throws(Exception::class)
private fun routerGet(path: String?): WebResourceResponse {
val parts = path!!.split("/").toTypedArray()
private fun routerGet(path: String): WebResourceResponse {
val parts = path.split("/").toTypedArray()
if (path.matches(API.IMAGE_PREVIEW)) {
return makeResponse(mImageService.getPreview(parts[3].toLong()), "image/jpeg")
} else if (path.matches(API.IMAGE_FULL)) {

View File

@ -0,0 +1,76 @@
package gallery.memories.mapper
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.provider.MediaStore
class SystemImage {
var fileId = 0L;
var baseName = ""
var mimeType = ""
var dateTaken = 0L
var height = 0L
var width = 0L
var size = 0L
var dataPath = ""
var isVideo = false
private var mCollection: Uri = IMAGE_URI
val uri: Uri
get() {
return ContentUris.withAppendedId(mCollection, fileId)
}
companion object {
val IMAGE_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val VIDEO_URI = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
fun getByIds(ctx: Context, ids: List<Long>): List<SystemImage> {
val images = getByIdsAndCollection(ctx, IMAGE_URI, ids)
if (images.size == ids.size) return images
return images + getByIdsAndCollection(ctx, VIDEO_URI, ids)
}
fun getByIdsAndCollection(ctx: Context, collection: Uri, ids: List<Long>): List<SystemImage> {
val selection = MediaStore.Images.Media._ID + " IN (" + ids.joinToString(",") + ")"
val list = mutableListOf<SystemImage>()
ctx.contentResolver.query(
collection,
arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.MIME_TYPE,
MediaStore.Images.Media.HEIGHT,
MediaStore.Images.Media.WIDTH,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.DATA
),
selection,
null,
null
).use { cursor ->
while (cursor!!.moveToNext()) {
val image = SystemImage()
image.fileId = cursor.getLong(0)
image.baseName = cursor.getString(1)
image.mimeType = cursor.getString(2)
image.height = cursor.getLong(3)
image.width = cursor.getLong(4)
image.size = cursor.getLong(5)
image.dateTaken = cursor.getLong(6)
image.dataPath = cursor.getString(7)
image.isVideo = collection == VIDEO_URI
image.mCollection = collection
list.add(image)
}
}
return list
}
}
}

View File

@ -2,11 +2,9 @@ package gallery.memories.service
import android.annotation.SuppressLint
import android.app.Activity
import android.content.ContentUris
import android.database.sqlite.SQLiteDatabase
import android.icu.text.SimpleDateFormat
import android.icu.util.TimeZone
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.text.TextUtils
@ -18,6 +16,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.collection.ArraySet
import androidx.exifinterface.media.ExifInterface
import gallery.memories.mapper.SystemImage
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
@ -165,68 +164,36 @@ class TimelineQuery(private val mCtx: AppCompatActivity) {
@Throws(Exception::class)
fun getImageInfo(id: Long): JSONObject {
val sql = "SELECT local_id, date_taken, dayid FROM images WHERE local_id = ?"
val sql = "SELECT dayid, date_taken FROM images WHERE local_id = ?"
mDb.rawQuery(sql, arrayOf(id.toString())).use { cursor ->
if (!cursor.moveToNext()) {
throw Exception("Image not found")
}
val localId = cursor.getLong(0)
val dateTaken = cursor.getLong(1)
val dayId = cursor.getLong(2)
return getImageInfoForCollection(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
localId, dateTaken, dayId)
?: return getImageInfoForCollection(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
localId, dateTaken, dayId)
?: throw Exception("File not found in any collection")
}
}
private fun getImageInfoForCollection(
collection: Uri,
localId: Long,
dateTaken: Long,
dayId: Long
): JSONObject? {
val selection = MediaStore.Images.Media._ID + " = " + localId
mCtx.contentResolver.query(
collection,
arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.MIME_TYPE,
MediaStore.Images.Media.HEIGHT,
MediaStore.Images.Media.WIDTH,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.DATA
),
selection,
null,
null
).use { cursor ->
if (!cursor!!.moveToNext()) {
throw Exception("Image not found")
// Get image from system table
val imageList = SystemImage.getByIds(mCtx, arrayListOf(id))
if (imageList.isEmpty()) {
throw Exception("File not found in any collection")
}
// Create basic info
// Add EXIF to json object
val image = imageList[0];
val dayId = cursor.getLong(0)
val dateTaken = cursor.getLong(1)
val obj = JSONObject()
.put(Fields.Photo.FILEID, cursor.getLong(0))
.put(Fields.Photo.BASENAME, cursor.getString(1))
.put(Fields.Photo.MIMETYPE, cursor.getString(2))
.put(Fields.Photo.FILEID, image.fileId)
.put(Fields.Photo.BASENAME, image.baseName)
.put(Fields.Photo.MIMETYPE, image.mimeType)
.put(Fields.Photo.DAYID, dayId)
.put(Fields.Photo.DATETAKEN, dateTaken)
.put(Fields.Photo.HEIGHT, cursor.getLong(3))
.put(Fields.Photo.WIDTH, cursor.getLong(4))
.put(Fields.Photo.SIZE, cursor.getLong(5))
.put(Fields.Photo.HEIGHT, image.height)
.put(Fields.Photo.WIDTH, image.width)
.put(Fields.Photo.SIZE, image.size)
.put(Fields.Photo.PERMISSIONS, Fields.Perm.DELETE)
val uri = cursor.getString(6)
// Get EXIF data
try {
val exif = ExifInterface(uri)
val exif = ExifInterface(image.dataPath)
obj.put(Fields.Photo.EXIF, JSONObject()
.put("Aperture", exif.getAttribute(ExifInterface.TAG_APERTURE_VALUE))
.put("FocalLength", exif.getAttribute(ExifInterface.TAG_FOCAL_LENGTH))
@ -245,7 +212,7 @@ class TimelineQuery(private val mCtx: AppCompatActivity) {
.put("Description", exif.getAttribute(ExifInterface.TAG_IMAGE_DESCRIPTION))
)
} catch (e: IOException) {
Log.e(TAG, "Error reading EXIF data for $uri")
Log.e(TAG, "Error reading EXIF data for $id")
}
return obj
@ -263,9 +230,7 @@ class TimelineQuery(private val mCtx: AppCompatActivity) {
return try {
// List of URIs
val uris = ids.map {
ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, it)
}
val uris = SystemImage.getByIds(mCtx, ids).map { it.uri }
// Delete file with media store
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
@ -301,7 +266,7 @@ class TimelineQuery(private val mCtx: AppCompatActivity) {
}
}
protected fun fullSyncDb() {
private fun fullSyncDb() {
// Flag all images for removal
mDb.execSQL("UPDATE images SET flag = 1")
mCtx.contentResolver.query(
@ -381,7 +346,7 @@ class TimelineQuery(private val mCtx: AppCompatActivity) {
// Get EXIF date using ExifInterface if image
if (!isVideo) {
try {
val exif = ExifInterface(uri!!)
val exif = ExifInterface(uri)
val exifDate = exif.getAttribute(ExifInterface.TAG_DATETIME)
?: throw IOException()
val sdf = SimpleDateFormat("yyyy:MM:dd HH:mm:ss")