Loading data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt +40 −17 Original line number Diff line number Diff line Loading @@ -26,8 +26,10 @@ import android.content.Context import android.content.Intent import android.graphics.BitmapFactory import android.media.MediaScannerConnection import android.net.Uri import android.os.Build import android.os.Environment import android.provider.MediaStore import android.provider.Telephony import android.provider.Telephony.Mms import android.provider.Telephony.Sms Loading @@ -44,6 +46,8 @@ import com.klinker.android.send_message.Transaction import com.moez.QKSMS.common.util.extensions.now import com.moez.QKSMS.compat.TelephonyCompat import com.moez.QKSMS.extensions.anyOf import com.moez.QKSMS.extensions.isImage import com.moez.QKSMS.extensions.isVideo import com.moez.QKSMS.manager.ActiveConversationManager import com.moez.QKSMS.manager.KeyManager import com.moez.QKSMS.model.Attachment Loading @@ -61,6 +65,8 @@ import io.realm.Case import io.realm.Realm import io.realm.RealmResults import io.realm.Sort import okio.buffer import okio.source import timber.log.Timber import java.io.File import java.io.FileNotFoundException Loading Loading @@ -167,36 +173,53 @@ class MessageRepositoryImpl @Inject constructor( .findAllAsync() } override fun savePart(id: Long): File? { override fun savePart(id: Long): Uri? { val part = getPart(id) ?: return null val extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(part.type) ?: return null val date = part.messages?.first()?.date val dir = File(Environment.getExternalStorageDirectory(), "QKSMS/Media").apply { mkdirs() } val fileName = part.name?.takeIf { name -> name.endsWith(extension) } ?: "${part.type.split("/").last()}_$date.$extension" var file: File var index = 0 do { file = File(dir, if (index == 0) fileName else fileName.replace(".$extension", " ($index).$extension")) index++ } while (file.exists()) try { FileOutputStream(file).use { outputStream -> val values = contentValuesOf( MediaStore.MediaColumns.DISPLAY_NAME to fileName, MediaStore.MediaColumns.MIME_TYPE to part.type, ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { values.put(MediaStore.MediaColumns.IS_PENDING, 1) values.put(MediaStore.MediaColumns.RELATIVE_PATH, when { part.isImage() -> "${Environment.DIRECTORY_PICTURES}/QKSMS" part.isVideo() -> "${Environment.DIRECTORY_MOVIES}/QKSMS" else -> "${Environment.DIRECTORY_DOWNLOADS}/QKSMS" }) } val contentUri = when { part.isImage() -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI part.isVideo() -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> MediaStore.Downloads.EXTERNAL_CONTENT_URI else -> MediaStore.Files.getContentUri("external") } val resolver = context.contentResolver val uri = resolver.insert(contentUri, values) Timber.v("Saving $fileName (${part.type}) to $uri") uri?.let { resolver.openOutputStream(uri)?.use { outputStream -> context.contentResolver.openInputStream(part.getUri())?.use { inputStream -> inputStream.copyTo(outputStream, 1024) } } } catch (e: FileNotFoundException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } Timber.v("Saved $fileName (${part.type}) to $uri") MediaScannerConnection.scanFile(context, arrayOf(file.path), null, null) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { resolver.update(uri, contentValuesOf(MediaStore.MediaColumns.IS_PENDING to 0), null, null) Timber.v("Marked $uri as not pending") } } return file.takeIf { it.exists() } return uri } /** Loading domain/src/main/java/com/moez/QKSMS/repository/MessageRepository.kt +2 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ */ package com.moez.QKSMS.repository import android.net.Uri import com.moez.QKSMS.model.Attachment import com.moez.QKSMS.model.Message import com.moez.QKSMS.model.MmsPart Loading @@ -40,7 +41,7 @@ interface MessageRepository { fun getPartsForConversation(threadId: Long): RealmResults<MmsPart> fun savePart(id: Long): File? fun savePart(id: Long): Uri? /** * Retrieves the list of messages which should be shown in the notification Loading presentation/src/main/java/com/moez/QKSMS/common/Navigator.kt +7 −9 Original line number Diff line number Diff line Loading @@ -260,23 +260,21 @@ class Navigator @Inject constructor( startActivityExternal(intent) } fun viewFile(file: File) { val data = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file) val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(file.name.split(".").last()) fun viewFile(uri: Uri, mimeType: String) { val intent = Intent(Intent.ACTION_VIEW) .setDataAndType(data, type) .setDataAndType(uri, mimeType.lowercase()) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) .let { Intent.createChooser(it, null) } startActivityExternal(intent) } fun shareFile(file: File) { val data = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file) val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(file.name.split(".").last()) fun shareFile(uri: Uri, mimeType: String) { val intent = Intent(Intent.ACTION_SEND) .setType(type) .putExtra(Intent.EXTRA_STREAM, data) .setType(mimeType.lowercase()) .putExtra(Intent.EXTRA_STREAM, uri) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) .let { Intent.createChooser(it, null) } startActivityExternal(intent) } Loading presentation/src/main/java/com/moez/QKSMS/feature/backup/BackupController.kt +0 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import androidx.core.view.isVisible import com.jakewharton.rxbinding2.view.clicks import com.moez.QKSMS.R import com.moez.QKSMS.common.base.QkController import com.moez.QKSMS.common.util.DateFormatter import com.moez.QKSMS.common.util.QkActivityResultContracts import com.moez.QKSMS.common.util.extensions.getLabel import com.moez.QKSMS.common.util.extensions.setBackgroundTint Loading presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeViewModel.kt +1 −1 Original line number Diff line number Diff line Loading @@ -433,7 +433,7 @@ class ComposeViewModel @Inject constructor( .autoDisposable(view.scope()) .subscribe { part -> if (permissionManager.hasStorage()) { messageRepo.savePart(part.id)?.let(navigator::viewFile) messageRepo.savePart(part.id)?.let { navigator.viewFile(it, part.type) } } else { view.requestStoragePermission() } Loading Loading
data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt +40 −17 Original line number Diff line number Diff line Loading @@ -26,8 +26,10 @@ import android.content.Context import android.content.Intent import android.graphics.BitmapFactory import android.media.MediaScannerConnection import android.net.Uri import android.os.Build import android.os.Environment import android.provider.MediaStore import android.provider.Telephony import android.provider.Telephony.Mms import android.provider.Telephony.Sms Loading @@ -44,6 +46,8 @@ import com.klinker.android.send_message.Transaction import com.moez.QKSMS.common.util.extensions.now import com.moez.QKSMS.compat.TelephonyCompat import com.moez.QKSMS.extensions.anyOf import com.moez.QKSMS.extensions.isImage import com.moez.QKSMS.extensions.isVideo import com.moez.QKSMS.manager.ActiveConversationManager import com.moez.QKSMS.manager.KeyManager import com.moez.QKSMS.model.Attachment Loading @@ -61,6 +65,8 @@ import io.realm.Case import io.realm.Realm import io.realm.RealmResults import io.realm.Sort import okio.buffer import okio.source import timber.log.Timber import java.io.File import java.io.FileNotFoundException Loading Loading @@ -167,36 +173,53 @@ class MessageRepositoryImpl @Inject constructor( .findAllAsync() } override fun savePart(id: Long): File? { override fun savePart(id: Long): Uri? { val part = getPart(id) ?: return null val extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(part.type) ?: return null val date = part.messages?.first()?.date val dir = File(Environment.getExternalStorageDirectory(), "QKSMS/Media").apply { mkdirs() } val fileName = part.name?.takeIf { name -> name.endsWith(extension) } ?: "${part.type.split("/").last()}_$date.$extension" var file: File var index = 0 do { file = File(dir, if (index == 0) fileName else fileName.replace(".$extension", " ($index).$extension")) index++ } while (file.exists()) try { FileOutputStream(file).use { outputStream -> val values = contentValuesOf( MediaStore.MediaColumns.DISPLAY_NAME to fileName, MediaStore.MediaColumns.MIME_TYPE to part.type, ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { values.put(MediaStore.MediaColumns.IS_PENDING, 1) values.put(MediaStore.MediaColumns.RELATIVE_PATH, when { part.isImage() -> "${Environment.DIRECTORY_PICTURES}/QKSMS" part.isVideo() -> "${Environment.DIRECTORY_MOVIES}/QKSMS" else -> "${Environment.DIRECTORY_DOWNLOADS}/QKSMS" }) } val contentUri = when { part.isImage() -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI part.isVideo() -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> MediaStore.Downloads.EXTERNAL_CONTENT_URI else -> MediaStore.Files.getContentUri("external") } val resolver = context.contentResolver val uri = resolver.insert(contentUri, values) Timber.v("Saving $fileName (${part.type}) to $uri") uri?.let { resolver.openOutputStream(uri)?.use { outputStream -> context.contentResolver.openInputStream(part.getUri())?.use { inputStream -> inputStream.copyTo(outputStream, 1024) } } } catch (e: FileNotFoundException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } Timber.v("Saved $fileName (${part.type}) to $uri") MediaScannerConnection.scanFile(context, arrayOf(file.path), null, null) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { resolver.update(uri, contentValuesOf(MediaStore.MediaColumns.IS_PENDING to 0), null, null) Timber.v("Marked $uri as not pending") } } return file.takeIf { it.exists() } return uri } /** Loading
domain/src/main/java/com/moez/QKSMS/repository/MessageRepository.kt +2 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ */ package com.moez.QKSMS.repository import android.net.Uri import com.moez.QKSMS.model.Attachment import com.moez.QKSMS.model.Message import com.moez.QKSMS.model.MmsPart Loading @@ -40,7 +41,7 @@ interface MessageRepository { fun getPartsForConversation(threadId: Long): RealmResults<MmsPart> fun savePart(id: Long): File? fun savePart(id: Long): Uri? /** * Retrieves the list of messages which should be shown in the notification Loading
presentation/src/main/java/com/moez/QKSMS/common/Navigator.kt +7 −9 Original line number Diff line number Diff line Loading @@ -260,23 +260,21 @@ class Navigator @Inject constructor( startActivityExternal(intent) } fun viewFile(file: File) { val data = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file) val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(file.name.split(".").last()) fun viewFile(uri: Uri, mimeType: String) { val intent = Intent(Intent.ACTION_VIEW) .setDataAndType(data, type) .setDataAndType(uri, mimeType.lowercase()) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) .let { Intent.createChooser(it, null) } startActivityExternal(intent) } fun shareFile(file: File) { val data = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file) val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(file.name.split(".").last()) fun shareFile(uri: Uri, mimeType: String) { val intent = Intent(Intent.ACTION_SEND) .setType(type) .putExtra(Intent.EXTRA_STREAM, data) .setType(mimeType.lowercase()) .putExtra(Intent.EXTRA_STREAM, uri) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) .let { Intent.createChooser(it, null) } startActivityExternal(intent) } Loading
presentation/src/main/java/com/moez/QKSMS/feature/backup/BackupController.kt +0 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import androidx.core.view.isVisible import com.jakewharton.rxbinding2.view.clicks import com.moez.QKSMS.R import com.moez.QKSMS.common.base.QkController import com.moez.QKSMS.common.util.DateFormatter import com.moez.QKSMS.common.util.QkActivityResultContracts import com.moez.QKSMS.common.util.extensions.getLabel import com.moez.QKSMS.common.util.extensions.setBackgroundTint Loading
presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeViewModel.kt +1 −1 Original line number Diff line number Diff line Loading @@ -433,7 +433,7 @@ class ComposeViewModel @Inject constructor( .autoDisposable(view.scope()) .subscribe { part -> if (permissionManager.hasStorage()) { messageRepo.savePart(part.id)?.let(navigator::viewFile) messageRepo.savePart(part.id)?.let { navigator.viewFile(it, part.type) } } else { view.requestStoragePermission() } Loading