From 3215436f324dbaa69a485bbfe8e70e53f9b72f5b Mon Sep 17 00:00:00 2001 From: moezbhatti Date: Sun, 20 Oct 2019 20:04:45 -0400 Subject: [PATCH] Save part to disk and share using content provider Fixes #1508 and fixes #1468 --- .../QKSMS/repository/ImageRepostoryImpl.kt | 26 -------------- .../QKSMS/repository/MessageRepositoryImpl.kt | 34 +++++++++++++++++++ .../com/moez/QKSMS/interactor/SaveImage.kt | 6 +--- .../moez/QKSMS/repository/ImageRepository.kt | 4 +-- .../QKSMS/repository/MessageRepository.kt | 5 ++- presentation/src/main/AndroidManifest.xml | 16 +++++++-- .../java/com/moez/QKSMS/common/Navigator.kt | 17 ++++++---- .../QKSMS/feature/compose/ComposeActivity.kt | 2 ++ .../moez/QKSMS/feature/compose/ComposeView.kt | 2 ++ .../QKSMS/feature/compose/ComposeViewModel.kt | 19 +++++++++++ .../QKSMS/feature/compose/MessagesAdapter.kt | 11 ++++-- .../QKSMS/feature/compose/part/FileBinder.kt | 18 ++++------ .../QKSMS/feature/compose/part/MediaBinder.kt | 16 ++++++--- .../QKSMS/feature/compose/part/PartBinder.kt | 23 ++++++++++--- .../feature/compose/part/PartsAdapter.kt | 25 +++++++++----- .../QKSMS/feature/compose/part/VCardBinder.kt | 20 ++++------- .../src/main/res/xml/provider_paths.xml | 24 +++++++++++++ 17 files changed, 179 insertions(+), 89 deletions(-) create mode 100644 presentation/src/main/res/xml/provider_paths.xml diff --git a/data/src/main/java/com/moez/QKSMS/repository/ImageRepostoryImpl.kt b/data/src/main/java/com/moez/QKSMS/repository/ImageRepostoryImpl.kt index 73dfdf1b..006abaf4 100644 --- a/data/src/main/java/com/moez/QKSMS/repository/ImageRepostoryImpl.kt +++ b/data/src/main/java/com/moez/QKSMS/repository/ImageRepostoryImpl.kt @@ -22,14 +22,8 @@ import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Matrix -import android.media.MediaScannerConnection import android.net.Uri -import android.os.Environment import androidx.exifinterface.media.ExifInterface -import java.io.File -import java.io.FileNotFoundException -import java.io.FileOutputStream -import java.io.IOException import javax.inject.Inject class ImageRepostoryImpl @Inject constructor(private val context: Context) : ImageRepository { @@ -58,24 +52,4 @@ class ImageRepostoryImpl @Inject constructor(private val context: Context) : Ima return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true) } - override fun saveImage(uri: Uri) { - val type = context.contentResolver.getType(uri)?.split("/") ?: return - val dir = File(Environment.getExternalStorageDirectory(), "QKSMS/Media").apply { mkdirs() } - val file = File(dir, "${type.first()}${System.currentTimeMillis()}.${type.last()}") - - try { - FileOutputStream(file).use { outputStream -> - context.contentResolver.openInputStream(uri)?.use { inputStream -> - inputStream.copyTo(outputStream, 1024) - } - } - } catch (e: FileNotFoundException) { - e.printStackTrace() - } catch (e: IOException) { - e.printStackTrace() - } - - MediaScannerConnection.scanFile(context, arrayOf(file.path), null, null) - } - } diff --git a/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt b/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt index 1b1097fe..7ee92c86 100644 --- a/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt +++ b/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt @@ -25,9 +25,12 @@ import android.content.ContentValues import android.content.Context import android.content.Intent import android.content.IntentFilter +import android.media.MediaScannerConnection import android.os.Build +import android.os.Environment import android.provider.Telephony import android.telephony.SmsManager +import android.webkit.MimeTypeMap import androidx.core.content.contentValuesOf import com.google.android.mms.ContentType import com.google.android.mms.MMSPart @@ -54,6 +57,10 @@ import io.realm.Realm import io.realm.RealmResults import io.realm.Sort import timber.log.Timber +import java.io.File +import java.io.FileNotFoundException +import java.io.FileOutputStream +import java.io.IOException import javax.inject.Inject import javax.inject.Singleton @@ -132,6 +139,33 @@ class MessageRepositoryImpl @Inject constructor( .findAllAsync() } + override fun savePart(id: Long): File? { + 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" + val file = File(dir, fileName) + + try { + FileOutputStream(file).use { outputStream -> + context.contentResolver.openInputStream(part.getUri())?.use { inputStream -> + inputStream.copyTo(outputStream, 1024) + } + } + } catch (e: FileNotFoundException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + + MediaScannerConnection.scanFile(context, arrayOf(file.path), null, null) + + return file.takeIf { it.exists() } + } + /** * Retrieves the list of messages which should be shown in the notification * for a given conversation diff --git a/domain/src/main/java/com/moez/QKSMS/interactor/SaveImage.kt b/domain/src/main/java/com/moez/QKSMS/interactor/SaveImage.kt index 809a31fb..3c5e5838 100644 --- a/domain/src/main/java/com/moez/QKSMS/interactor/SaveImage.kt +++ b/domain/src/main/java/com/moez/QKSMS/interactor/SaveImage.kt @@ -18,21 +18,17 @@ */ package com.moez.QKSMS.interactor -import com.moez.QKSMS.repository.ImageRepository import com.moez.QKSMS.repository.MessageRepository import io.reactivex.Flowable import javax.inject.Inject class SaveImage @Inject constructor( - private val imageRepository: ImageRepository, private val messageRepo: MessageRepository ) : Interactor() { override fun buildObservable(params: Long): Flowable<*> { return Flowable.just(params) - .map { partId -> messageRepo.getPart(partId) } - .map { part -> part.getUri() } - .doOnNext { uri -> imageRepository.saveImage(uri) } + .doOnNext { partId -> messageRepo.savePart(partId) } } } \ No newline at end of file diff --git a/domain/src/main/java/com/moez/QKSMS/repository/ImageRepository.kt b/domain/src/main/java/com/moez/QKSMS/repository/ImageRepository.kt index 6ec8e4b7..70c6ecbb 100644 --- a/domain/src/main/java/com/moez/QKSMS/repository/ImageRepository.kt +++ b/domain/src/main/java/com/moez/QKSMS/repository/ImageRepository.kt @@ -25,6 +25,4 @@ interface ImageRepository { fun loadImage(uri: Uri): Bitmap? - fun saveImage(uri: Uri) - -} \ No newline at end of file +} diff --git a/domain/src/main/java/com/moez/QKSMS/repository/MessageRepository.kt b/domain/src/main/java/com/moez/QKSMS/repository/MessageRepository.kt index b3ec7b58..80530bb1 100644 --- a/domain/src/main/java/com/moez/QKSMS/repository/MessageRepository.kt +++ b/domain/src/main/java/com/moez/QKSMS/repository/MessageRepository.kt @@ -22,6 +22,7 @@ import com.moez.QKSMS.model.Attachment import com.moez.QKSMS.model.Message import com.moez.QKSMS.model.MmsPart import io.realm.RealmResults +import java.io.File interface MessageRepository { @@ -37,6 +38,8 @@ interface MessageRepository { fun getPartsForConversation(threadId: Long): RealmResults + fun savePart(id: Long): File? + /** * Retrieves the list of messages which should be shown in the notification * for a given conversation @@ -95,4 +98,4 @@ interface MessageRepository { fun deleteMessages(vararg messageIds: Long) -} \ No newline at end of file +} diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index f22519f3..52fc8ea6 100644 --- a/presentation/src/main/AndroidManifest.xml +++ b/presentation/src/main/AndroidManifest.xml @@ -17,8 +17,8 @@ ~ You should have received a copy of the GNU General Public License ~ along with QKSMS. If not, see . --> - + @@ -165,10 +165,10 @@ android:name="android.appwidget.provider" android:resource="@xml/widget_info" /> + - @@ -202,6 +202,16 @@ android:name="preloaded_fonts" android:resource="@array/preloaded_fonts" /> + + + + \ No newline at end of file diff --git a/presentation/src/main/java/com/moez/QKSMS/common/Navigator.kt b/presentation/src/main/java/com/moez/QKSMS/common/Navigator.kt index d4c3c3de..f9ad53d2 100644 --- a/presentation/src/main/java/com/moez/QKSMS/common/Navigator.kt +++ b/presentation/src/main/java/com/moez/QKSMS/common/Navigator.kt @@ -26,6 +26,8 @@ import android.os.Build import android.provider.ContactsContract import android.provider.Settings import android.provider.Telephony +import android.webkit.MimeTypeMap +import androidx.core.content.FileProvider import com.moez.QKSMS.BuildConfig import com.moez.QKSMS.common.util.BillingManager import com.moez.QKSMS.feature.backup.BackupActivity @@ -40,10 +42,10 @@ import com.moez.QKSMS.feature.settings.SettingsActivity import com.moez.QKSMS.manager.AnalyticsManager import com.moez.QKSMS.manager.NotificationManager import com.moez.QKSMS.manager.PermissionManager +import java.io.File import javax.inject.Inject import javax.inject.Singleton - @Singleton class Navigator @Inject constructor( private val context: Context, @@ -166,7 +168,6 @@ class Navigator @Inject constructor( startActivity(intent) } - fun showRating() { val intent = Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.moez.QKSMS")) .addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY @@ -176,7 +177,8 @@ class Navigator @Inject constructor( try { startActivity(intent) } catch (e: ActivityNotFoundException) { - startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=com.moez.QKSMS"))) + val url = "http://play.google.com/store/apps/details?id=com.moez.QKSMS" + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) } } @@ -245,9 +247,12 @@ class Navigator @Inject constructor( startActivityExternal(intent) } - fun openFile(uri: Uri, contentType: String) { + fun viewFile(file: File) { + val data = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file) + val type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(file.name.split(".").last()) val intent = Intent(Intent.ACTION_VIEW) - .setDataAndType(uri, contentType) + .setDataAndType(data, type) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) startActivityExternal(intent) } @@ -272,4 +277,4 @@ class Navigator @Inject constructor( } } -} \ No newline at end of file +} diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeActivity.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeActivity.kt index 7957488e..9bdc5618 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeActivity.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeActivity.kt @@ -55,6 +55,7 @@ import com.moez.QKSMS.common.util.extensions.showKeyboard import com.moez.QKSMS.model.Attachment import com.moez.QKSMS.model.Contact import com.moez.QKSMS.model.Message +import com.moez.QKSMS.model.MmsPart import com.uber.autodispose.android.lifecycle.scope import com.uber.autodispose.autoDisposable import dagger.android.AndroidInjection @@ -91,6 +92,7 @@ class ComposeActivity : QkThemedActivity(), ComposeView { override val optionsItemIntent: Subject = PublishSubject.create() override val sendAsGroupIntent by lazy { sendAsGroupBackground.clicks() } override val messageClickIntent: Subject by lazy { messageAdapter.clicks } + override val messagePartClickIntent: Subject by lazy { messageAdapter.partClicks } override val messagesSelectedIntent by lazy { messageAdapter.selectionChanges } override val cancelSendingIntent: Subject by lazy { messageAdapter.cancelSending } override val attachmentDeletedIntent: Subject by lazy { attachmentAdapter.attachmentDeleted } diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeView.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeView.kt index e15b9d00..fd60d41b 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeView.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeView.kt @@ -25,6 +25,7 @@ import com.moez.QKSMS.common.base.QkView import com.moez.QKSMS.model.Attachment import com.moez.QKSMS.model.Contact import com.moez.QKSMS.model.Message +import com.moez.QKSMS.model.MmsPart import io.reactivex.Observable import io.reactivex.subjects.Subject @@ -40,6 +41,7 @@ interface ComposeView : QkView { val optionsItemIntent: Observable val sendAsGroupIntent: Observable<*> val messageClickIntent: Subject + val messagePartClickIntent: Subject val messagesSelectedIntent: Observable> val cancelSendingIntent: Subject val attachmentDeletedIntent: Subject diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeViewModel.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeViewModel.kt index facddcd0..20410cbf 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeViewModel.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/ComposeViewModel.kt @@ -34,6 +34,7 @@ import com.moez.QKSMS.compat.SubscriptionManagerCompat import com.moez.QKSMS.compat.TelephonyCompat import com.moez.QKSMS.extensions.asObservable import com.moez.QKSMS.extensions.isImage +import com.moez.QKSMS.extensions.isVideo import com.moez.QKSMS.extensions.mapNotNull import com.moez.QKSMS.extensions.removeAccents import com.moez.QKSMS.filter.ContactFilter @@ -424,6 +425,24 @@ class ComposeViewModel @Inject constructor( .autoDisposable(view.scope()) .subscribe() + // Media attachment clicks + view.messagePartClickIntent + .filter { part -> part.isImage() || part.isVideo() } + .autoDisposable(view.scope()) + .subscribe { part -> navigator.showMedia(part.id) } + + // Non-media attachment clicks + view.messagePartClickIntent + .filter { part -> !part.isImage() && !part.isVideo() } + .autoDisposable(view.scope()) + .subscribe { part -> + if (permissionManager.hasStorage()) { + messageRepo.savePart(part.id)?.let(navigator::viewFile) + } else { + view.requestStoragePermission() + } + } + // Update the State when the message selected count changes view.messagesSelectedIntent .map { selection -> selection.size } diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/MessagesAdapter.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/MessagesAdapter.kt index 67958f3d..da9601bd 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/MessagesAdapter.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/MessagesAdapter.kt @@ -34,7 +34,6 @@ import android.widget.ProgressBar import androidx.recyclerview.widget.RecyclerView import com.jakewharton.rxbinding2.view.clicks import com.moez.QKSMS.R -import com.moez.QKSMS.common.Navigator import com.moez.QKSMS.common.base.QkRealmAdapter import com.moez.QKSMS.common.base.QkViewHolder import com.moez.QKSMS.common.util.Colors @@ -54,6 +53,7 @@ import com.moez.QKSMS.feature.compose.BubbleUtils.getBubble import com.moez.QKSMS.feature.compose.part.PartsAdapter import com.moez.QKSMS.model.Conversation import com.moez.QKSMS.model.Message +import com.moez.QKSMS.model.MmsPart import com.moez.QKSMS.model.Recipient import com.moez.QKSMS.util.PhoneNumberUtils import com.moez.QKSMS.util.Preferences @@ -64,13 +64,14 @@ import kotlinx.android.synthetic.main.message_list_item_in.view.* import java.util.* import java.util.concurrent.TimeUnit import javax.inject.Inject +import javax.inject.Provider class MessagesAdapter @Inject constructor( subscriptionManager: SubscriptionManagerCompat, private val context: Context, private val colors: Colors, private val dateFormatter: DateFormatter, - private val navigator: Navigator, + private val partsAdapterProvider: Provider, private val phoneNumberUtils: PhoneNumberUtils, private val prefs: Preferences, private val textViewStyler: TextViewStyler @@ -88,6 +89,7 @@ class MessagesAdapter @Inject constructor( } val clicks: Subject = PublishSubject.create() + val partClicks: Subject = PublishSubject.create() val cancelSending: Subject = PublishSubject.create() var data: Pair>? = null @@ -153,7 +155,9 @@ class MessagesAdapter @Inject constructor( view.body.hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE } - view.attachments.adapter = PartsAdapter(context, navigator, theme) + val partsAdapter = partsAdapterProvider.get() + partsAdapter.clicks.subscribe(partClicks) + view.attachments.adapter = partsAdapter view.attachments.setRecycledViewPool(partsViewPool) view.body.forwardTouches(view) @@ -273,6 +277,7 @@ class MessagesAdapter @Inject constructor( // Bind the attachments val partsAdapter = view.attachments.adapter as PartsAdapter + partsAdapter.theme = theme partsAdapter.setData(message, previous, next, view) } diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/FileBinder.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/FileBinder.kt index c2f3b03f..58051c4c 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/FileBinder.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/FileBinder.kt @@ -19,33 +19,28 @@ package com.moez.QKSMS.feature.compose.part import android.annotation.SuppressLint -import android.content.ContentUris import android.content.Context import android.view.Gravity import android.view.View import android.widget.FrameLayout import com.moez.QKSMS.R -import com.moez.QKSMS.common.Navigator import com.moez.QKSMS.common.util.Colors import com.moez.QKSMS.common.util.extensions.resolveThemeColor import com.moez.QKSMS.common.util.extensions.setBackgroundTint import com.moez.QKSMS.common.util.extensions.setTint import com.moez.QKSMS.feature.compose.BubbleUtils -import com.moez.QKSMS.mapper.CursorToPartImpl import com.moez.QKSMS.model.Message import com.moez.QKSMS.model.MmsPart import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import kotlinx.android.synthetic.main.mms_file_list_item.view.* +import javax.inject.Inject -class FileBinder( - private val context: Context, - private val navigator: Navigator, - private val theme: Colors.Theme -) : PartBinder { +class FileBinder @Inject constructor(colors: Colors, private val context: Context) : PartBinder() { override val partLayout = R.layout.mms_file_list_item + override var theme = colors.theme() // This is the last binder we check. If we're here, we can bind the part override fun canBindPart(part: MmsPart) = true @@ -58,11 +53,10 @@ class FileBinder( canGroupWithPrevious: Boolean, canGroupWithNext: Boolean ) { - val uri = ContentUris.withAppendedId(CursorToPartImpl.CONTENT_URI, part.id) - val bubble = BubbleUtils.getBubble(false, canGroupWithPrevious, canGroupWithNext, message.isMe()) + BubbleUtils.getBubble(false, canGroupWithPrevious, canGroupWithNext, message.isMe()) + .let(view.fileBackground::setBackgroundResource) - view.setOnClickListener { navigator.openFile(uri, part.type) } - view.fileBackground.setBackgroundResource(bubble) + view.setOnClickListener { clicks.onNext(part) } Observable.just(part.getUri()) .map(context.contentResolver::openInputStream) diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/MediaBinder.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/MediaBinder.kt index 62a23fa5..14f98f24 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/MediaBinder.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/MediaBinder.kt @@ -21,7 +21,7 @@ package com.moez.QKSMS.feature.compose.part import android.content.Context import android.view.View import com.moez.QKSMS.R -import com.moez.QKSMS.common.Navigator +import com.moez.QKSMS.common.util.Colors import com.moez.QKSMS.common.util.extensions.setVisible import com.moez.QKSMS.common.widget.BubbleImageView import com.moez.QKSMS.extensions.isImage @@ -30,16 +30,24 @@ import com.moez.QKSMS.model.Message import com.moez.QKSMS.model.MmsPart import com.moez.QKSMS.util.GlideApp import kotlinx.android.synthetic.main.mms_preview_list_item.view.* +import javax.inject.Inject -class MediaBinder(private val context: Context, private val navigator: Navigator) : PartBinder { +class MediaBinder @Inject constructor(colors: Colors, private val context: Context) : PartBinder() { override val partLayout = R.layout.mms_preview_list_item + override var theme = colors.theme() override fun canBindPart(part: MmsPart) = part.isImage() || part.isVideo() - override fun bindPart(view: View, part: MmsPart, message: Message, canGroupWithPrevious: Boolean, canGroupWithNext: Boolean) { + override fun bindPart( + view: View, + part: MmsPart, + message: Message, + canGroupWithPrevious: Boolean, + canGroupWithNext: Boolean + ) { view.video.setVisible(part.isVideo()) - view.setOnClickListener { navigator.showMedia(part.id) } + view.setOnClickListener { clicks.onNext(part) } view.thumbnail.bubbleStyle = when { !canGroupWithPrevious && canGroupWithNext -> if (message.isMe()) BubbleImageView.Style.OUT_FIRST else BubbleImageView.Style.IN_FIRST diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/PartBinder.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/PartBinder.kt index 53f220fe..cadcdfbe 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/PartBinder.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/PartBinder.kt @@ -19,15 +19,28 @@ package com.moez.QKSMS.feature.compose.part import android.view.View +import com.moez.QKSMS.common.util.Colors import com.moez.QKSMS.model.Message import com.moez.QKSMS.model.MmsPart +import io.reactivex.subjects.PublishSubject +import io.reactivex.subjects.Subject -interface PartBinder { +abstract class PartBinder { - val partLayout: Int + val clicks: Subject = PublishSubject.create() - fun canBindPart(part: MmsPart): Boolean + abstract val partLayout: Int - fun bindPart(view: View, part: MmsPart, message: Message, canGroupWithPrevious: Boolean, canGroupWithNext: Boolean) + abstract var theme: Colors.Theme -} \ No newline at end of file + abstract fun canBindPart(part: MmsPart): Boolean + + abstract fun bindPart( + view: View, + part: MmsPart, + message: Message, + canGroupWithPrevious: Boolean, + canGroupWithNext: Boolean + ) + +} diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/PartsAdapter.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/PartsAdapter.kt index ac02cf8d..8c365f5e 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/PartsAdapter.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/PartsAdapter.kt @@ -18,11 +18,9 @@ */ package com.moez.QKSMS.feature.compose.part -import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import com.moez.QKSMS.common.Navigator import com.moez.QKSMS.common.base.QkAdapter import com.moez.QKSMS.common.base.QkViewHolder import com.moez.QKSMS.common.util.Colors @@ -32,15 +30,26 @@ import com.moez.QKSMS.extensions.isText import com.moez.QKSMS.feature.compose.BubbleUtils.canGroup import com.moez.QKSMS.model.Message import com.moez.QKSMS.model.MmsPart +import io.reactivex.Observable import kotlinx.android.synthetic.main.message_list_item_in.view.* +import javax.inject.Inject -class PartsAdapter(context: Context, navigator: Navigator, theme: Colors.Theme) : QkAdapter() { +class PartsAdapter @Inject constructor( + colors: Colors, + fileBinder: FileBinder, + mediaBinder: MediaBinder, + vCardBinder: VCardBinder +) : QkAdapter() { - private val partBinders = listOf( - MediaBinder(context, navigator), - VCardBinder(context, navigator, theme), - FileBinder(context, navigator, theme) - ) + private val partBinders = listOf(mediaBinder, vCardBinder, fileBinder) + + var theme: Colors.Theme = colors.theme() + set(value) { + field = value + partBinders.forEach { binder -> binder.theme = value } + } + + val clicks = Observable.merge(partBinders.map { it.clicks }) private lateinit var message: Message private var previous: Message? = null diff --git a/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/VCardBinder.kt b/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/VCardBinder.kt index 9407f6af..9569b845 100644 --- a/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/VCardBinder.kt +++ b/presentation/src/main/java/com/moez/QKSMS/feature/compose/part/VCardBinder.kt @@ -18,13 +18,11 @@ */ package com.moez.QKSMS.feature.compose.part -import android.content.ContentUris import android.content.Context import android.view.Gravity import android.view.View import android.widget.FrameLayout import com.moez.QKSMS.R -import com.moez.QKSMS.common.Navigator import com.moez.QKSMS.common.util.Colors import com.moez.QKSMS.common.util.extensions.resolveThemeColor import com.moez.QKSMS.common.util.extensions.setBackgroundTint @@ -32,7 +30,6 @@ import com.moez.QKSMS.common.util.extensions.setTint import com.moez.QKSMS.extensions.isVCard import com.moez.QKSMS.extensions.mapNotNull import com.moez.QKSMS.feature.compose.BubbleUtils -import com.moez.QKSMS.mapper.CursorToPartImpl import com.moez.QKSMS.model.Message import com.moez.QKSMS.model.MmsPart import ezvcard.Ezvcard @@ -40,14 +37,12 @@ import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import kotlinx.android.synthetic.main.mms_vcard_list_item.view.* +import javax.inject.Inject -class VCardBinder( - private val context: Context, - private val navigator: Navigator, - private val theme: Colors.Theme -) : PartBinder { +class VCardBinder @Inject constructor(colors: Colors, private val context: Context) : PartBinder() { override val partLayout = R.layout.mms_vcard_list_item + override var theme = colors.theme() override fun canBindPart(part: MmsPart) = part.isVCard() @@ -58,13 +53,12 @@ class VCardBinder( canGroupWithPrevious: Boolean, canGroupWithNext: Boolean ) { - val uri = ContentUris.withAppendedId(CursorToPartImpl.CONTENT_URI, part.id) - val bubble = BubbleUtils.getBubble(false, canGroupWithPrevious, canGroupWithNext, message.isMe()) + BubbleUtils.getBubble(false, canGroupWithPrevious, canGroupWithNext, message.isMe()) + .let(view.vCardBackground::setBackgroundResource) - view.setOnClickListener { navigator.openFile(uri, part.type) } - view.vCardBackground.setBackgroundResource(bubble) + view.setOnClickListener { clicks.onNext(part) } - Observable.just(uri) + Observable.just(part.getUri()) .map(context.contentResolver::openInputStream) .mapNotNull { inputStream -> inputStream.use { Ezvcard.parse(it).first() } } .subscribeOn(Schedulers.computation()) diff --git a/presentation/src/main/res/xml/provider_paths.xml b/presentation/src/main/res/xml/provider_paths.xml new file mode 100644 index 00000000..98b55d83 --- /dev/null +++ b/presentation/src/main/res/xml/provider_paths.xml @@ -0,0 +1,24 @@ + + + + +