SettingsPresenter.kt

package chat.rocket.android.settings.presentation

import android.content.Context
import android.content.Intent
import android.os.Build
import chat.rocket.android.R
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.dynamiclinks.DynamicLinksForFirebase
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.RemoveAccountInteractor
import chat.rocket.android.server.domain.SaveCurrentLanguageInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.HashType
import chat.rocket.android.util.extension.hash
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.adminPanelUrl
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.retryIO
import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.rest.deleteOwnAccount
import chat.rocket.core.internal.rest.serverInfo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.util.*
import javax.inject.Inject
import javax.inject.Named

class SettingsPresenter @Inject constructor(
    private val view: SettingsView,
    private val strategy: CancelStrategy,
    private val navigator: MainNavigator,
    @Named("currentServer") private val currentServer: String?,
    private val userHelper: UserHelper,
    private val analyticsTrackingInteractor: AnalyticsTrackingInteractor,
    private val tokenRepository: TokenRepository,
    private val permissions: PermissionsInteractor,
    private val rocketChatClientFactory: RocketChatClientFactory,
    private val dynamicLinksManager: DynamicLinksForFirebase,
    private val saveLanguageInteractor: SaveCurrentLanguageInteractor,
    getCurrentServerInteractor: GetCurrentServerInteractor,
    removeAccountInteractor: RemoveAccountInteractor,
    databaseManagerFactory: DatabaseManagerFactory?,
    connectionManagerFactory: ConnectionManagerFactory
) : CheckServerPresenter(
    strategy = strategy,
    factory = rocketChatClientFactory,
    currentSavedServer = currentServer,
    serverInteractor = getCurrentServerInteractor,
    removeAccountInteractor = removeAccountInteractor,
    tokenRepository = tokenRepository,
    dbManagerFactory = databaseManagerFactory,
    managerFactory = connectionManagerFactory,
    tokenView = view,
    navigator = navigator
) {
    private val token = currentServer?.let { tokenRepository.get(it) }

    fun setupView() {
        launchUI(strategy) {
            try {
                currentServer?.let {
                    val serverInfo = retryIO(description = "serverInfo", times = 5) {
                        rocketChatClientFactory.get(it).serverInfo()
                    }

                    userHelper.user()?.let { user ->
                        view.setupSettingsView(
                            it.avatarUrl(user.username!!, token?.userId, token?.authToken),
                            userHelper.displayName(user) ?: user.username ?: "",
                            user.status.toString(),
                            permissions.isAdministrationEnabled(),
                            analyticsTrackingInteractor.get(),
                            true,
                            serverInfo.version
                        )
                    }
                }
            } catch (exception: Exception) {
                Timber.d(exception, "Error getting server info")
                exception.message?.let {
                    view.showMessage(it)
                }.ifNull {
                    view.showGenericErrorMessage()
                }
            }
        }
    }

    fun enableAnalyticsTracking(isEnabled: Boolean) {
        analyticsTrackingInteractor.save(isEnabled)
    }

    fun deleteAccount(password: String) {
        launchUI(strategy) {
            view.showLoading()
            try {
                currentServer?.let {
                    withContext(Dispatchers.Default) {
                        // REMARK: Backend API is only working with a lowercase hash.
                        // https://github.com/RocketChat/Rocket.Chat/issues/12573
                        retryIO {
                            rocketChatClientFactory.get(it)
                                .deleteOwnAccount(password.hash(HashType.Sha256).toLowerCase())
                        }
                        setupConnectionInfo(it)
                        logout()
                    }
                }
            } catch (exception: Exception) {
                exception.message?.let {
                    view.showMessage(it)
                }.ifNull {
                    view.showGenericErrorMessage()
                }
            } finally {
                view.hideLoading()
            }
        }
    }

    fun getCurrentLocale(context: Context): Locale {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            context.resources.configuration.locales.get(0)
        } else {
            context.resources.configuration.locale
        }
    }

    fun saveLocale(language: String, country: String? = null) {
        saveLanguageInteractor.save(language, country)
    }

    fun toProfile() = navigator.toProfile()

    fun toAdmin() = currentServer?.let { currentServer ->
        tokenRepository.get(currentServer)?.let {
            navigator.toAdminPanel(currentServer.adminPanelUrl(), it.authToken)
        }
    }

    fun toLicense(licenseUrl: String, licenseTitle: String) =
        navigator.toLicense(licenseUrl, licenseTitle)

    fun shareViaApp(context: Context?) {
        launchUI(strategy) {
            val user = userHelper.user()

            val deepLinkCallback = { returnedString: String? ->
                val link = returnedString ?: context?.getString(R.string.play_store_link)
                with(Intent(Intent.ACTION_SEND)) {
                    type = "text/plain"
                    putExtra(Intent.EXTRA_SUBJECT, context?.getString(R.string.msg_check_this_out))
                    putExtra(Intent.EXTRA_TEXT, link)
                    context?.startActivity(
                        Intent.createChooser(
                            this,
                            context.getString(R.string.msg_share_using)
                        )
                    )
                }
            }
            currentServer?.let {
                dynamicLinksManager.createDynamicLink(user?.username, it, deepLinkCallback)
            }
        }
    }

    fun recreateActivity() = navigator.recreateActivity()
}