diff --git a/app/build.gradle b/app/build.gradle index f9a7d1500..bbc65715d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -292,12 +292,6 @@ dependencies { implementation 'com.github.wooplr:Spotlight:1.3' implementation'com.github.mario:chatkit:d32a7372bb' - implementation 'com.github.mario.fresco:fresco:111' - implementation 'com.github.mario.fresco:animated-webp:111' - implementation 'com.github.mario.fresco:webpsupport:111' - implementation 'com.github.mario.fresco:animated-gif:111' - implementation 'com.github.mario.fresco:imagepipeline-okhttp3:111' - implementation "io.coil-kt:coil:${coil_version}" implementation "io.coil-kt:coil-gif:${coil_version}" implementation "io.coil-kt:coil-svg:${coil_version}" diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt index 604f23f66..aaf94d873 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt @@ -30,13 +30,13 @@ import android.text.SpannableString import android.text.TextUtils import android.util.TypedValue import android.view.View +import android.widget.ImageView import android.widget.TextView import androidx.core.view.ViewCompat import androidx.emoji.widget.EmojiTextView import butterknife.BindView import butterknife.ButterKnife import com.amulyakhare.textdrawable.TextDrawable -import com.facebook.drawee.view.SimpleDraweeView import com.google.android.flexbox.FlexboxLayout import com.nextcloud.talk.R import com.nextcloud.talk.models.json.chat.ChatMessage @@ -60,7 +60,7 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders @JvmField @BindView(R.id.messageUserAvatar) - var messageUserAvatarView: SimpleDraweeView? = null + var messageUserAvatarView: ImageView? = null @JvmField @BindView(R.id.messageTime) @@ -91,16 +91,12 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders if (message.actorType == "guests") { // do nothing, avatar is set } else if (message.actorType == "bots" && message.actorType == "changelog") { - messageUserAvatarView!!.controller = null val layers = arrayOfNulls(2) layers[0] = context.getDrawable(R.drawable.ic_launcher_background) layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground) val layerDrawable = LayerDrawable(layers) - - messageUserAvatarView!!.hierarchy - .setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable)) + messageUserAvatarView?.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable)) } else if (message.actorType == "bots") { - messageUserAvatarView!!.controller = null val drawable = TextDrawable.builder() .beginConfig() .bold() @@ -110,7 +106,7 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders context.resources.getColor(R.color.black) ) messageUserAvatarView!!.visibility = View.VISIBLE - messageUserAvatarView!!.hierarchy.setPlaceholderImage(drawable) + messageUserAvatarView?.setImageDrawable(drawable) } } else { if (message.oneToOneConversation) { diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt index d6208266f..ca42172af 100644 --- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt +++ b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt @@ -36,9 +36,6 @@ import androidx.work.WorkManager import coil.Coil import coil.ImageLoader import com.bluelinelabs.logansquare.LoganSquare -import com.facebook.cache.disk.DiskCacheConfig -import com.facebook.drawee.backends.pipeline.Fresco -import com.facebook.imagepipeline.core.ImagePipelineConfig import com.nextcloud.talk.BuildConfig import com.nextcloud.talk.components.filebrowser.webdav.DavUtils import com.nextcloud.talk.jobs.AccountRemovalWorker @@ -56,7 +53,6 @@ import com.nextcloud.talk.newarch.local.models.UserNgEntity import com.nextcloud.talk.newarch.local.models.other.UserStatus.* import com.nextcloud.talk.utils.ClosedInterfaceImpl import com.nextcloud.talk.utils.DisplayUtils -import com.nextcloud.talk.utils.OkHttpNetworkFetcherWithCache import com.nextcloud.talk.utils.database.user.UserUtils import com.nextcloud.talk.utils.preferences.AppPreferences import com.nextcloud.talk.webrtc.MagicWebRTCUtils @@ -135,18 +131,6 @@ class NextcloudTalkApplication : Application(), LifecycleObserver { setAppTheme(appPreferences.theme) super.onCreate() - val imagePipelineConfig = ImagePipelineConfig.newBuilder(this) - .setNetworkFetcher(OkHttpNetworkFetcherWithCache(okHttpClient)) - .setMainDiskCacheConfig( - DiskCacheConfig.newBuilder(this) - .setMaxCacheSize(0) - .setMaxCacheSizeOnLowDiskSpace(0) - .setMaxCacheSizeOnVeryLowDiskSpace(0) - .build() - ) - .build() - - Fresco.initialize(this, imagePipelineConfig) Security.insertProviderAt(Conscrypt.newProvider(), 1) ClosedInterfaceImpl().providerInstallerInstallIfNeededAsync() diff --git a/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java b/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java index 177b9f228..5e51fe5da 100644 --- a/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java +++ b/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java @@ -25,10 +25,10 @@ import android.text.Editable; import android.text.Spanned; import android.widget.EditText; -import com.facebook.widget.text.span.BetterImageSpan; import com.nextcloud.talk.R; import com.nextcloud.talk.models.json.mention.Mention; import com.nextcloud.talk.newarch.local.models.UserNgEntity; +import com.nextcloud.talk.utils.BetterImageSpan; import com.nextcloud.talk.utils.DisplayUtils; import com.nextcloud.talk.utils.MagicCharPolicy; import com.nextcloud.talk.utils.text.Spans; diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt b/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt index b77ac9e95..c81989868 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt @@ -47,8 +47,6 @@ import butterknife.OnLongClick import coil.api.load import coil.transform.CircleCropTransformation import com.bluelinelabs.logansquare.LoganSquare -import com.facebook.drawee.backends.pipeline.Fresco -import com.facebook.drawee.view.SimpleDraweeView import com.nextcloud.talk.R import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.controllers.base.BaseController @@ -66,7 +64,6 @@ import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOveral import com.nextcloud.talk.newarch.local.models.UserNgEntity import com.nextcloud.talk.newarch.local.models.getCredentials import com.nextcloud.talk.utils.ApiUtils -import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.animations.PulseAnimation import com.nextcloud.talk.utils.bundle.BundleKeys @@ -79,7 +76,6 @@ import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers -import kotlinx.android.synthetic.main.rv_item_conversation_with_last_message.view.* import me.zhanghai.android.effortlesspermissions.AfterPermissionDenied import me.zhanghai.android.effortlesspermissions.EffortlessPermissions import me.zhanghai.android.effortlesspermissions.OpenAppDetailsDialogFragment @@ -99,7 +95,7 @@ class CallController(args: Bundle) : BaseController() { @JvmField @BindView(R.id.callControlEnableSpeaker) - var callControlEnableSpeaker: SimpleDraweeView? = null + var callControlEnableSpeaker: ImageView? = null @JvmField @BindView(R.id.pip_video_view) var pipVideoView: SurfaceViewRenderer? = null @@ -115,13 +111,13 @@ class CallController(args: Bundle) : BaseController() { var callControls: RelativeLayout? = null @JvmField @BindView(R.id.call_control_microphone) - var microphoneControlButton: SimpleDraweeView? = null + var microphoneControlButton: ImageView? = null @JvmField @BindView(R.id.call_control_camera) - var cameraControlButton: SimpleDraweeView? = null + var cameraControlButton: ImageView? = null @JvmField @BindView(R.id.call_control_switch_camera) - var cameraSwitchButton: SimpleDraweeView? = null + var cameraSwitchButton: ImageView? = null @JvmField @BindView(R.id.connectingTextView) var connectingTextView: TextView? = null @@ -460,10 +456,9 @@ class CallController(args: Bundle) : BaseController() { onCameraClick() } } else { - cameraControlButton!!.hierarchy - .setPlaceholderImage(R.drawable.ic_videocam_off_white_24px) - cameraControlButton!!.alpha = 0.7f - cameraSwitchButton!!.visibility = View.GONE + cameraControlButton?.setImageResource(R.drawable.ic_videocam_off_white_24px) + cameraControlButton?.alpha = 0.7f + cameraSwitchButton?.visibility = View.GONE } } @@ -472,7 +467,7 @@ class CallController(args: Bundle) : BaseController() { onMicrophoneClick() } } else { - microphoneControlButton!!.hierarchy.setPlaceholderImage(R.drawable.ic_mic_off_white_24px) + microphoneControlButton?.setImageResource(R.drawable.ic_mic_off_white_24px) } if (!isConnectionEstablished) { @@ -598,11 +593,9 @@ class CallController(args: Bundle) : BaseController() { if (audioManager != null) { audioManager!!.toggleUseSpeakerphone() if (audioManager!!.isSpeakerphoneAutoOn) { - callControlEnableSpeaker!!.hierarchy - .setPlaceholderImage(R.drawable.ic_volume_up_white_24dp) + callControlEnableSpeaker?.setImageResource(R.drawable.ic_volume_up_white_24dp) } else { - callControlEnableSpeaker!!.hierarchy - .setPlaceholderImage(R.drawable.ic_volume_mute_white_24dp) + callControlEnableSpeaker?.setImageResource(R.drawable.ic_volume_mute_white_24dp) } } } @@ -643,15 +636,14 @@ class CallController(args: Bundle) : BaseController() { audioOn = !audioOn if (audioOn) { - microphoneControlButton!!.hierarchy.setPlaceholderImage(R.drawable.ic_mic_white_24px) + microphoneControlButton?.setImageResource(R.drawable.ic_mic_white_24px) } else { - microphoneControlButton!!.hierarchy - .setPlaceholderImage(R.drawable.ic_mic_off_white_24px) + microphoneControlButton?.setImageResource(R.drawable.ic_mic_off_white_24px) } toggleMedia(audioOn, false) } else { - microphoneControlButton!!.hierarchy.setPlaceholderImage(R.drawable.ic_mic_white_24px) + microphoneControlButton?.setImageResource(R.drawable.ic_mic_white_24px) pulseAnimation!!.start() toggleMedia(true, false) } @@ -695,13 +687,12 @@ class CallController(args: Bundle) : BaseController() { videoOn = !videoOn if (videoOn) { - cameraControlButton!!.hierarchy.setPlaceholderImage(R.drawable.ic_videocam_white_24px) + cameraControlButton?.setImageResource(R.drawable.ic_videocam_white_24px) if (cameraEnumerator!!.deviceNames.size > 1) { cameraSwitchButton!!.visibility = View.VISIBLE } } else { - cameraControlButton!!.hierarchy - .setPlaceholderImage(R.drawable.ic_videocam_off_white_24px) + cameraControlButton?.setImageResource(R.drawable.ic_videocam_off_white_24px) cameraSwitchButton!!.visibility = View.GONE } @@ -2373,8 +2364,7 @@ class CallController(args: Bundle) : BaseController() { v.onTouchEvent(event) if (event.action == MotionEvent.ACTION_UP && isPTTActive) { isPTTActive = false - microphoneControlButton!!.hierarchy - .setPlaceholderImage(R.drawable.ic_mic_off_white_24px) + microphoneControlButton?.setImageResource(R.drawable.ic_mic_off_white_24px) pulseAnimation!!.stop() toggleMedia(false, false) animateCallControls(false, 5000) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.kt b/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.kt index 19ddb224c..34f294a08 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.kt @@ -183,7 +183,8 @@ class SwitchAccountController : BaseController { } return super.onCreateView(inflater, container) } - override fun onViewBound(view: View) { + + override fun onViewBound(view: View) { super.onViewBound(view) swipeRefreshLayout!!.isEnabled = false diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.kt b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.kt index 1f8f1b533..b0928962a 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.kt @@ -61,10 +61,8 @@ import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import org.koin.android.ext.android.inject import org.parceler.Parcels import retrofit2.HttpException diff --git a/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt index c18580b96..2a8d4fa76 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt @@ -143,26 +143,26 @@ class PushRegistrationWorker( }) } - override fun onError(e: Throwable) { - eventBus.post( - EventStatus( - userEntityObject.id!!, - EventStatus.EventType.PUSH_REGISTRATION, - false - ) - ) - } + override fun onError(e: Throwable) { + eventBus.post( + EventStatus( + userEntityObject.id!!, + EventStatus.EventType.PUSH_REGISTRATION, + false + ) + ) + } - override fun onComplete() {} - }) - } + override fun onComplete() {} + }) } } } } } + } - companion object { - const val TAG = "PushRegistrationWorker" - } - } \ No newline at end of file + companion object { + const val TAG = "PushRegistrationWorker" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt b/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt index ccdfcb76f..9d0e7e43b 100644 --- a/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt +++ b/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt @@ -37,21 +37,21 @@ data class ExternalSignalingServer( @JsonField(name = ["externalSignalingTicket"]) var externalSignalingTicket: String? = null ) : Parcelable { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false - other as ExternalSignalingServer + other as ExternalSignalingServer - if (externalSignalingServer != other.externalSignalingServer) return false - if (externalSignalingTicket != other.externalSignalingTicket) return false + if (externalSignalingServer != other.externalSignalingServer) return false + if (externalSignalingTicket != other.externalSignalingTicket) return false - return true - } + return true + } - override fun hashCode(): Int { - var result = externalSignalingServer?.hashCode() ?: 0 - result = 31 * result + (externalSignalingTicket?.hashCode() ?: 0) - return result - } + override fun hashCode(): Int { + var result = externalSignalingServer?.hashCode() ?: 0 + result = 31 * result + (externalSignalingTicket?.hashCode() ?: 0) + return result + } } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.kt b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.kt index 269ba95fe..c4b4df4c2 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.kt @@ -32,17 +32,17 @@ import java.util.* @JsonObject @Parcelize data class Capabilities( - @JsonField(name = ["spreed"]) - var spreedCapability: SpreedCapability? = null, - @JsonField(name = ["notifications"]) - var notificationsCapability: NotificationsCapability? = null, - @JsonField(name = ["theming"]) - var themingCapability: ThemingCapability? = null -): Parcelable { + @JsonField(name = ["spreed"]) + var spreedCapability: SpreedCapability? = null, + @JsonField(name = ["notifications"]) + var notificationsCapability: NotificationsCapability? = null, + @JsonField(name = ["theming"]) + var themingCapability: ThemingCapability? = null +) : Parcelable { override fun equals(o: Any?): Boolean { if (this === o) return true if (o !is Capabilities) return false - return (spreedCapability == o.spreedCapability && + return (spreedCapability == o.spreedCapability && notificationsCapability == o.notificationsCapability && themingCapability == o.themingCapability) } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/NotificationsCapability.kt b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/NotificationsCapability.kt index ddc1d9271..edc8a9b77 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/NotificationsCapability.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/NotificationsCapability.kt @@ -32,9 +32,9 @@ import java.util.* @JsonObject @Parcelize data class NotificationsCapability( - @JsonField(name = ["ocs-endpoints"]) - var features: List? = null -): Parcelable { + @JsonField(name = ["ocs-endpoints"]) + var features: List? = null +) : Parcelable { override fun equals(o: Any?): Boolean { if (this === o) return true diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/SpreedCapability.kt b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/SpreedCapability.kt index e05474015..6777d39f4 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/SpreedCapability.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/SpreedCapability.kt @@ -32,11 +32,11 @@ import java.util.* @JsonObject @Parcelize data class SpreedCapability( - @JsonField(name = ["features"]) - var features: List? = null, - @JsonField(name = ["config"]) - var config: HashMap>? = null -): Parcelable { + @JsonField(name = ["features"]) + var features: List? = null, + @JsonField(name = ["config"]) + var config: HashMap>? = null +) : Parcelable { override fun equals(o: Any?): Boolean { if (this === o) return true diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.kt b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.kt index 5bc75a79c..2e0284246 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.kt @@ -32,27 +32,27 @@ import java.util.* @JsonObject @Parcelize data class ThemingCapability( - @JsonField(name = ["name"]) - var name: String? = null, - @JsonField(name = ["url"]) - var url: String? = null, - @JsonField(name = ["slogan"]) - var slogan: String? = null, - @JsonField(name = ["color"]) - var color: String? = null, - @JsonField(name = ["color-text"]) - var colorText: String? = null, - @JsonField(name = ["color-element"]) - var colorElement: String? = null, - @JsonField(name = ["logo"]) - var logo: String? = null, - @JsonField(name = ["background"]) - var background: String? = null, - @JsonField(name = ["background-plain"]) - var backgroundPlain: Boolean = false, - @JsonField(name = ["background-default"]) - var backgroundDefault: Boolean = false -): Parcelable { + @JsonField(name = ["name"]) + var name: String? = null, + @JsonField(name = ["url"]) + var url: String? = null, + @JsonField(name = ["slogan"]) + var slogan: String? = null, + @JsonField(name = ["color"]) + var color: String? = null, + @JsonField(name = ["color-text"]) + var colorText: String? = null, + @JsonField(name = ["color-element"]) + var colorElement: String? = null, + @JsonField(name = ["logo"]) + var logo: String? = null, + @JsonField(name = ["background"]) + var background: String? = null, + @JsonField(name = ["background-plain"]) + var backgroundPlain: Boolean = false, + @JsonField(name = ["background-default"]) + var backgroundDefault: Boolean = false +) : Parcelable { override fun equals(o: Any?): Boolean { if (this === o) return true diff --git a/app/src/main/java/com/nextcloud/talk/models/json/push/PushConfigurationState.kt b/app/src/main/java/com/nextcloud/talk/models/json/push/PushConfigurationState.kt index 637e7d2f2..98f42bdf1 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/push/PushConfigurationState.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/push/PushConfigurationState.kt @@ -44,27 +44,27 @@ data class PushConfigurationState( var usesRegularPass: Boolean = false ) : Parcelable { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false - other as PushConfigurationState + other as PushConfigurationState - if (pushToken != other.pushToken) return false - if (deviceIdentifier != other.deviceIdentifier) return false - if (deviceIdentifierSignature != other.deviceIdentifierSignature) return false - if (userPublicKey != other.userPublicKey) return false - if (usesRegularPass != other.usesRegularPass) return false + if (pushToken != other.pushToken) return false + if (deviceIdentifier != other.deviceIdentifier) return false + if (deviceIdentifierSignature != other.deviceIdentifierSignature) return false + if (userPublicKey != other.userPublicKey) return false + if (usesRegularPass != other.usesRegularPass) return false - return true - } + return true + } - override fun hashCode(): Int { - var result = pushToken?.hashCode() ?: 0 - result = 31 * result + (deviceIdentifier?.hashCode() ?: 0) - result = 31 * result + (deviceIdentifierSignature?.hashCode() ?: 0) - result = 31 * result + (userPublicKey?.hashCode() ?: 0) - result = 31 * result + usesRegularPass.hashCode() - return result - } + override fun hashCode(): Int { + var result = pushToken?.hashCode() ?: 0 + result = 31 * result + (deviceIdentifier?.hashCode() ?: 0) + result = 31 * result + (deviceIdentifierSignature?.hashCode() ?: 0) + result = 31 * result + (userPublicKey?.hashCode() ?: 0) + result = 31 * result + usesRegularPass.hashCode() + return result + } } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/data/source/remote/ApiService.kt b/app/src/main/java/com/nextcloud/talk/newarch/data/source/remote/ApiService.kt index 519f56710..9cff494ee 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/data/source/remote/ApiService.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/data/source/remote/ApiService.kt @@ -67,10 +67,10 @@ interface ApiService { @FormUrlEncoded @POST suspend fun joinConversation(@Header("Authorization") authorization: String, - @Url url: String, @Field("password") password: String?): RoomOverall + @Url url: String, @Field("password") password: String?): RoomOverall @DELETE suspend fun exitConversation(@Header("Authorization") authorization: String, - @Url url: String): GenericOverall + @Url url: String): GenericOverall } diff --git a/app/src/main/java/com/nextcloud/talk/newarch/di/module/ConversationsModule.kt b/app/src/main/java/com/nextcloud/talk/newarch/di/module/ConversationsModule.kt index 5ae5ea51f..e6b9a916e 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/di/module/ConversationsModule.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/di/module/ConversationsModule.kt @@ -57,6 +57,7 @@ fun createJoinConversationUseCase(nextcloudTalkRepository: NextcloudTalkReposito fun createExitConversationUseCase(nextcloudTalkRepository: NextcloudTalkRepository, apiErrorHandler: ApiErrorHandler): ExitConversationUseCase { return ExitConversationUseCase(nextcloudTalkRepository, apiErrorHandler) } + fun createChatViewModelFactory(application: Application, joinConversationUseCase: JoinConversationUseCase, exitConversationUseCase: ExitConversationUseCase, conversationsRepository: ConversationsRepository, messagesRepository: MessagesRepository, conversationsManager: ConversationsManager): ChatViewModelFactory { return ChatViewModelFactory(application, joinConversationUseCase, exitConversationUseCase, conversationsRepository, messagesRepository, conversationsManager) } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/di/module/ManagementModule.kt b/app/src/main/java/com/nextcloud/talk/newarch/di/module/ManagementModule.kt index a6f25edc6..1c4ab6e05 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/di/module/ManagementModule.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/di/module/ManagementModule.kt @@ -30,7 +30,7 @@ import org.koin.dsl.module import java.net.CookieManager val ManagementModule = module { - single{ createConversationsManager(get(), get(), get(), get(), get(), get()) } + single { createConversationsManager(get(), get(), get(), get(), get(), get()) } } fun createConversationsManager(usersRepository: UsersRepository, cookieManager: CookieManager, okHttpClient: OkHttpClient, conversationsRepository: ConversationsRepository, getConversationUseCase: GetConversationUseCase, joinConversationUseCase: JoinConversationUseCase): ConversationsManager { diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt index d240d231b..23f6b56ac 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatView.kt @@ -102,7 +102,7 @@ class ChatView : BaseView(), MessageHolders.ContentChecker, MessagesLi view?.lobbyView?.visibility = View.VISIBLE val timer = conversation.lobbyTimer if (timer != null && timer != 0L) { - view?.lobbyTextView?.text = String.format( + view?.lobbyTextView?.text = String.format( resources!!.getString(R.string.nc_lobby_waiting_with_date), DateUtils.getLocalDateStringFromTimestampForLobby( conversation.lobbyTimer!! diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatViewModel.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatViewModel.kt index c6e6f861f..502996b20 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/chat/ChatViewModel.kt @@ -5,20 +5,15 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations import androidx.lifecycle.viewModelScope import com.nextcloud.talk.models.json.conversations.Conversation -import com.nextcloud.talk.models.json.conversations.RoomOverall -import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.newarch.conversationsList.mvp.BaseViewModel -import com.nextcloud.talk.newarch.data.model.ErrorModel import com.nextcloud.talk.newarch.domain.repository.offline.ConversationsRepository import com.nextcloud.talk.newarch.domain.repository.offline.MessagesRepository import com.nextcloud.talk.newarch.domain.usecases.ExitConversationUseCase import com.nextcloud.talk.newarch.domain.usecases.JoinConversationUseCase -import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse import com.nextcloud.talk.newarch.local.models.UserNgEntity import com.nextcloud.talk.newarch.utils.ConversationsManager import com.nextcloud.talk.newarch.utils.ConversationsManagerInterface import kotlinx.coroutines.launch -import org.koin.core.parameter.parametersOf class ChatViewModel constructor(application: Application, private val joinConversationUseCase: JoinConversationUseCase, diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/di/module/ConversationsListModule.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/di/module/ConversationsListModule.kt index add41eacf..94c07103f 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/di/module/ConversationsListModule.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/di/module/ConversationsListModule.kt @@ -21,10 +21,8 @@ package com.nextcloud.talk.newarch.features.conversationsList.di.module import android.app.Application -import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler import com.nextcloud.talk.newarch.domain.repository.offline.ConversationsRepository import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository -import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkRepository import com.nextcloud.talk.newarch.domain.usecases.DeleteConversationUseCase import com.nextcloud.talk.newarch.domain.usecases.GetConversationsUseCase import com.nextcloud.talk.newarch.domain.usecases.LeaveConversationUseCase diff --git a/app/src/main/java/com/nextcloud/talk/newarch/utils/ConversationsManagerInterface.kt b/app/src/main/java/com/nextcloud/talk/newarch/utils/ConversationsManagerInterface.kt index 7ebd3992c..6374add4f 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/utils/ConversationsManagerInterface.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/utils/ConversationsManagerInterface.kt @@ -23,7 +23,7 @@ package com.nextcloud.talk.newarch.utils import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.newarch.local.models.UserNgEntity -interface ConversationsManagerInterface { +interface ConversationsManagerInterface { enum class OperationStatus { STATUS_OK, STATUS_FAILED diff --git a/app/src/main/java/com/nextcloud/talk/newarch/utils/NetworkUtils.kt b/app/src/main/java/com/nextcloud/talk/newarch/utils/NetworkUtils.kt index 23545e3c6..cf2c7aaac 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/utils/NetworkUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/utils/NetworkUtils.kt @@ -31,7 +31,8 @@ import java.net.Proxy.NO_PROXY import java.net.Proxy.Type import java.net.Proxy.Type.SOCKS -class NetworkUtils { class HeadersInterceptor : Interceptor { +class NetworkUtils { + class HeadersInterceptor : Interceptor { @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { diff --git a/app/src/main/java/com/nextcloud/talk/utils/BetterImageSpan.java b/app/src/main/java/com/nextcloud/talk/utils/BetterImageSpan.java new file mode 100644 index 000000000..dd6ebabcf --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/BetterImageSpan.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.nextcloud.talk.utils; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.text.style.DynamicDrawableSpan; +import android.text.style.ReplacementSpan; + +import androidx.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A better implementation of image spans that also supports centering images against the text. + * + *

In order to migrate from ImageSpan, replace {@code new ImageSpan(drawable, alignment)} with + * {@code new BetterImageSpan(drawable, BetterImageSpan.normalizeAlignment(alignment))}. + * + *

There are 2 main differences between BetterImageSpan and ImageSpan: 1. Pass in ALIGN_CENTER to + * center images against the text. 2. ALIGN_BOTTOM no longer unnecessarily increases the size of the + * text: DynamicDrawableSpan (ImageSpan's parent) adjusts sizes as if alignment was ALIGN_BASELINE + * which can lead to unnecessary whitespace. + */ +public class BetterImageSpan extends ReplacementSpan { + + public static final int ALIGN_BOTTOM = 0; + public static final int ALIGN_BASELINE = 1; + public static final int ALIGN_CENTER = 2; + private final int mAlignment; + private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt(); + private final Drawable mDrawable; + private int mWidth; + private int mHeight; + private Rect mBounds; + public BetterImageSpan(Drawable drawable) { + this(drawable, ALIGN_BASELINE); + } + public BetterImageSpan(Drawable drawable, @BetterImageSpanAlignment int verticalAlignment) { + mDrawable = drawable; + mAlignment = verticalAlignment; + updateBounds(); + } + + /** + * A helper function to allow dropping in BetterImageSpan as a replacement to ImageSpan, and + * allowing for center alignment if passed in. + */ + public static final @BetterImageSpanAlignment + int normalizeAlignment(int alignment) { + switch (alignment) { + case DynamicDrawableSpan.ALIGN_BOTTOM: + return ALIGN_BOTTOM; + case ALIGN_CENTER: + return ALIGN_CENTER; + case DynamicDrawableSpan.ALIGN_BASELINE: + default: + return ALIGN_BASELINE; + } + } + + public Drawable getDrawable() { + return mDrawable; + } + + /** + * Returns the width of the image span and increases the height if font metrics are available. + */ + @Override + public int getSize( + Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fontMetrics) { + updateBounds(); + if (fontMetrics == null) { + return mWidth; + } + + int offsetAbove = getOffsetAboveBaseline(fontMetrics); + int offsetBelow = mHeight + offsetAbove; + if (offsetAbove < fontMetrics.ascent) { + fontMetrics.ascent = offsetAbove; + } + + if (offsetAbove < fontMetrics.top) { + fontMetrics.top = offsetAbove; + } + + if (offsetBelow > fontMetrics.descent) { + fontMetrics.descent = offsetBelow; + } + + if (offsetBelow > fontMetrics.bottom) { + fontMetrics.bottom = offsetBelow; + } + + return mWidth; + } + + @Override + public void draw( + Canvas canvas, + CharSequence text, + int start, + int end, + float x, + int top, + int y, + int bottom, + Paint paint) { + paint.getFontMetricsInt(mFontMetricsInt); + int iconTop = y + getOffsetAboveBaseline(mFontMetricsInt); + canvas.translate(x, iconTop); + mDrawable.draw(canvas); + canvas.translate(-x, -iconTop); + } + + public void updateBounds() { + mBounds = mDrawable.getBounds(); + + mWidth = mBounds.width(); + mHeight = mBounds.height(); + } + + private int getOffsetAboveBaseline(Paint.FontMetricsInt fm) { + switch (mAlignment) { + case ALIGN_BOTTOM: + return fm.descent - mHeight; + case ALIGN_CENTER: + int textHeight = fm.descent - fm.ascent; + int offset = (textHeight - mHeight) / 2; + return fm.ascent + offset; + case ALIGN_BASELINE: + default: + return -mHeight; + } + } + + @IntDef({ALIGN_BASELINE, ALIGN_BOTTOM, ALIGN_CENTER}) + @Retention(RetentionPolicy.SOURCE) + public @interface BetterImageSpanAlignment { + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt index 8307bb335..2920e3323 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt @@ -25,9 +25,7 @@ import android.content.Context import android.content.Intent import android.content.res.ColorStateList import android.content.res.Resources -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Typeface +import android.graphics.* import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.net.Uri @@ -41,7 +39,6 @@ import android.text.style.StyleSpan import android.util.Log import android.util.TypedValue import android.view.View -import android.view.ViewGroup import android.widget.EditText import android.widget.TextView import androidx.annotation.ColorInt @@ -50,30 +47,25 @@ import androidx.annotation.DrawableRes import androidx.annotation.XmlRes import androidx.appcompat.widget.AppCompatDrawableManager import androidx.core.content.ContextCompat +import androidx.core.graphics.applyCanvas import androidx.core.graphics.drawable.DrawableCompat import androidx.emoji.text.EmojiCompat import coil.Coil import coil.api.load +import coil.bitmappool.BitmapPool import coil.target.Target import coil.transform.CircleCropTransformation -import com.facebook.drawee.view.SimpleDraweeView -import com.facebook.imagepipeline.common.RotationOptions -import com.facebook.imagepipeline.image.ImageInfo -import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor -import com.facebook.imagepipeline.request.ImageRequest -import com.facebook.imagepipeline.request.ImageRequestBuilder -import com.facebook.widget.text.span.BetterImageSpan import com.google.android.material.chip.ChipDrawable import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.events.UserMentionClickEvent -import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.newarch.local.models.UserNgEntity import com.nextcloud.talk.newarch.utils.Images import com.nextcloud.talk.utils.text.Spans import org.greenrobot.eventbus.EventBus import java.lang.reflect.InvocationTargetException import java.util.regex.Pattern +import kotlin.math.min object DisplayUtils { @@ -103,25 +95,25 @@ object DisplayUtils { textView.movementMethod = LinkMovementMethod.getInstance() } - private fun updateViewSize( - imageInfo: ImageInfo?, - draweeView: SimpleDraweeView - ) { - if (imageInfo != null) { - val maxSize = draweeView.context - .resources - .getDimensionPixelSize(R.dimen.maximum_file_preview_size) - draweeView.layoutParams.width = if (imageInfo.width > maxSize) maxSize else imageInfo.width - draweeView.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT - draweeView.aspectRatio = imageInfo.width.toFloat() / imageInfo.height - draweeView.requestLayout() - } - } - fun getRoundedDrawable(drawable: Drawable?): Drawable { val bitmap = getBitmap(drawable!!) - RoundAsCirclePostprocessor(true).process(bitmap) - return BitmapDrawable(bitmap) + return BitmapDrawable(roundImage(BitmapPool(10000), bitmap)) + } + + private fun roundImage(pool: BitmapPool, input: Bitmap): Bitmap { + val circlePaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG) + val bitmapPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG).apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) } + + val minSize = min(input.width, input.height) + val radius = minSize / 2f + val output = pool.get(minSize, minSize, input.config) + output.applyCanvas { + drawCircle(radius, radius, radius, circlePaint) + drawBitmap(input, 0f, 0f, bitmapPaint) + } + pool.put(input) + + return output } private fun getBitmap(drawable: Drawable): Bitmap { @@ -364,22 +356,6 @@ object DisplayUtils { return spannableString } - fun getImageRequestForUrl(url: String, userEntity: UserEntity?): ImageRequest { - val headers = HashMap() - if (userEntity != null && url.startsWith(userEntity.baseUrl) && url.contains( - "index.php/core/preview?fileId=")) { - headers.put("Authorization", - ApiUtils.getCredentials(userEntity.username, userEntity.token)) - } - - return ImageRequestBuilder.newBuilderWithSource(Uri.parse(url)) - .setProgressiveRenderingEnabled(true) - .setRotationOptions(RotationOptions.autoRotate()) - .disableDiskCache() - .setHeaders(headers) - .build() - } - fun getMessageSelector( @ColorInt normalColor: Int, @ColorInt selectedColor: Int, @ColorInt pressedColor: Int, @DrawableRes shape: Int diff --git a/app/src/main/java/com/nextcloud/talk/utils/OkHttpNetworkFetcherWithCache.java b/app/src/main/java/com/nextcloud/talk/utils/OkHttpNetworkFetcherWithCache.java deleted file mode 100644 index e3bb9e02f..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/OkHttpNetworkFetcherWithCache.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017-2018 Mario Danic - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.nextcloud.talk.utils; - -import com.facebook.imagepipeline.backends.okhttp3.OkHttpNetworkFetcher; - -import java.util.concurrent.Executor; - -import okhttp3.Call; -import okhttp3.OkHttpClient; - -public class OkHttpNetworkFetcherWithCache extends OkHttpNetworkFetcher { - public OkHttpNetworkFetcherWithCache(OkHttpClient okHttpClient) { - super(okHttpClient); - } - - public OkHttpNetworkFetcherWithCache(Call.Factory callFactory, Executor cancellationExecutor) { - super(callFactory, cancellationExecutor); - } - - public OkHttpNetworkFetcherWithCache(Call.Factory callFactory, Executor cancellationExecutor, - boolean disableOkHttpCache) { - super(callFactory, cancellationExecutor, true); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/text/Spans.java b/app/src/main/java/com/nextcloud/talk/utils/text/Spans.java index 79c7d75f2..093cb16e4 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/text/Spans.java +++ b/app/src/main/java/com/nextcloud/talk/utils/text/Spans.java @@ -24,7 +24,7 @@ import android.graphics.drawable.Drawable; import androidx.annotation.NonNull; -import com.facebook.widget.text.span.BetterImageSpan; +import com.nextcloud.talk.utils.BetterImageSpan; import lombok.Data; diff --git a/app/src/main/res/drawable/negative_color_circle.xml b/app/src/main/res/drawable/negative_color_circle.xml new file mode 100644 index 000000000..377bb68c1 --- /dev/null +++ b/app/src/main/res/drawable/negative_color_circle.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/positive_color_circle.xml b/app/src/main/res/drawable/positive_color_circle.xml new file mode 100644 index 000000000..1e82373b5 --- /dev/null +++ b/app/src/main/res/drawable/positive_color_circle.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/primary_circle.xml b/app/src/main/res/drawable/primary_circle.xml deleted file mode 100644 index 3c6519214..000000000 --- a/app/src/main/res/drawable/primary_circle.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/primary_color_circle.xml b/app/src/main/res/drawable/primary_color_circle.xml new file mode 100644 index 000000000..920502ce2 --- /dev/null +++ b/app/src/main/res/drawable/primary_color_circle.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/controller_call.xml b/app/src/main/res/layout/controller_call.xml index a18d8a7ae..37d810b15 100644 --- a/app/src/main/res/layout/controller_call.xml +++ b/app/src/main/res/layout/controller_call.xml @@ -66,49 +66,49 @@ android:background="@android:color/transparent" android:gravity="center"> - + android:scaleType="centerInside" + android:background="@drawable/primary_color_circle" + android:src="@drawable/ic_mic_off_white_24px" /> - + android:scaleType="centerInside" + android:background="@drawable/primary_color_circle" + android:src="@drawable/ic_videocam_white_24px"/> - + android:scaleType="centerInside" + android:background="@drawable/primary_color_circle" + android:src="@drawable/ic_volume_mute_white_24dp" /> - + android:background="@drawable/negative_color_circle" + android:scaleType="centerInside" + android:src="@drawable/ic_call_end_white_24px"/> - + android:visibility="visible" + android:scaleType="centerInside" + android:background="@drawable/primary_color_circle" + android:src="@drawable/ic_switch_video_white_24px" + /> + android:layout_height="match_parent" + android:visibility="gone"/> diff --git a/app/src/main/res/layout/controller_call_notification.xml b/app/src/main/res/layout/controller_call_notification.xml index 6a989ceb2..8c2a9bb65 100644 --- a/app/src/main/res/layout/controller_call_notification.xml +++ b/app/src/main/res/layout/controller_call_notification.xml @@ -39,34 +39,34 @@ android:animateLayoutChanges="true" android:orientation="horizontal"> - + android:scaleType="centerInside" + android:background="@color/nc_darkGreen" + android:src="@drawable/ic_call_white_24dp" /> - + android:scaleType="centerInside" + android:background="@drawable/negative_color_circle" + android:src="@drawable/ic_call_end_white_24px" /> - + android:scaleType="centerInside" + android:background="@color/nc_darkGreen" + android:src="@drawable/ic_videocam_white_24px" /> - + android:scaleType="fitCenter" /> - + /> diff --git a/app/src/main/res/layout/item_custom_incoming_text_message.xml b/app/src/main/res/layout/item_custom_incoming_text_message.xml index b4bb55a17..25b2ce5fa 100644 --- a/app/src/main/res/layout/item_custom_incoming_text_message.xml +++ b/app/src/main/res/layout/item_custom_incoming_text_message.xml @@ -27,13 +27,12 @@ android:layout_marginRight="16dp" android:layout_marginBottom="2dp"> - + android:layout_marginEnd="8dp" /> - + android:scaleType="fitCenter" />