Remove Fresco & Cleanups

This commit is contained in:
Mario Danic 2019-12-19 17:18:35 +01:00
parent 0ab30c439e
commit 380667040a
No known key found for this signature in database
GPG Key ID: CDE0BBD2738C4CC0
36 changed files with 359 additions and 316 deletions

View File

@ -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}"

View File

@ -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<Drawable>(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) {

View File

@ -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()

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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"
}
}
companion object {
const val TAG = "PushRegistrationWorker"
}
}

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -32,9 +32,9 @@ import java.util.*
@JsonObject
@Parcelize
data class NotificationsCapability(
@JsonField(name = ["ocs-endpoints"])
var features: List<String>? = null
): Parcelable {
@JsonField(name = ["ocs-endpoints"])
var features: List<String>? = null
) : Parcelable {
override fun equals(o: Any?): Boolean {
if (this === o) return true

View File

@ -32,11 +32,11 @@ import java.util.*
@JsonObject
@Parcelize
data class SpreedCapability(
@JsonField(name = ["features"])
var features: List<String>? = null,
@JsonField(name = ["config"])
var config: HashMap<String, HashMap<String, String>>? = null
): Parcelable {
@JsonField(name = ["features"])
var features: List<String>? = null,
@JsonField(name = ["config"])
var config: HashMap<String, HashMap<String, String>>? = null
) : Parcelable {
override fun equals(o: Any?): Boolean {
if (this === o) return true

View File

@ -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

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -102,7 +102,7 @@ class ChatView : BaseView(), MessageHolders.ContentChecker<IMessage>, 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!!

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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.
*
* <p>In order to migrate from ImageSpan, replace {@code new ImageSpan(drawable, alignment)} with
* {@code new BetterImageSpan(drawable, BetterImageSpan.normalizeAlignment(alignment))}.
*
* <p>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 {
}
}

View File

@ -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<String, String>()
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

View File

@ -1,43 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@ -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;

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="@color/nc_darkRed"/>
<size android:width="10dp" android:height="10dp"/>
</shape>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="@color/nc_darkGreen"/>
<size android:width="10dp" android:height="10dp"/>
</shape>

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~
~ 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 <http://www.gnu.org/licenses/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="@color/colorPrimary"/>
</shape>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="@color/colorPrimary"/>
<size android:width="10dp" android:height="10dp"/>
</shape>

View File

@ -66,49 +66,49 @@
android:background="@android:color/transparent"
android:gravity="center">
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto"
<ImageView
android:id="@+id/call_control_microphone"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginStart="24dp"
android:alpha="0.7"
app:backgroundImage="@color/colorPrimary"
app:placeholderImage="@drawable/ic_mic_off_white_24px"
app:roundAsCircle="true" />
android:scaleType="centerInside"
android:background="@drawable/primary_color_circle"
android:src="@drawable/ic_mic_off_white_24px" />
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto"
<ImageView
android:id="@+id/call_control_camera"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:alpha="0.7"
app:backgroundImage="@color/colorPrimary"
app:placeholderImage="@drawable/ic_videocam_white_24px"
app:roundAsCircle="true" />
android:scaleType="centerInside"
android:background="@drawable/primary_color_circle"
android:src="@drawable/ic_videocam_white_24px"/>
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto"
<ImageView
android:id="@+id/callControlEnableSpeaker"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:visibility="gone"
app:backgroundImage="@color/colorPrimary"
app:placeholderImage="@drawable/ic_volume_mute_white_24dp"
app:roundAsCircle="true" />
android:scaleType="centerInside"
android:background="@drawable/primary_color_circle"
android:src="@drawable/ic_volume_mute_white_24dp" />
</LinearLayout>
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto"
<ImageView
android:id="@+id/callControlHangupView"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_above="@id/callControlsLinearLayoutView"
android:layout_centerHorizontal="true"
app:backgroundImage="@color/nc_darkRed"
app:placeholderImage="@drawable/ic_call_end_white_24px"
app:roundAsCircle="true" />
android:background="@drawable/negative_color_circle"
android:scaleType="centerInside"
android:src="@drawable/ic_call_end_white_24px"/>
</RelativeLayout>
<FrameLayout
@ -125,20 +125,23 @@
android:layout_margin="16dp"
android:visibility="invisible" />
<com.facebook.drawee.view.SimpleDraweeView xmlns:app="http://schemas.android.com/apk/res-auto"
<ImageView xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/call_control_switch_camera"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="20dp"
app:backgroundImage="@color/colorPrimary"
app:placeholderImage="@drawable/ic_switch_video_white_24px"
app:roundAsCircle="true" />
android:visibility="visible"
android:scaleType="centerInside"
android:background="@drawable/primary_color_circle"
android:src="@drawable/ic_switch_video_white_24px"
/>
</FrameLayout>
<include
layout="@layout/call_states"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
android:visibility="gone"/>
</RelativeLayout>

View File

@ -39,34 +39,34 @@
android:animateLayoutChanges="true"
android:orientation="horizontal">
<com.facebook.drawee.view.SimpleDraweeView
<ImageView
android:id="@+id/callAnswerVoiceOnlyView"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="24dp"
android:visibility="gone"
app:backgroundImage="@color/nc_darkGreen"
app:placeholderImage="@drawable/ic_call_white_24dp"
app:roundAsCircle="true" />
android:scaleType="centerInside"
android:background="@color/nc_darkGreen"
android:src="@drawable/ic_call_white_24dp" />
<com.facebook.drawee.view.SimpleDraweeView
<ImageView
android:id="@+id/callControlHangupView"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="24dp"
app:backgroundImage="@color/nc_darkRed"
app:placeholderImage="@drawable/ic_call_end_white_24px"
app:roundAsCircle="true" />
android:scaleType="centerInside"
android:background="@drawable/negative_color_circle"
android:src="@drawable/ic_call_end_white_24px" />
<com.facebook.drawee.view.SimpleDraweeView
<ImageView
android:id="@+id/callAnswerCameraView"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="24dp"
android:visibility="gone"
app:backgroundImage="@color/nc_darkGreen"
app:placeholderImage="@drawable/ic_videocam_white_24px"
app:roundAsCircle="true" />
android:scaleType="centerInside"
android:background="@color/nc_darkGreen"
android:src="@drawable/ic_videocam_white_24px" />
</LinearLayout>
<RelativeLayout

View File

@ -32,12 +32,12 @@
android:layout_height="wrap_content"
android:layout_toEndOf="@id/messageUserAvatar">
<com.facebook.drawee.view.SimpleDraweeView
<ImageView
android:id="@id/image"
android:layout_width="@dimen/minimum_file_preview_size"
android:layout_height="@dimen/minimum_file_preview_size"
android:adjustViewBounds="true"
app:actualImageScaleType="fitCenter" />
android:scaleType="fitCenter" />
<com.google.android.flexbox.FlexboxLayout
android:layout_width="wrap_content"
@ -79,13 +79,13 @@
</RelativeLayout>
<com.facebook.drawee.view.SimpleDraweeView
<ImageView
android:id="@id/messageUserAvatar"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginEnd="8dp"
app:roundAsCircle="true" />
/>
</RelativeLayout>

View File

@ -27,13 +27,12 @@
android:layout_marginRight="16dp"
android:layout_marginBottom="2dp">
<com.facebook.drawee.view.SimpleDraweeView
<ImageView
android:id="@id/messageUserAvatar"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentTop="true"
android:layout_marginEnd="8dp"
app:roundAsCircle="true" />
android:layout_marginEnd="8dp" />
<com.google.android.flexbox.FlexboxLayout
android:id="@id/bubble"

View File

@ -27,13 +27,13 @@
android:layout_marginEnd="16dp"
android:layout_marginBottom="2dp">
<com.facebook.drawee.view.SimpleDraweeView
<ImageView
android:id="@id/image"
android:layout_width="@dimen/minimum_file_preview_size"
android:layout_height="@dimen/minimum_file_preview_size"
android:layout_alignParentEnd="true"
android:adjustViewBounds="true"
app:actualImageScaleType="fitCenter" />
android:scaleType="fitCenter" />
<com.google.android.flexbox.FlexboxLayout
android:layout_width="wrap_content"

View File

@ -49,7 +49,7 @@
android:id="@+id/imageView"
android:layout_width="@dimen/small_item_height"
android:layout_height="@dimen/small_item_height"
android:background="@drawable/primary_circle"
android:background="@drawable/primary_color_circle"
android:layout_centerVertical="true"
android:layout_marginEnd="8dp" />