Commit 30a02575 authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Merge branch 'v3.0.0' into redesignOnboarding

parents 8c74508e 93d43d3b
......@@ -6,6 +6,7 @@ if (isPlay) { apply plugin: 'io.fabric' }
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: "com.github.ben-manes.versions"
android {
compileSdkVersion versions.compileSdk
......@@ -15,8 +16,8 @@ android {
applicationId "chat.rocket.android"
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
versionCode 2036
versionName "2.5.1"
versionCode 2042
versionName "2.6.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
......@@ -104,6 +105,7 @@ dependencies {
implementation libraries.browser
implementation libraries.androidKtx
implementation libraries.fragmentsKtx
implementation libraries.dagger
implementation libraries.daggerSupport
......@@ -117,6 +119,8 @@ dependencies {
kapt libraries.roomProcessor
implementation libraries.lifecycleExtensions
kapt libraries.lifecycleCompiler
implementation libraries.viewmodelKtx
implementation libraries.workmanager
implementation libraries.rxKotlin
implementation libraries.rxAndroid
......@@ -145,14 +149,14 @@ dependencies {
implementation libraries.aVLoadingIndicatorView
implementation "com.github.luciofm:livedata-ktx:b1e8bbc25a"
implementation libraries.livedataKtx
// Proprietary libraries
playImplementation libraries.fcm
playImplementation libraries.firebaseAnalytics
playImplementation libraries.playServicesAuth
playImplementation('com.crashlytics.sdk.android:crashlytics:2.9.4@aar') { transitive = true }
playImplementation('com.crashlytics.sdk.android:answers:1.4.2@aar') { transitive = true }
playImplementation('com.crashlytics.sdk.android:crashlytics:2.9.5@aar') { transitive = true }
playImplementation('com.crashlytics.sdk.android:answers:1.4.3@aar') { transitive = true }
testImplementation libraries.junit
testImplementation libraries.truth
......
package chat.rocket.android.util.helper.analytics
package chat.rocket.android.analytics
import chat.rocket.android.util.helper.analytics.event.AuthenticationEvent
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import chat.rocket.android.util.helper.analytics.event.SubscriptionTypeEvent
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.analytics.event.SubscriptionTypeEvent
object AnalyticsManager : Analytics {
class AnswersAnalytics : Analytics {
override fun logLogin(event: AuthenticationEvent, loginSucceeded: Boolean) {
// Do absolutely nothing
......
package chat.rocket.android.analytics
import android.content.Context
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.analytics.event.SubscriptionTypeEvent
import javax.inject.Inject
class GoogleAnalyticsForFirebase @Inject constructor(val context: Context) :
Analytics {
override fun logLogin(event: AuthenticationEvent, loginSucceeded: Boolean) {
// Do absolutely nothing
}
override fun logSignUp(event: AuthenticationEvent, signUpSucceeded: Boolean) {
// Do absolutely nothing
}
override fun logScreenView(event: ScreenViewEvent) {
// Do absolutely nothing
}
override fun logMessageSent(event: SubscriptionTypeEvent, serverUrl: String) {
// Do absolutely nothing
}
override fun logMediaUploaded(event: SubscriptionTypeEvent, mimeType: String) {
// Do absolutely nothing
}
override fun logReaction(event: SubscriptionTypeEvent) {
// Do absolutely nothing
}
override fun logServerSwitch(serverUrl: String, serverCount: Int) {
// Do absolutely nothing
}
}
package chat.rocket.android.push
class FirebaseTokenService {
}
\ No newline at end of file
fun refreshPushToken() {
}
package chat.rocket.android.util
import chat.rocket.android.main.presentation.MainPresenter
fun refreshFCMToken(presenter: MainPresenter) {
//Do absolutely nothing
}
fun invalidateFirebaseToken(token: String) {
//Do absolutely nothing
}
\ No newline at end of file
app/src/main/ic_launcher-web.png

39.1 KB | W: | H:

app/src/main/ic_launcher-web.png

63.8 KB | W: | H:

app/src/main/ic_launcher-web.png
app/src/main/ic_launcher-web.png
app/src/main/ic_launcher-web.png
app/src/main/ic_launcher-web.png
  • 2-up
  • Swipe
  • Onion skin
package chat.rocket.android.about.di
import chat.rocket.android.about.ui.AboutFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class AboutFragmentProvider {
@ContributesAndroidInjector()
abstract fun provideAboutFragment(): AboutFragment
}
......@@ -7,10 +7,10 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import chat.rocket.android.BuildConfig
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_about.*
import javax.inject.Inject
......@@ -19,7 +19,12 @@ internal const val TAG_ABOUT_FRAGMENT = "AboutFragment"
class AboutFragment : Fragment() {
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
}
override fun onCreateView(
inflater: LayoutInflater,
......@@ -32,15 +37,15 @@ class AboutFragment : Fragment() {
setupToolbar()
setupViews()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.About)
}
analyticsManager.logScreenView(ScreenViewEvent.About)
}
private fun setupViews() {
text_version_name.text = BuildConfig.VERSION_NAME
text_build_number.text = getString(R.string.msg_build, BuildConfig.VERSION_CODE,
BuildConfig.GIT_SHA, BuildConfig.FLAVOR)
text_build_number.text = getString(
R.string.msg_build, BuildConfig.VERSION_CODE,
BuildConfig.GIT_SHA, BuildConfig.FLAVOR
)
}
private fun setupToolbar() {
......
package chat.rocket.android.util.helper.analytics
package chat.rocket.android.analytics
import chat.rocket.android.util.helper.analytics.event.AuthenticationEvent
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import chat.rocket.android.util.helper.analytics.event.SubscriptionTypeEvent
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.analytics.event.SubscriptionTypeEvent
interface Analytics {
......
package chat.rocket.android.analytics
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.analytics.event.SubscriptionTypeEvent
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import javax.inject.Inject
class AnalyticsManager @Inject constructor(
private val analyticsTrackingInteractor: AnalyticsTrackingInteractor,
getCurrentServerInteractor: GetCurrentServerInteractor,
getAccountsInteractor: GetAccountsInteractor,
private val analytics: List<Analytics>
) {
val serverUrl = getCurrentServerInteractor.get()
val accounts = getAccountsInteractor.get()
fun logLogin(
event: AuthenticationEvent,
loginSucceeded: Boolean
) {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logLogin(event, loginSucceeded) }
}
}
fun logSignUp(
event: AuthenticationEvent,
signUpSucceeded: Boolean
) {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logSignUp(event, signUpSucceeded) }
}
}
fun logScreenView(event: ScreenViewEvent) {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logScreenView(event) }
}
}
fun logMessageSent(event: SubscriptionTypeEvent) {
if (analyticsTrackingInteractor.get() && serverUrl != null) {
analytics.forEach { it.logMessageSent(event, serverUrl) }
}
}
fun logMediaUploaded(event: SubscriptionTypeEvent, mimeType: String) {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMediaUploaded(event, mimeType) }
}
}
fun logReaction(event: SubscriptionTypeEvent) {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logReaction(event) }
}
}
fun logServerSwitch() {
if (analyticsTrackingInteractor.get() && serverUrl != null) {
analytics.forEach { it.logServerSwitch(serverUrl, accounts.size) }
}
}
}
package chat.rocket.android.util.helper.analytics.event
package chat.rocket.android.analytics.event
sealed class AuthenticationEvent(val methodName: String) {
object AuthenticationWithUserAndPassword : AuthenticationEvent("User and password")
object AuthenticationWithCas : AuthenticationEvent("CAS")
object AuthenticationWithSaml : AuthenticationEvent("SAML")
object AuthenticationWithOauth : AuthenticationEvent("Oauth")
object AuthenticationWithDeeplink : AuthenticationEvent("Deep link")
}
package chat.rocket.android.util.helper.analytics.event
package chat.rocket.android.analytics.event
sealed class ScreenViewEvent(val screenName: String) {
......@@ -23,4 +23,4 @@ sealed class ScreenViewEvent(val screenName: String) {
object Settings : ScreenViewEvent("SettingsFragment")
object SignUp : ScreenViewEvent("SignupFragment")
object TwoFa : ScreenViewEvent("TwoFAFragment")
}
\ No newline at end of file
}
package chat.rocket.android.util.helper.analytics.event
package chat.rocket.android.analytics.event
sealed class SubscriptionTypeEvent(val subscriptionTypeName: String) {
object DirectMessage : SubscriptionTypeEvent("Direct Message")
object Channel : SubscriptionTypeEvent("Channel")
object Group : SubscriptionTypeEvent("Group")
}
\ No newline at end of file
}
......@@ -8,9 +8,15 @@ import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.work.Worker
import chat.rocket.android.BuildConfig
import chat.rocket.android.dagger.DaggerAppComponent
import chat.rocket.android.dagger.injector.HasWorkerInjector
import chat.rocket.android.dagger.qualifier.ForMessages
import chat.rocket.android.emoji.Emoji
import chat.rocket.android.emoji.EmojiRepository
import chat.rocket.android.emoji.Fitzpatrick
import chat.rocket.android.emoji.internal.EmojiCategory
import chat.rocket.android.helper.CrashlyticsTree
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.AccountsRepository
......@@ -18,22 +24,26 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.SITE_URL
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO
import chat.rocket.android.util.setupFabric
import chat.rocket.common.RocketChatException
import chat.rocket.core.internal.rest.getCustomEmojis
import com.facebook.drawee.backends.pipeline.DraweeConfig
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.core.ImagePipelineConfig
import com.jakewharton.threetenabp.AndroidThreeTen
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasActivityInjector
import dagger.android.HasBroadcastReceiverInjector
import dagger.android.HasServiceInjector
import kotlinx.coroutines.experimental.launch
import timber.log.Timber
import java.lang.ref.WeakReference
import javax.inject.Inject
class RocketChatApplication : Application(), HasActivityInjector, HasServiceInjector,
HasBroadcastReceiverInjector {
HasBroadcastReceiverInjector, HasWorkerInjector {
@Inject
lateinit var appLifecycleObserver: AppLifecycleObserver
......@@ -47,6 +57,9 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
@Inject
lateinit var broadcastReceiverInjector: DispatchingAndroidInjector<BroadcastReceiver>
@Inject
lateinit var workerInjector: DispatchingAndroidInjector<Worker>
@Inject
lateinit var imagePipelineConfig: ImagePipelineConfig
@Inject
......@@ -63,6 +76,8 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
lateinit var localRepository: LocalRepository
@Inject
lateinit var accountRepository: AccountsRepository
@Inject
lateinit var factory: RocketChatClientFactory
@Inject
@field:ForMessages
......@@ -98,6 +113,9 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
// TODO - remove REALM files.
// TODO - remove this
checkCurrentServer()
// TODO - FIXME - we need to proper inject the EmojiRepository and initialize it properly
loadEmojis()
}
private fun checkCurrentServer() {
......@@ -132,17 +150,13 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
}
}
override fun activityInjector(): AndroidInjector<Activity> {
return activityDispatchingAndroidInjector
}
override fun activityInjector() = activityDispatchingAndroidInjector
override fun serviceInjector(): AndroidInjector<Service> {
return serviceDispatchingAndroidInjector
}
override fun serviceInjector() = serviceDispatchingAndroidInjector
override fun broadcastReceiverInjector(): AndroidInjector<BroadcastReceiver> {
return broadcastReceiverInjector
}
override fun broadcastReceiverInjector() = broadcastReceiverInjector
override fun workerInjector() = workerInjector
companion object {
var context: WeakReference<Context>? = null
......@@ -150,6 +164,44 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
return context?.get()
}
}
// TODO - FIXME - This is a big Workaround
/**
* Load all emojis for the current server. Simple emojis are always the same for every server,
* but custom emojis vary according to the its url.
*/
fun loadEmojis() {
EmojiRepository.init(this)
val currentServer = getCurrentServerInteractor.get()
currentServer?.let { server ->
launch {
val client = factory.create(server)
EmojiRepository.setCurrentServerUrl(server)
val customEmojiList = mutableListOf<Emoji>()
try {
for (customEmoji in retryIO("getCustomEmojis()") { client.getCustomEmojis() }) {
customEmojiList.add(Emoji(
shortname = ":${customEmoji.name}:",
category = EmojiCategory.CUSTOM.name,
url = "$currentServer/emoji-custom/${customEmoji.name}.${customEmoji.extension}",
count = 0,
fitzpatrick = Fitzpatrick.Default.type,
keywords = customEmoji.aliases,
shortnameAlternates = customEmoji.aliases,
siblings = mutableListOf(),
unicode = "",
isDefault = true
))
}
EmojiRepository.load(this@RocketChatApplication, customEmojis = customEmojiList)
} catch (ex: RocketChatException) {
Timber.e(ex)
EmojiRepository.load(this@RocketChatApplication as Context)
}
}
}
}
}
private fun LocalRepository.needOldMessagesCleanUp() = getBoolean(CLEANUP_OLD_MESSAGES_NEEDED, true)
......
package chat.rocket.android.authentication.login.presentation
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.OauthHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.*
import chat.rocket.android.server.domain.GetConnectingServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SaveAccountInteractor
import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.casLoginUrl
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.gitlabUrl
import chat.rocket.android.server.domain.isCasAuthenticationEnabled
import chat.rocket.android.server.domain.isFacebookAuthenticationEnabled
import chat.rocket.android.server.domain.isGithubAuthenticationEnabled
import chat.rocket.android.server.domain.isGitlabAuthenticationEnabled
import chat.rocket.android.server.domain.isGoogleAuthenticationEnabled
import chat.rocket.android.server.domain.isLdapAuthenticationEnabled
import chat.rocket.android.server.domain.isLinkedinAuthenticationEnabled
import chat.rocket.android.server.domain.isLoginFormEnabled
import chat.rocket.android.server.domain.isPasswordResetEnabled
import chat.rocket.android.server.domain.isRegistrationEnabledForNewUsers
import chat.rocket.android.server.domain.isWordpressAuthenticationEnabled
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.domain.wordpressUrl
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
......@@ -15,11 +38,8 @@ import chat.rocket.android.util.extensions.encodeToBase64
import chat.rocket.android.util.extensions.generateRandomString
import chat.rocket.android.util.extensions.isEmail
import chat.rocket.android.util.extensions.parseColor
import chat.rocket.android.util.extensions.registerPushToken
import chat.rocket.android.util.extensions.samlUrl
import chat.rocket.android.util.extensions.serverLogoUrl
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.AuthenticationEvent
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatAuthException
import chat.rocket.common.RocketChatException
......@@ -60,9 +80,8 @@ class LoginPresenter @Inject constructor(
private val navigator: AuthenticationNavigator,
private val tokenRepository: TokenRepository,
private val localRepository: LocalRepository,
private val getAccountsInteractor: GetAccountsInteractor,
private val settingsInteractor: GetSettingsInteractor,
private val analyticsTrackingInteractor: AnalyticsTrackingInteractor,
private val analyticsManager: AnalyticsManager,
serverInteractor: GetConnectingServerInteractor,
private val saveCurrentServer: SaveCurrentServerInteractor,
private val saveAccountInteractor: SaveAccountInteractor,
......@@ -312,12 +331,10 @@ class LoginPresenter @Inject constructor(
)
localRepository.saveCurrentUser(currentServer, user)
saveCurrentServer.save(currentServer)
localRepository.save(LocalRepository.CURRENT_USERNAME_KEY, myself.username)
saveAccount(myself.username!!)
saveToken(token)
registerPushToken()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logLogin(loginMethod, true)
}
analyticsManager.logLogin(loginMethod, true)
if (loginType == TYPE_LOGIN_USER_EMAIL) {
view.saveSmartLockCredentials(usernameOrEmail, password)
}
......@@ -331,9 +348,7 @@ class LoginPresenter @Inject constructor(
navigator.toTwoFA(usernameOrEmail, password)
}
else -> {
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logLogin(loginMethod, false)
}
analyticsManager.logLogin(loginMethod, false)
exception.message?.let {
view.showMessage(it)
}.ifNull {
......@@ -472,12 +487,4 @@ class LoginPresenter @Inject constructor(
private fun saveToken(token: Token) {
tokenRepository.save(currentServer, token)
}
private suspend fun registerPushToken() {
localRepository.get(LocalRepository.KEY_PUSH_TOKEN)?.let {
client.registerPushToken(it, getAccountsInteractor.get(), factory)
}
// TODO: When the push token is null, at some point we should receive it with
// onTokenRefresh() on FirebaseTokenService, we need to confirm it.
}
}
\ No newline at end of file
......@@ -6,7 +6,6 @@ import android.content.Intent
import android.graphics.PorterDuff
import android.os.Build
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.text.style.ClickableSpan
import android.view.LayoutInflater
import android.view.View
......@@ -18,20 +17,30 @@ import android.widget.LinearLayout
import android.widget.ScrollView
import androidx.core.view.isVisible
import androidx.core.view.postDelayed
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import chat.rocket.android.authentication.login.presentation.LoginPresenter
import chat.rocket.android.authentication.login.presentation.LoginView
import chat.rocket.android.helper.*
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.*
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import chat.rocket.android.webview.sso.ui.INTENT_SSO_TOKEN
import chat.rocket.android.webview.sso.ui.ssoWebViewIntent
import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.TextHelper
import chat.rocket.android.helper.getCredentials
import chat.rocket.android.helper.hasCredentialsSupport
import chat.rocket.android.helper.requestStoredCredentials
import chat.rocket.android.helper.saveCredentials
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.shake
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.extensions.vibrateSmartPhone
import chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_SECRET
import chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_TOKEN
import chat.rocket.android.webview.oauth.ui.oauthWebViewIntent
import chat.rocket.android.webview.sso.ui.INTENT_SSO_TOKEN
import chat.rocket.android.webview.sso.ui.ssoWebViewIntent
import chat.rocket.common.util.ifNull
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_log_in.*
......@@ -49,7 +58,7 @@ class LoginFragment : Fragment(), LoginView {
@Inject
lateinit var presenter: LoginPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private var isOauthViewEnable = false
private var deepLinkInfo: LoginDeepLinkInfo? = null
......@@ -93,9 +102,7 @@ class LoginFragment : Fragment(), LoginView {
image_key.isVisible = false
}
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.Login)
}
analyticsManager.logScreenView(ScreenViewEvent.Login)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
......
package chat.rocket.android.authentication.loginoptions.presentation
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.authentication.login.presentation.*
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
......@@ -33,17 +35,17 @@ private const val SERVICE_NAME_LINKEDIN = "linkedin"
private const val SERVICE_NAME_GILAB = "gitlab"
class LoginOptionsPresenter @Inject constructor(
private val view: LoginOptionsView,
private val strategy: CancelStrategy,
private val factory: RocketChatClientFactory,
private val navigator: AuthenticationNavigator,
private val settingsInteractor: GetSettingsInteractor,
private val localRepository: LocalRepository,
private val saveCurrentServer: SaveCurrentServerInteractor,
private val saveAccountInteractor: SaveAccountInteractor,
private val getAccountsInteractor: GetAccountsInteractor,
private val tokenRepository: TokenRepository,
serverInteractor: GetConnectingServerInteractor
private val view: LoginOptionsView,
private val strategy: CancelStrategy,
private val factory: RocketChatClientFactory,
private val navigator: AuthenticationNavigator,
private val settingsInteractor: GetSettingsInteractor,
private val localRepository: LocalRepository,
private val saveCurrentServer: SaveCurrentServerInteractor,
private val saveAccountInteractor: SaveAccountInteractor,
private val analyticsManager: AnalyticsManager,
private val tokenRepository: TokenRepository,
serverInteractor: GetConnectingServerInteractor
) {
// TODO - we should validate the current server when opening the app, and have a nonnull get()
private var currentServer = serverInteractor.get()!!
......@@ -245,7 +247,11 @@ class LoginOptionsPresenter @Inject constructor(
saveCurrentServer.save(currentServer)
saveAccount(myself.username!!)
saveToken(token)
registerPushToken()
// TODO
// analyticsManager.logSignUp(
// AuthenticationEvent.AuthenticationWithOauth,
// true
// )
navigator.toChatList()
} else if (loginType == TYPE_LOGIN_OAUTH) {
navigator.toRegisterUsername(token.userId, token.authToken)
......@@ -284,14 +290,6 @@ class LoginOptionsPresenter @Inject constructor(
tokenRepository.save(currentServer, token)
}
private suspend fun registerPushToken() {
localRepository.get(LocalRepository.KEY_PUSH_TOKEN)?.let {
client.registerPushToken(it, getAccountsInteractor.get(), factory)
}
// TODO: When the push token is null, at some point we should receive it with
// onTokenRefresh() on FirebaseTokenService, we need to confirm it.
}
fun toCreateAccount() {
navigator.toCreateAccount()
}
......
package chat.rocket.android.authentication.registerusername.presentation
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetConnectingServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings
......@@ -17,10 +16,7 @@ import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.registerPushToken
import chat.rocket.android.util.extensions.serverLogoUrl
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.AuthenticationEvent
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.Token
......@@ -34,11 +30,9 @@ class RegisterUsernamePresenter @Inject constructor(
private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator,
private val tokenRepository: TokenRepository,
private val localRepository: LocalRepository,
private val factory: RocketChatClientFactory,
factory: RocketChatClientFactory,
private val saveAccountInteractor: SaveAccountInteractor,
private val getAccountsInteractor: GetAccountsInteractor,
private val analyticsTrackingInteractor: AnalyticsTrackingInteractor,
private val analyticsManager: AnalyticsManager,
serverInteractor: GetConnectingServerInteractor,
private val saveCurrentServer: SaveCurrentServerInteractor,
settingsInteractor: GetSettingsInteractor
......@@ -62,16 +56,14 @@ class RegisterUsernamePresenter @Inject constructor(
saveAccount(registeredUsername)
saveCurrentServer.save(currentServer)
tokenRepository.save(currentServer, Token(userId, authToken))
registerPushToken()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logSignUp(AuthenticationEvent.AuthenticationWithOauth, true)
}
analyticsManager.logSignUp(
AuthenticationEvent.AuthenticationWithOauth,
true
)
navigator.toChatList()
}
} catch (exception: RocketChatException) {
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logSignUp(AuthenticationEvent.AuthenticationWithOauth, false)
}
analyticsManager.logSignUp(AuthenticationEvent.AuthenticationWithOauth, false)
exception.message?.let {
view.showMessage(it)
}.ifNull {
......@@ -84,14 +76,6 @@ class RegisterUsernamePresenter @Inject constructor(
}
}
private suspend fun registerPushToken() {
localRepository.get(LocalRepository.KEY_PUSH_TOKEN)?.let {
client.registerPushToken(it, getAccountsInteractor.get(), factory)
}
// TODO: When the push token is null, at some point we should receive it with
// onTokenRefresh() on FirebaseTokenService, we need to confirm it.
}
private suspend fun saveAccount(username: String) {
val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it)
......
......@@ -3,17 +3,23 @@ package chat.rocket.android.authentication.registerusername.ui
import DrawableHelper
import android.os.Build
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.authentication.registerusername.presentation.RegisterUsernamePresenter
import chat.rocket.android.authentication.registerusername.presentation.RegisterUsernameView
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.*
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.shake
import chat.rocket.android.util.extensions.showKeyboard
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.extensions.vibrateSmartPhone
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_register_username.*
import javax.inject.Inject
......@@ -24,7 +30,7 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
@Inject
lateinit var presenter: RegisterUsernamePresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private lateinit var userId: String
private lateinit var authToken: String
......@@ -69,9 +75,7 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
setupOnClickListener()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.RegisterUsername)
}
analyticsManager.logScreenView(ScreenViewEvent.RegisterUsername)
}
override fun alertBlankUsername() {
......
......@@ -3,18 +3,24 @@ package chat.rocket.android.authentication.resetpassword.ui
import DrawableHelper
import android.os.Build
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.authentication.resetpassword.presentation.ResetPasswordPresenter
import chat.rocket.android.authentication.resetpassword.presentation.ResetPasswordView
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.*
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.shake
import chat.rocket.android.util.extensions.showKeyboard
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.extensions.vibrateSmartPhone
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_reset_password.*
import javax.inject.Inject
......@@ -25,7 +31,7 @@ class ResetPasswordFragment : Fragment(), ResetPasswordView {
@Inject
lateinit var presenter: ResetPasswordPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
......@@ -52,9 +58,7 @@ class ResetPasswordFragment : Fragment(), ResetPasswordView {
setupOnClickListener()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.ResetPassword)
}
analyticsManager.logScreenView(ScreenViewEvent.ResetPassword)
}
override fun alertBlankEmail() {
......
......@@ -3,7 +3,6 @@ package chat.rocket.android.authentication.server.ui
import android.app.AlertDialog
import android.net.Uri
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
......@@ -11,17 +10,25 @@ import android.view.ViewTreeObserver
import android.widget.AdapterView
import android.widget.ArrayAdapter
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import chat.rocket.android.BuildConfig
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import chat.rocket.android.authentication.server.presentation.ServerPresenter
import chat.rocket.android.authentication.server.presentation.ServerView
import chat.rocket.android.authentication.ui.AuthenticationActivity
import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.*
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import chat.rocket.android.util.extensions.hintContent
import chat.rocket.android.util.extensions.ifEmpty
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.sanitize
import chat.rocket.android.util.extensions.setLightStatusBar
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.common.util.ifNull
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.app_bar_chat_room.*
......@@ -35,10 +42,11 @@ class ServerFragment : Fragment(), ServerView {
@Inject
lateinit var presenter: ServerPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private var deepLinkInfo: LoginDeepLinkInfo? = null
private val layoutListener = ViewTreeObserver.OnGlobalLayoutListener {
text_server_url.isCursorVisible = KeyboardHelper.isSoftKeyboardShown(constraint_layout.rootView)
text_server_url.isCursorVisible =
KeyboardHelper.isSoftKeyboardShown(constraint_layout.rootView)
}
private var protocol = "https://"
private var ignoreChange = false
......@@ -50,7 +58,11 @@ class ServerFragment : Fragment(), ServerView {
deepLinkInfo = arguments?.getParcelable(DEEP_LINK_INFO)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? =
container?.inflate(R.layout.fragment_authentication_server)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
......@@ -65,45 +77,51 @@ class ServerFragment : Fragment(), ServerView {
presenter.deepLink(it)
}
spinner_server_protocol.adapter = ArrayAdapter<String>(activity,
android.R.layout.simple_dropdown_item_1line, arrayOf("https://", "http://"))
spinner_server_protocol.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when(position) {
0 -> {
protocol = "https://"
}
1 -> {
if (ignoreChange) {
protocol = "http://"
} else {
ui {
AlertDialog.Builder(it)
.setTitle(R.string.msg_warning)
.setMessage(R.string.msg_http_insecure)
.setPositiveButton(R.string.msg_proceed) { _, _ ->
protocol = "http://"
}
.setNegativeButton(R.string.msg_cancel) { _, _ ->
spinner_server_protocol.setSelection(0)
}
.setCancelable(false)
.create()
.show()
spinner_server_protocol.adapter = ArrayAdapter<String>(
activity,
android.R.layout.simple_dropdown_item_1line, arrayOf("https://", "http://")
)
spinner_server_protocol.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
when (position) {
0 -> {
protocol = "https://"
}
1 -> {
if (ignoreChange) {
protocol = "http://"
} else {
ui {
AlertDialog.Builder(it)
.setTitle(R.string.msg_warning)
.setMessage(R.string.msg_http_insecure)
.setPositiveButton(R.string.msg_proceed) { _, _ ->
protocol = "http://"
}
.setNegativeButton(R.string.msg_cancel) { _, _ ->
spinner_server_protocol.setSelection(0)
}
.setCancelable(false)
.create()
.show()
}
}
}
}
ignoreChange = false
}
}
ignoreChange = false
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.Server)
}
analyticsManager.logScreenView(ScreenViewEvent.Server)
}
private fun setupToobar() {
......@@ -121,7 +139,8 @@ class ServerFragment : Fragment(), ServerView {
constraint_layout.viewTreeObserver.removeOnGlobalLayoutListener(layoutListener)
}
override fun showInvalidServerUrlMessage() = showMessage(getString(R.string.msg_invalid_server_url))
override fun showInvalidServerUrlMessage() =
showMessage(getString(R.string.msg_invalid_server_url))
override fun showLoading() {
ui {
......@@ -157,7 +176,12 @@ class ServerFragment : Fragment(), ServerView {
ui {
hideLoading()
AlertDialog.Builder(it)
.setMessage(getString(R.string.msg_ver_not_recommended, BuildConfig.RECOMMENDED_SERVER_VERSION))
.setMessage(
getString(
R.string.msg_ver_not_recommended,
BuildConfig.RECOMMENDED_SERVER_VERSION
)
)
.setPositiveButton(R.string.msg_ok) { _, _ ->
performConnect()
}
......@@ -170,7 +194,12 @@ class ServerFragment : Fragment(), ServerView {
ui {
hideLoading()
AlertDialog.Builder(it)
.setMessage(getString(R.string.msg_ver_not_minimum, BuildConfig.REQUIRED_SERVER_VERSION))
.setMessage(
getString(
R.string.msg_ver_not_minimum,
BuildConfig.REQUIRED_SERVER_VERSION
)
)
.setPositiveButton(R.string.msg_ok, null)
.setOnDismissListener {
// reset the deeplink info, so the user can log to another server...
......@@ -197,7 +226,9 @@ class ServerFragment : Fragment(), ServerView {
override fun updateServerUrl(url: HttpUrl) {
if (activity != null && view != null) {
if (url.scheme() == "https") spinner_server_protocol.setSelection(0) else spinner_server_protocol.setSelection(1)
if (url.scheme() == "https") spinner_server_protocol.setSelection(0) else spinner_server_protocol.setSelection(
1
)
protocol = "${url.scheme()}://"
val serverUrl = url.toString().removePrefix("${url.scheme()}://")
......
package chat.rocket.android.authentication.signup.presentation
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetConnectingServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings
......@@ -17,15 +17,11 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.privacyPolicyUrl
import chat.rocket.android.util.extensions.registerPushToken
import chat.rocket.android.util.extensions.serverLogoUrl
import chat.rocket.android.util.extensions.termsOfServiceUrl
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.AuthenticationEvent
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.login
import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.signup
......@@ -39,14 +35,12 @@ class SignupPresenter @Inject constructor(
private val localRepository: LocalRepository,
private val serverInteractor: GetConnectingServerInteractor,
private val saveCurrentServerInteractor: SaveCurrentServerInteractor,
private val analyticsTrackingInteractor: AnalyticsTrackingInteractor,
private val analyticsManager: AnalyticsManager,
private val factory: RocketChatClientFactory,
private val saveAccountInteractor: SaveAccountInteractor,
private val getAccountsInteractor: GetAccountsInteractor,
settingsInteractor: GetSettingsInteractor
) {
private val currentServer = serverInteractor.get()!!
private val client: RocketChatClient = factory.create(currentServer)
private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!)
fun signup(name: String, username: String, password: String, email: String) {
......@@ -80,22 +74,17 @@ class SignupPresenter @Inject constructor(
saveCurrentServerInteractor.save(currentServer)
localRepository.save(LocalRepository.CURRENT_USERNAME_KEY, me.username)
saveAccount(me)
registerPushToken()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logSignUp(
AuthenticationEvent.AuthenticationWithUserAndPassword,
true
)
}
analyticsManager.logSignUp(
AuthenticationEvent.AuthenticationWithUserAndPassword,
true
)
view.saveSmartLockCredentials(username, password)
navigator.toChatList()
} catch (exception: RocketChatException) {
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logSignUp(
AuthenticationEvent.AuthenticationWithUserAndPassword,
false
)
}
analyticsManager.logSignUp(
AuthenticationEvent.AuthenticationWithUserAndPassword,
false
)
exception.message?.let {
view.showMessage(it)
}.ifNull {
......@@ -122,14 +111,6 @@ class SignupPresenter @Inject constructor(
}
}
private suspend fun registerPushToken() {
localRepository.get(LocalRepository.KEY_PUSH_TOKEN)?.let {
client.registerPushToken(it, getAccountsInteractor.get(), factory)
}
// TODO: When the push token is null, at some point we should receive it with
// onTokenRefresh() on FirebaseTokenService, we need to confirm it.
}
private suspend fun saveAccount(me: Myself) {
val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it)
......
......@@ -13,20 +13,19 @@ import android.view.ViewTreeObserver
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.R.string.message_credentials_saved_successfully
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.authentication.signup.presentation.SignupPresenter
import chat.rocket.android.authentication.signup.presentation.SignupView
import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.TextHelper
import chat.rocket.android.helper.saveCredentials
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.shake
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.extensions.vibrateSmartPhone
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_sign_up.*
import javax.inject.Inject
......@@ -38,7 +37,7 @@ class SignupFragment : Fragment(), SignupView {
@Inject
lateinit var presenter: SignupPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private val layoutListener = ViewTreeObserver.OnGlobalLayoutListener {
if (KeyboardHelper.isSoftKeyboardShown(constraint_layout.rootView)) {
text_new_user_agreement.setVisible(false)
......@@ -82,9 +81,7 @@ class SignupFragment : Fragment(), SignupView {
)
}
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.SignUp)
}
analyticsManager.logScreenView(ScreenViewEvent.SignUp)
}
override fun onDestroyView() {
......
package chat.rocket.android.authentication.twofactor.presentation
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.*
import chat.rocket.android.server.domain.GetConnectingServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SaveAccountInteractor
import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.registerPushToken
import chat.rocket.android.util.extensions.serverLogoUrl
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.AuthenticationEvent
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatAuthException
import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.login
import chat.rocket.core.internal.rest.me
import chat.rocket.core.model.Myself
......@@ -30,14 +35,12 @@ class TwoFAPresenter @Inject constructor(
private val localRepository: LocalRepository,
private val serverInteractor: GetConnectingServerInteractor,
private val saveCurrentServerInteractor: SaveCurrentServerInteractor,
private val analyticsTrackingInteractor: AnalyticsTrackingInteractor,
private val analyticsManager: AnalyticsManager,
private val factory: RocketChatClientFactory,
private val saveAccountInteractor: SaveAccountInteractor,
private val getAccountsInteractor: GetAccountsInteractor,
settingsInteractor: GetSettingsInteractor
) {
private val currentServer = serverInteractor.get()!!
private val client: RocketChatClient = factory.create(currentServer)
private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!)
// TODO: If the usernameOrEmail and password was informed by the user on the previous screen, then we should pass only the pin, like this: fun authenticate(pin: EditText)
......@@ -67,24 +70,20 @@ class TwoFAPresenter @Inject constructor(
saveAccount(me)
saveCurrentServerInteractor.save(currentServer)
tokenRepository.save(server, token)
registerPushToken()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logLogin(
AuthenticationEvent.AuthenticationWithUserAndPassword,
true
)
}
localRepository.save(LocalRepository.CURRENT_USERNAME_KEY, me.username)
analyticsManager.logLogin(
AuthenticationEvent.AuthenticationWithUserAndPassword,
true
)
navigator.toChatList()
} catch (exception: RocketChatException) {
if (exception is RocketChatAuthException) {
view.alertInvalidTwoFactorAuthenticationCode()
} else {
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logLogin(
AuthenticationEvent.AuthenticationWithUserAndPassword,
false
)
}
analyticsManager.logLogin(
AuthenticationEvent.AuthenticationWithUserAndPassword,
false
)
exception.message?.let {
view.showMessage(it)
}.ifNull {
......@@ -101,14 +100,6 @@ class TwoFAPresenter @Inject constructor(
fun signup() = navigator.toSignUp()
private suspend fun registerPushToken() {
localRepository.get(LocalRepository.KEY_PUSH_TOKEN)?.let {
client.registerPushToken(it, getAccountsInteractor.get(), factory)
}
// TODO: When the push token is null, at some point we should receive it with
// onTokenRefresh() on FirebaseTokenService, we need to confirm it.
}
private suspend fun saveAccount(me: Myself) {
val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it)
......
......@@ -10,9 +10,10 @@ import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.authentication.twofactor.presentation.TwoFAPresenter
import chat.rocket.android.authentication.twofactor.presentation.TwoFAView
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.shake
......@@ -20,8 +21,6 @@ import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.extensions.vibrateSmartPhone
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_two_fa.*
import javax.inject.Inject
......@@ -32,7 +31,7 @@ class TwoFAFragment : Fragment(), TwoFAView {
@Inject
lateinit var presenter: TwoFAPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
lateinit var username: String
lateinit var password: String
......@@ -66,9 +65,7 @@ class TwoFAFragment : Fragment(), TwoFAView {
setupOnClickListener()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.TwoFa)
}
analyticsManager.logScreenView(ScreenViewEvent.TwoFa)
}
override fun alertBlankTwoFactorAuthenticationCode() {
......
......@@ -9,15 +9,14 @@ import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.chatinformation.adapter.ReadReceiptAdapter
import chat.rocket.android.chatinformation.presentation.MessageInfoPresenter
import chat.rocket.android.chatinformation.presentation.MessageInfoView
import chat.rocket.android.chatinformation.viewmodel.ReadReceiptViewModel
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_message_info.*
import javax.inject.Inject
......@@ -37,7 +36,7 @@ class MessageInfoFragment : Fragment(), MessageInfoView {
@Inject
lateinit var presenter: MessageInfoPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private lateinit var adapter: ReadReceiptAdapter
private lateinit var messageId: String
......@@ -67,9 +66,7 @@ class MessageInfoFragment : Fragment(), MessageInfoView {
setupRecyclerView()
presenter.loadReadReceipts(messageId = messageId)
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.MessageInfo)
}
analyticsManager.logScreenView(ScreenViewEvent.MessageInfo)
}
private fun setupRecyclerView() {
......
......@@ -158,23 +158,36 @@ class ChatRoomAdapter(
}
fun prependData(dataSet: List<BaseUiModel<*>>) {
val item = dataSet.indexOfFirst { newItem ->
this.dataSet.indexOfFirst { it.messageId == newItem.messageId && it.viewType == newItem.viewType } > -1
}
if (item == -1) {
this.dataSet.addAll(0, dataSet)
notifyItemRangeInserted(0, dataSet.size)
} else {
dataSet.forEach { item ->
val index = this.dataSet.indexOfFirst {
item.messageId == it.messageId && item.viewType == it.viewType
}
if (index > -1) {
this.dataSet[index] = item
notifyItemChanged(index)
}
//---At first we will update all already saved elements with received updated ones
val filteredDataSet = dataSet.filter { newItem ->
val matchedIndex = this.dataSet.indexOfFirst { it.messageId == newItem.messageId && it.viewType == newItem.viewType }
if (matchedIndex > -1) {
this.dataSet[matchedIndex] = newItem
notifyItemChanged(matchedIndex)
}
return@filter (matchedIndex < 0)
}
val minAdditionDate = filteredDataSet.minBy { it.message.timestamp } ?: return
//---In the most cases we will just add new elements to the top of messages heap
if (this.dataSet.isEmpty() || minAdditionDate.message.timestamp > this.dataSet[0].message.timestamp) {
this.dataSet.addAll(0, filteredDataSet)
notifyItemRangeInserted(0, filteredDataSet.size)
return
}
//---Else branch: merging messages---
//---We are inserting new received elements into set. Sort them by time+type and show
if (filteredDataSet.isEmpty()) return
this.dataSet.addAll(0, filteredDataSet)
val tmp = this.dataSet.sortedWith(Comparator { t, t2 ->
val timeComparison = t.message.timestamp.compareTo(t2.message.timestamp)
if (timeComparison == 0) {
return@Comparator t.viewType.compareTo(t2.viewType)
}
timeComparison
}).reversed()
this.dataSet.clear()
this.dataSet.addAll(tmp)
notifyDataSetChanged()
}
fun updateItem(message: BaseUiModel<*>) {
......
......@@ -5,7 +5,6 @@ import android.app.job.JobService
import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.common.RocketChatException
import chat.rocket.core.internal.rest.sendMessage
import chat.rocket.core.model.Message
import dagger.android.AndroidInjection
......
......@@ -33,6 +33,8 @@ import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter
import chat.rocket.android.chatroom.adapter.PEOPLE
......@@ -60,7 +62,6 @@ import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.helper.ImageHelper
import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.MessageParser
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.circularRevealOrUnreveal
......@@ -72,8 +73,6 @@ import chat.rocket.android.util.extensions.rotateBy
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf
import chat.rocket.core.internal.realtime.socket.model.State
......@@ -148,7 +147,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
@Inject
lateinit var parser: MessageParser
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private lateinit var adapter: ChatRoomAdapter
internal lateinit var chatRoomId: String
private lateinit var chatRoomName: String
......@@ -219,8 +218,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
adapter = ChatRoomAdapter(chatRoomId, chatRoomType, chatRoomName, this,
reactionListener = this)
adapter = ChatRoomAdapter(chatRoomId, chatRoomType, chatRoomName, this, reactionListener = this)
}
override fun onCreateView(
......@@ -246,9 +244,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
it.showToolbarChatRoomIcon(chatRoomType)
}
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.ChatRoom)
}
analyticsManager.logScreenView(ScreenViewEvent.ChatRoom)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
......@@ -480,23 +476,18 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun showTypingStatus(usernameList: List<String>) {
ui {
when (usernameList.size) {
1 -> {
text_typing_status.text =
1 -> text_typing_status.text =
SpannableStringBuilder()
.bold { append(usernameList[0]) }
.append(getString(R.string.msg_is_typing))
}
2 -> {
text_typing_status.text =
2 -> text_typing_status.text =
SpannableStringBuilder()
.bold { append(usernameList[0]) }
.append(getString(R.string.msg_and))
.bold { append(usernameList[1]) }
.append(getString(R.string.msg_are_typing))
}
else -> {
text_typing_status.text = getString(R.string.msg_several_users_are_typing)
}
else -> text_typing_status.text = getString(R.string.msg_several_users_are_typing)
}
text_typing_status.isVisible = true
}
......@@ -720,16 +711,16 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
text_connection_status.text = getString(R.string.status_connected)
handler.postDelayed(dismissStatus, 2000)
}
is State.Disconnected -> text_connection_status.text =
getString(R.string.status_disconnected)
is State.Connecting -> text_connection_status.text =
getString(R.string.status_connecting)
is State.Authenticating -> text_connection_status.text =
getString(R.string.status_authenticating)
is State.Disconnecting -> text_connection_status.text =
getString(R.string.status_disconnecting)
is State.Waiting -> text_connection_status.text =
getString(R.string.status_waiting, state.seconds)
is State.Disconnected ->
text_connection_status.text = getString(R.string.status_disconnected)
is State.Connecting ->
text_connection_status.text = getString(R.string.status_connecting)
is State.Authenticating ->
text_connection_status.text = getString(R.string.status_authenticating)
is State.Disconnecting ->
text_connection_status.text = getString(R.string.status_disconnecting)
is State.Waiting ->
text_connection_status.text = getString(R.string.status_waiting, state.seconds)
}
}
}
......@@ -791,7 +782,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
activity?.supportFragmentManager?.registerFragmentLifecycleCallbacks(
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentAttached(fm: FragmentManager, f: Fragment, context: Context) {
override fun onFragmentAttached(
fm: FragmentManager,
f: Fragment,
context: Context
) {
if (f is MessageActionsBottomSheet) {
setReactionButtonIcon(R.drawable.ic_reaction_24dp)
emojiKeyboardPopup.dismiss()
......@@ -802,12 +797,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
)
subscribeComposeTextMessage()
emojiKeyboardPopup =
EmojiKeyboardPopup(activity!!, activity!!.findViewById(R.id.fragment_container))
emojiKeyboardPopup = EmojiKeyboardPopup(activity!!, activity!!.findViewById(R.id.fragment_container))
emojiKeyboardPopup.listener = this
text_message.listener = object : ComposerEditText.ComposerEditTextListener {
override fun onKeyboardOpened() {
}
override fun onKeyboardOpened() {}
override fun onKeyboardClosed() {
activity?.let {
......@@ -1005,7 +998,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
presenter.messageInfo(id)
}
override fun citeMessage(roomName: String, roomType: String, messageId: String, mentionAuthor: Boolean) {
override fun citeMessage(
roomName: String,
roomType: String,
messageId: String,
mentionAuthor: Boolean
) {
presenter.citeMessage(roomName, roomType, messageId, mentionAuthor)
}
......@@ -1037,10 +1035,15 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
ui {
val builder = AlertDialog.Builder(it)
builder.setTitle(it.getString(R.string.msg_delete_message))
.setMessage(it.getString(R.string.msg_delete_description))
.setPositiveButton(it.getString(R.string.msg_ok)) { _, _ -> presenter.deleteMessage(roomId, id) }
.setNegativeButton(it.getString(R.string.msg_cancel)) { _, _ -> }
.show()
.setMessage(it.getString(R.string.msg_delete_description))
.setPositiveButton(it.getString(R.string.msg_ok)) { _, _ ->
presenter.deleteMessage(
roomId,
id
)
}
.setNegativeButton(it.getString(R.string.msg_cancel)) { _, _ -> }
.show()
}
}
......
package chat.rocket.android.chatroom.ui
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import androidx.core.view.isVisible
import chat.rocket.android.emoji.internal.GlideApp
import chat.rocket.android.util.extensions.getFileName
import chat.rocket.android.util.extensions.getMimeType
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) {
activity?.let { fragmentActivity ->
uri.getMimeType(fragmentActivity).let { mimeType ->
imagePreview.isVisible = false
audioVideoAttachment.isVisible = false
textFile.isVisible = false
var bitmap: Bitmap? = null
activity?.let { context ->
uri.getMimeType(context).let { mimeType ->
description.text.clear()
when {
mimeType.startsWith("image") -> {
imagePreview.isVisible = true
imagePreview.setImageURI(uri)
}
mimeType.startsWith("video") -> {
audioVideoAttachment.isVisible = true
GlideApp
.with(context)
.asBitmap()
.load(uri)
.override(imagePreview.width, imagePreview.height)
.fitCenter()
.into(object : SimpleTarget<Bitmap>() {
override fun onResourceReady(
resource: Bitmap,
transition: Transition<in Bitmap>?
) {
bitmap = resource
imagePreview.setImageBitmap(resource)
imagePreview.isVisible = true
}
})
}
mimeType.startsWith("video") -> audioVideoAttachment.isVisible = true
else -> {
textFile.isVisible = true
textFile.text = uri.getFileName(fragmentActivity)
textFile.text = uri.getFileName(context)
}
}
}
}
sendButton.setOnClickListener {
presenter.uploadFile(chatRoomId, uri, (citation ?: "") + description.text.toString())
presenter.uploadFile(
chatRoomId,
uri,
(citation ?: "") + description.text.toString(),
bitmap
)
alertDialog.dismiss()
}
cancelButton.setOnClickListener { alertDialog.dismiss() }
......
......@@ -21,6 +21,8 @@ import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.chatrooms.adapter.RoomsAdapter
import chat.rocket.android.chatrooms.presentation.ChatRoomsPresenter
import chat.rocket.android.chatrooms.presentation.ChatRoomsView
......@@ -32,15 +34,12 @@ import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.helper.ChatRoomsSortOrder
import chat.rocket.android.helper.Constants
import chat.rocket.android.helper.SharedPreferenceHelper
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extension.onQueryTextListener
import chat.rocket.android.util.extensions.fadeIn
import chat.rocket.android.util.extensions.fadeOut
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import chat.rocket.android.widget.DividerItemDecoration
import chat.rocket.core.internal.realtime.socket.model.State
import dagger.android.support.AndroidSupportInjection
......@@ -60,7 +59,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
@Inject
lateinit var dbManager: DatabaseManager // TODO - remove when moving ChatRoom screen to DB
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
lateinit var viewModel: ChatRoomsViewModel
private var searchView: SearchView? = null
private var sortView: MenuItem? = null
......@@ -112,9 +111,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
setupToolbar()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.ChatRooms)
}
analyticsManager.logScreenView(ScreenViewEvent.ChatRooms)
}
private fun subscribeUi() {
......@@ -124,9 +121,13 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
}
recycler_view.layoutManager = LinearLayoutManager(it)
recycler_view.addItemDecoration(DividerItemDecoration(it,
recycler_view.addItemDecoration(
DividerItemDecoration(
it,
resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_start),
resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_end)))
resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_end)
)
)
recycler_view.itemAnimator = DefaultItemAnimator()
recycler_view.adapter = adapter
......@@ -141,7 +142,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
})
viewModel.loadingState.observe(viewLifecycleOwner, Observer { state ->
when(state) {
when (state) {
is LoadingState.Loading -> if (state.count == 0L) showLoading()
is LoadingState.Loaded -> {
hideLoading()
......@@ -195,29 +196,41 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
// TODO - simplify this
R.id.action_sort -> {
val dialogLayout = layoutInflater.inflate(R.layout.chatroom_sort_dialog, null)
val sortType = SharedPreferenceHelper.getInt(Constants.CHATROOM_SORT_TYPE_KEY, ChatRoomsSortOrder.ACTIVITY)
val groupByType = SharedPreferenceHelper.getBoolean(Constants.CHATROOM_GROUP_BY_TYPE_KEY, false)
val sortType = SharedPreferenceHelper.getInt(
Constants.CHATROOM_SORT_TYPE_KEY,
ChatRoomsSortOrder.ACTIVITY
)
val groupByType =
SharedPreferenceHelper.getBoolean(Constants.CHATROOM_GROUP_BY_TYPE_KEY, false)
val radioGroup = dialogLayout.findViewById<RadioGroup>(R.id.radio_group_sort)
val groupByTypeCheckBox = dialogLayout.findViewById<CheckBox>(R.id.checkbox_group_by_type)
val groupByTypeCheckBox =
dialogLayout.findViewById<CheckBox>(R.id.checkbox_group_by_type)
radioGroup.check(when (sortType) {
0 -> R.id.radio_sort_alphabetical
else -> R.id.radio_sort_activity
})
radioGroup.check(
when (sortType) {
0 -> R.id.radio_sort_alphabetical
else -> R.id.radio_sort_activity
}
)
radioGroup.setOnCheckedChangeListener { _, checkedId ->
run {
SharedPreferenceHelper.putInt(Constants.CHATROOM_SORT_TYPE_KEY, when (checkedId) {
R.id.radio_sort_alphabetical -> 0
R.id.radio_sort_activity -> 1
else -> 1
})
SharedPreferenceHelper.putInt(
Constants.CHATROOM_SORT_TYPE_KEY, when (checkedId) {
R.id.radio_sort_alphabetical -> 0
R.id.radio_sort_activity -> 1
else -> 1
}
)
}
}
groupByTypeCheckBox.isChecked = groupByType
groupByTypeCheckBox.setOnCheckedChangeListener { _, isChecked ->
SharedPreferenceHelper.putBoolean(Constants.CHATROOM_GROUP_BY_TYPE_KEY, isChecked)
SharedPreferenceHelper.putBoolean(
Constants.CHATROOM_GROUP_BY_TYPE_KEY,
isChecked
)
}
AlertDialog.Builder(context)
......@@ -234,10 +247,13 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
}
private fun updateSort() {
val sortType = SharedPreferenceHelper.getInt(Constants.CHATROOM_SORT_TYPE_KEY, ChatRoomsSortOrder.ACTIVITY)
val sortType = SharedPreferenceHelper.getInt(
Constants.CHATROOM_SORT_TYPE_KEY,
ChatRoomsSortOrder.ACTIVITY
)
val grouped = SharedPreferenceHelper.getBoolean(Constants.CHATROOM_GROUP_BY_TYPE_KEY, false)
val query = when(sortType) {
val query = when (sortType) {
ChatRoomsSortOrder.ALPHABETICAL -> {
Query.ByName(grouped)
}
......@@ -304,11 +320,16 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
text_connection_status.text = getString(R.string.status_connected)
handler.postDelayed(dismissStatus, 2000)
}
is State.Disconnected -> text_connection_status.text = getString(R.string.status_disconnected)
is State.Connecting -> text_connection_status.text = getString(R.string.status_connecting)
is State.Authenticating -> text_connection_status.text = getString(R.string.status_authenticating)
is State.Disconnecting -> text_connection_status.text = getString(R.string.status_disconnecting)
is State.Waiting -> text_connection_status.text = getString(R.string.status_waiting, state.seconds)
is State.Disconnected -> text_connection_status.text =
getString(R.string.status_disconnected)
is State.Connecting -> text_connection_status.text =
getString(R.string.status_connecting)
is State.Authenticating -> text_connection_status.text =
getString(R.string.status_authenticating)
is State.Disconnecting -> text_connection_status.text =
getString(R.string.status_disconnecting)
is State.Waiting -> text_connection_status.text =
getString(R.string.status_waiting, state.seconds)
}
}
}
......
......@@ -17,15 +17,15 @@ import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.realtime.socket.model.State
import chat.rocket.core.internal.rest.spotlight
import chat.rocket.core.model.SpotlightResult
import com.shopify.livedataktx.distinct
import com.shopify.livedataktx.map
import com.shopify.livedataktx.nonNull
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.isActive
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.newSingleThreadContext
import kotlinx.coroutines.experimental.withContext
import me.henrytao.livedataktx.distinct
import me.henrytao.livedataktx.map
import me.henrytao.livedataktx.nonNull
import timber.log.Timber
import java.security.InvalidParameterException
import kotlin.coroutines.experimental.coroutineContext
......
......@@ -15,18 +15,17 @@ import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.createchannel.presentation.CreateChannelPresenter
import chat.rocket.android.createchannel.presentation.CreateChannelView
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.members.adapter.MembersAdapter
import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf
import com.google.android.material.chip.Chip
......@@ -43,7 +42,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
@Inject
lateinit var createChannelPresenter: CreateChannelPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private var actionMode: ActionMode? = null
private val adapter: MembersAdapter = MembersAdapter {
if (it.username != null) {
......@@ -77,9 +76,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
setupRecyclerView()
subscribeEditTexts()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.CreateChannel)
}
analyticsManager.logScreenView(ScreenViewEvent.CreateChannel)
}
override fun onDestroyView() {
......
package chat.rocket.android.dagger
import android.app.Application
import chat.rocket.android.app.AppLifecycleObserver
import chat.rocket.android.app.RocketChatApplication
import chat.rocket.android.chatroom.service.MessageService
import chat.rocket.android.dagger.module.ActivityBuilder
import chat.rocket.android.dagger.module.AndroidWorkerInjectionModule
import chat.rocket.android.dagger.module.AppModule
import chat.rocket.android.dagger.module.ReceiverBuilder
import chat.rocket.android.dagger.module.ServiceBuilder
import chat.rocket.android.push.FirebaseTokenService
import dagger.BindsInstance
import dagger.Component
import dagger.android.support.AndroidSupportInjectionModule
......@@ -16,7 +15,8 @@ import javax.inject.Singleton
@Singleton
@Component(modules = [AndroidSupportInjectionModule::class,
AppModule::class, ActivityBuilder::class, ServiceBuilder::class, ReceiverBuilder::class])
AppModule::class, ActivityBuilder::class, ServiceBuilder::class, ReceiverBuilder::class,
AndroidWorkerInjectionModule::class])
interface AppComponent {
@Component.Builder
......@@ -29,10 +29,5 @@ interface AppComponent {
fun inject(app: RocketChatApplication)
fun inject(service: FirebaseTokenService)
fun inject(service: MessageService)
/*@Component.Builder
abstract class Builder : AndroidInjector.Builder<RocketChatApplication>()*/
}
package chat.rocket.android.dagger.injector
import androidx.work.Worker
object AndroidWorkerInjection {
fun inject(worker: Worker) {
val application = worker.applicationContext
if (application !is HasWorkerInjector) {
throw RuntimeException("${application.javaClass.canonicalName} does not implement ${HasWorkerInjector::class.java.canonicalName}")
}
val workerInjector = (application as HasWorkerInjector).workerInjector()
checkNotNull(workerInjector) { "${application.javaClass}.workerInjector() return null" }
workerInjector.inject(worker)
}
}
\ No newline at end of file
package chat.rocket.android.dagger.injector
import androidx.work.Worker
import dagger.android.AndroidInjector
interface HasWorkerInjector {
fun workerInjector(): AndroidInjector<Worker>
}
\ No newline at end of file
package chat.rocket.android.dagger.module
import chat.rocket.android.about.di.AboutFragmentProvider
import chat.rocket.android.authentication.di.AuthenticationModule
import chat.rocket.android.authentication.login.di.LoginFragmentProvider
import chat.rocket.android.authentication.loginoptions.di.LoginOptionsFragmentProvider
......@@ -62,6 +63,7 @@ abstract class ActivityBuilder {
CreateChannelProvider::class,
ProfileFragmentProvider::class,
SettingsFragmentProvider::class,
AboutFragmentProvider::class,
PreferencesFragmentProvider::class
]
)
......
package chat.rocket.android.dagger.module
import androidx.work.Worker
import dagger.Module
import dagger.android.AndroidInjector
import dagger.multibindings.Multibinds
@Module
abstract class AndroidWorkerInjectionModule {
@Multibinds
abstract fun workerInjectorFactories(): Map<Class<out Worker>, AndroidInjector.Factory<out Worker>>
}
\ No newline at end of file
......@@ -9,6 +9,10 @@ import android.content.Context
import android.content.SharedPreferences
import chat.rocket.android.BuildConfig
import chat.rocket.android.R
import chat.rocket.android.analytics.Analytics
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.AnswersAnalytics
import chat.rocket.android.analytics.GoogleAnalyticsForFirebase
import chat.rocket.android.authentication.infraestructure.SharedPreferencesMultiServerTokenRepository
import chat.rocket.android.authentication.infraestructure.SharedPreferencesTokenRepository
import chat.rocket.android.chatroom.service.MessageService
......@@ -23,10 +27,12 @@ import chat.rocket.android.push.GroupedPush
import chat.rocket.android.push.PushManager
import chat.rocket.android.server.domain.AccountsRepository
import chat.rocket.android.server.domain.ActiveUsersRepository
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.server.domain.AnalyticsTrackingRepository
import chat.rocket.android.server.domain.ChatRoomsRepository
import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.GetAccountInteractor
import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.JobSchedulerInteractor
......@@ -115,7 +121,10 @@ class AppModule {
@Provides
@Singleton
fun provideImagePipelineConfig(context: Context, okHttpClient: OkHttpClient): ImagePipelineConfig {
fun provideImagePipelineConfig(
context: Context,
okHttpClient: OkHttpClient
): ImagePipelineConfig {
val listeners = setOf(RequestLoggingListener())
return OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient)
......@@ -185,7 +194,10 @@ class AppModule {
@Provides
@Singleton
fun providePermissionsRepository(localRepository: LocalRepository, moshi: Moshi): PermissionsRepository {
fun providePermissionsRepository(
localRepository: LocalRepository,
moshi: Moshi
): PermissionsRepository {
return SharedPreferencesPermissionsRepository(localRepository, moshi)
}
......@@ -234,15 +246,20 @@ class AppModule {
@Provides
@Singleton
fun provideMultiServerTokenRepository(repository: LocalRepository, moshi: Moshi): MultiServerTokenRepository {
fun provideMultiServerTokenRepository(
repository: LocalRepository,
moshi: Moshi
): MultiServerTokenRepository {
return SharedPreferencesMultiServerTokenRepository(repository, moshi)
}
@Provides
@Singleton
fun provideMessageRepository(@ForMessages preferences: SharedPreferences,
moshi: Moshi,
currentServerInteractor: GetCurrentServerInteractor): MessagesRepository {
fun provideMessageRepository(
@ForMessages preferences: SharedPreferences,
moshi: Moshi,
currentServerInteractor: GetCurrentServerInteractor
): MessagesRepository {
return SharedPreferencesMessagesRepository(preferences, moshi, currentServerInteractor)
}
......@@ -257,10 +274,12 @@ class AppModule {
fun provideConfiguration(context: Application): SpannableConfiguration {
val res = context.resources
return SpannableConfiguration.builder(context)
.theme(SpannableTheme.builder()
.blockMargin(0)
.linkColor(res.getColor(R.color.colorAccent))
.build())
.theme(
SpannableTheme.builder()
.blockMargin(0)
.linkColor(res.getColor(R.color.colorAccent))
.build()
)
.build()
}
......@@ -277,7 +296,10 @@ class AppModule {
@Provides
@Singleton
fun provideAccountsRepository(preferences: SharedPreferences, moshi: Moshi): AccountsRepository =
fun provideAccountsRepository(
preferences: SharedPreferences,
moshi: Moshi
): AccountsRepository =
SharedPreferencesAccountsRepository(preferences, moshi)
@Provides
......@@ -296,8 +318,16 @@ class AppModule {
manager: NotificationManager,
moshi: Moshi,
getAccountInteractor: GetAccountInteractor,
getSettingsInteractor: GetSettingsInteractor): PushManager {
return PushManager(groupedPushes, manager, moshi, getAccountInteractor, getSettingsInteractor, context)
getSettingsInteractor: GetSettingsInteractor
): PushManager {
return PushManager(
groupedPushes,
manager,
moshi,
getAccountInteractor,
getSettingsInteractor,
context
)
}
@Provides
......@@ -307,14 +337,19 @@ class AppModule {
@Provides
fun provideSendMessageJob(context: Application): JobInfo {
return JobInfo.Builder(MessageService.RETRY_SEND_MESSAGE_ID,
ComponentName(context, MessageService::class.java))
return JobInfo.Builder(
MessageService.RETRY_SEND_MESSAGE_ID,
ComponentName(context, MessageService::class.java)
)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build()
}
@Provides
fun provideJobSchedulerInteractor(jobScheduler: JobScheduler, jobInfo: JobInfo): JobSchedulerInteractor {
fun provideJobSchedulerInteractor(
jobScheduler: JobScheduler,
jobInfo: JobInfo
): JobSchedulerInteractor {
return JobSchedulerInteractorImpl(jobScheduler, jobInfo)
}
......@@ -331,4 +366,33 @@ class AppModule {
): DatabaseManager {
return factory.create(currentServer)
}
@Provides
@Singleton
fun provideAnswersAnalytics(): AnswersAnalytics {
return AnswersAnalytics()
}
@Provides
@Singleton
fun provideGoogleAnalyticsForFirebase(context: Application): GoogleAnalyticsForFirebase {
return GoogleAnalyticsForFirebase(context)
}
@Provides
@Singleton
fun provideAnalyticsManager(
analyticsTrackingInteractor: AnalyticsTrackingInteractor,
getCurrentServerInteractor: GetCurrentServerInteractor,
getAccountsInteractor: GetAccountsInteractor,
answersAnalytics: AnswersAnalytics,
googleAnalyticsForFirebase: GoogleAnalyticsForFirebase
): AnalyticsManager {
return AnalyticsManager(
analyticsTrackingInteractor,
getCurrentServerInteractor,
getAccountsInteractor,
listOf(answersAnalytics, googleAnalyticsForFirebase)
)
}
}
package chat.rocket.android.dagger.qualifier
import androidx.work.Worker
import dagger.MapKey
import kotlin.reflect.KClass
@MapKey
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class WorkerKey(val value: KClass<out Worker>)
......@@ -10,18 +10,17 @@ import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.chatroom.uimodel.BaseUiModel
import chat.rocket.android.favoritemessages.presentation.FavoriteMessagesPresenter
import chat.rocket.android.favoritemessages.presentation.FavoriteMessagesView
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_favorite_messages.*
import javax.inject.Inject
......@@ -41,7 +40,7 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
@Inject
lateinit var presenter: FavoriteMessagesPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private lateinit var chatRoomId: String
private val adapter = ChatRoomAdapter(enableActions = false)
......@@ -68,9 +67,7 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
setupToolbar()
presenter.loadFavoriteMessages(chatRoomId)
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.FavoriteMessages)
}
analyticsManager.logScreenView(ScreenViewEvent.FavoriteMessages)
}
override fun showFavoriteMessages(favoriteMessages: List<BaseUiModel<*>>) {
......
......@@ -13,6 +13,8 @@ import androidx.recyclerview.widget.DividerItemDecoration.HORIZONTAL
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.files.adapter.FilesAdapter
import chat.rocket.android.files.presentation.FilesPresenter
......@@ -21,12 +23,9 @@ import chat.rocket.android.files.uimodel.FileUiModel
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.helper.ImageHelper
import chat.rocket.android.player.PlayerActivity
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_files.*
import javax.inject.Inject
......@@ -46,7 +45,7 @@ class FilesFragment : Fragment(), FilesView {
@Inject
lateinit var presenter: FilesPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private val adapter: FilesAdapter =
FilesAdapter { fileUiModel -> presenter.openFile(fileUiModel) }
private val linearLayoutManager = LinearLayoutManager(context)
......@@ -75,31 +74,30 @@ class FilesFragment : Fragment(), FilesView {
setupRecyclerView()
presenter.loadFiles(chatRoomId)
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.Files)
}
analyticsManager.logScreenView(ScreenViewEvent.Files)
}
override fun showFiles(dataSet: List<FileUiModel>, total: Long) {
setupToolbar(total)
if (adapter.itemCount == 0) {
adapter.prependData(dataSet)
if (dataSet.size >= 30) {
recycler_view.addOnScrollListener(object :
EndlessRecyclerViewScrollListener(linearLayoutManager) {
override fun onLoadMore(
page: Int,
totalItemsCount: Int,
recyclerView: RecyclerView
) {
presenter.loadFiles(chatRoomId)
}
})
ui {
setupToolbar(total)
if (adapter.itemCount == 0) {
adapter.prependData(dataSet)
if (dataSet.size >= 30) {
recycler_view.addOnScrollListener(object :
EndlessRecyclerViewScrollListener(linearLayoutManager) {
override fun onLoadMore(
page: Int,
totalItemsCount: Int,
recyclerView: RecyclerView
) {
presenter.loadFiles(chatRoomId)
}
})
}
group_no_file.isVisible = dataSet.isEmpty()
} else {
adapter.appendData(dataSet)
}
group_no_file.isVisible = dataSet.isEmpty()
} else {
adapter.appendData(dataSet)
}
}
......
......@@ -34,8 +34,8 @@ class FileUiModel(
}
private fun getUserDisplayName(): String {
val username = "@${genericAttachment.user?.username}"
val realName = genericAttachment.user?.name
val username = "@${genericAttachment.user.username}"
val realName = genericAttachment.user.name
val uploaderName = if (settings.useRealName()) realName else username
return uploaderName ?: username
}
......
......@@ -131,7 +131,7 @@ class MessageParser @Inject constructor(
private val builder: SpannableBuilder
) : SpannableMarkdownVisitor(configuration, builder) {
private val emojiSize = context.resources.getDimensionPixelSize(R.dimen.radius_mention)
private val emojiSize = context.resources.getDimensionPixelSize(R.dimen.custom_emoji_small)
override fun visit(document: Document) {
val spannable = EmojiParser.parse(context, builder.text())
......
......@@ -27,7 +27,6 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.adminPanelUrl
import chat.rocket.android.util.extensions.registerPushToken
import chat.rocket.android.util.extensions.serverLogoUrl
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatAuthException
......@@ -59,7 +58,7 @@ class MainPresenter @Inject constructor(
private val saveAccountInteractor: SaveAccountInteractor,
private val getAccountsInteractor: GetAccountsInteractor,
private val removeAccountInteractor: RemoveAccountInteractor,
private val factory: RocketChatClientFactory,
factory: RocketChatClientFactory,
private val groupedPush: GroupedPush,
dbManagerFactory: DatabaseManagerFactory,
getSettingsInteractor: GetSettingsInteractor,
......@@ -233,13 +232,6 @@ class MainPresenter @Inject constructor(
}
}
suspend fun refreshToken(token: String?) {
token?.let {
localRepository.save(LocalRepository.KEY_PUSH_TOKEN, token)
client.registerPushToken(token, getAccountsInteractor.get(), factory)
}
}
private suspend fun saveAccount(uiModel: NavHeaderUiModel) {
val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it)
......
......@@ -18,6 +18,7 @@ import chat.rocket.android.main.adapter.Selector
import chat.rocket.android.main.presentation.MainPresenter
import chat.rocket.android.main.presentation.MainView
import chat.rocket.android.main.uimodel.NavHeaderUiModel
import chat.rocket.android.push.refreshPushToken
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.ui.INTENT_CHAT_ROOM_ID
......@@ -26,7 +27,6 @@ import chat.rocket.android.util.extensions.fadeOut
import chat.rocket.android.util.extensions.rotateBy
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.invalidateFirebaseToken
import chat.rocket.android.util.refreshFCMToken
import chat.rocket.common.model.UserStatus
import dagger.android.AndroidInjection
import dagger.android.AndroidInjector
......@@ -36,9 +36,6 @@ import dagger.android.support.HasSupportFragmentInjector
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.nav_header.view.*
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.launch
import timber.log.Timber
import javax.inject.Inject
private const val CURRENT_STATE = "current_state"
......@@ -64,9 +61,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
launch(CommonPool) {
refreshFCMToken(presenter)
}
refreshPushToken()
chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID)
......
......@@ -2,6 +2,7 @@ package chat.rocket.android.members.di
import chat.rocket.android.members.ui.MembersFragment
import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.members.ui.MemberBottomSheetFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
......@@ -11,4 +12,9 @@ abstract class MembersFragmentProvider {
@ContributesAndroidInjector(modules = [MembersFragmentModule::class])
@PerFragment
abstract fun provideMembersFragment(): MembersFragment
@ContributesAndroidInjector()
@PerFragment
abstract fun provideMemberBottomSheetFragment(): MemberBottomSheetFragment
}
\ No newline at end of file
......@@ -6,12 +6,12 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import chat.rocket.android.R
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.util.extensions.content
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_member_bottom_sheet.*
import javax.inject.Inject
......@@ -43,7 +43,7 @@ private const val BUNDLE_UTC_OFFSET = "utc_offset"
class MemberBottomSheetFragment : BottomSheetDialogFragment() {
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private lateinit var avatarUri: String
private lateinit var realName: String
private lateinit var username: String
......@@ -52,6 +52,7 @@ class MemberBottomSheetFragment : BottomSheetDialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
val bundle = arguments
if (bundle != null) {
......@@ -76,9 +77,7 @@ class MemberBottomSheetFragment : BottomSheetDialogFragment() {
super.onViewCreated(view, savedInstanceState)
showMemberDetails()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.MemberBottomSheet)
}
analyticsManager.logScreenView(ScreenViewEvent.MemberBottomSheet)
}
private fun showMemberDetails() {
......
package chat.rocket.android.members.ui
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.members.adapter.MembersAdapter
import chat.rocket.android.members.presentation.MembersPresenter
import chat.rocket.android.members.presentation.MembersView
import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_members.*
import javax.inject.Inject
......@@ -41,7 +40,7 @@ class MembersFragment : Fragment(), MembersView {
@Inject
lateinit var presenter: MembersPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private val adapter: MembersAdapter =
MembersAdapter { memberUiModel -> presenter.toMemberDetails(memberUiModel) }
private val linearLayoutManager = LinearLayoutManager(context)
......@@ -70,9 +69,7 @@ class MembersFragment : Fragment(), MembersView {
setupRecyclerView()
presenter.loadChatRoomsMembers(chatRoomId)
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.Members)
}
analyticsManager.logScreenView(ScreenViewEvent.Members)
}
override fun showMembers(dataSet: List<MemberUiModel>, total: Long) {
......
......@@ -10,18 +10,17 @@ import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.chatroom.uimodel.BaseUiModel
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.mentions.presentention.MentionsPresenter
import chat.rocket.android.mentions.presentention.MentionsView
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_mentions.*
import javax.inject.Inject
......@@ -44,7 +43,7 @@ class MentionsFragment : Fragment(), MentionsView {
@Inject
lateinit var presenter: MentionsPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
......@@ -70,9 +69,7 @@ class MentionsFragment : Fragment(), MentionsView {
setupToolbar()
presenter.loadMentions(chatRoomId)
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.Mentions)
}
analyticsManager.logScreenView(ScreenViewEvent.Mentions)
}
override fun showMentions(mentions: List<BaseUiModel<*>>) {
......
......@@ -10,6 +10,8 @@ import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.chatroom.uimodel.BaseUiModel
......@@ -20,8 +22,6 @@ import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_pinned_messages.*
import javax.inject.Inject
......@@ -41,7 +41,7 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
@Inject
lateinit var presenter: PinnedMessagesPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private lateinit var chatRoomId: String
private val adapter = ChatRoomAdapter(enableActions = false)
......@@ -69,9 +69,7 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
setupToolbar()
presenter.loadPinnedMessages(chatRoomId)
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.PinnedMessages)
}
analyticsManager.logScreenView(ScreenViewEvent.PinnedMessages)
}
override fun showPinnedMessages(pinnedMessages: List<BaseUiModel<*>>) {
......
......@@ -7,12 +7,11 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import chat.rocket.android.BuildConfig
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.preferences.presentation.PreferencesPresenter
import chat.rocket.android.preferences.presentation.PreferencesView
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_preferences.*
......@@ -24,7 +23,7 @@ class PreferencesFragment : Fragment(), PreferencesView {
@Inject
lateinit var presenter: PreferencesPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
......@@ -43,17 +42,15 @@ class PreferencesFragment : Fragment(), PreferencesView {
setupListeners()
presenter.loadAnalyticsTrackingInformation()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.Preferences)
}
analyticsManager.logScreenView(ScreenViewEvent.Preferences)
}
override fun setupAnalyticsTrackingView(isAnalyticsTrackingEnabled: Boolean) {
if (BuildConfig.FLAVOR == "foss") {
text_analytics_tracking_description.text =
getString(R.string.msg_not_applicable_since_it_is_a_foss_version)
switch_analytics_tracking.isChecked = false
switch_analytics_tracking.isEnabled = false
text_analytics_tracking_description.text =
getString(R.string.msg_not_applicable_since_it_is_a_foss_version)
return
}
......
......@@ -17,10 +17,11 @@ import androidx.core.net.toUri
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.profile.presentation.ProfilePresenter
import chat.rocket.android.profile.presentation.ProfileView
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extension.dispatchImageSelection
import chat.rocket.android.util.extension.dispatchTakePicture
......@@ -28,8 +29,6 @@ import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import com.facebook.drawee.backends.pipeline.Fresco
import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
......@@ -48,7 +47,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
@Inject
lateinit var presenter: ProfilePresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private var currentName = ""
private var currentUsername = ""
private var currentEmail = ""
......@@ -81,9 +80,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
presenter.loadUserProfile()
subscribeEditTexts()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.Profile)
}
analyticsManager.logScreenView(ScreenViewEvent.Profile)
}
override fun onDestroyView() {
......
......@@ -4,7 +4,6 @@ import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.RemoteInput
import android.widget.Toast
import chat.rocket.android.R
......
......@@ -3,7 +3,7 @@ package chat.rocket.android.server.domain
import chat.rocket.android.server.domain.model.Account
interface AccountsRepository {
suspend fun save(account: Account)
suspend fun load(): List<Account>
suspend fun remove(serverUrl: String)
fun save(account: Account)
fun load(): List<Account>
fun remove(serverUrl: String)
}
\ No newline at end of file
......@@ -3,5 +3,5 @@ package chat.rocket.android.server.domain
import javax.inject.Inject
class GetAccountsInteractor @Inject constructor(val repository: AccountsRepository) {
suspend fun get() = repository.load()
fun get() = repository.load()
}
\ No newline at end of file
......@@ -72,4 +72,22 @@ interface MessagesRepository {
suspend fun getAllUnsent(): List<Message>
suspend fun getUnsentByRoomId(roomId: String): List<Message>
/**
* Save time of the latest room messages sync.
* Call this fun only when the latest messages list being received via /history or /messages network calls
*
* @param rid The id of the room the messages are.
* @param timeMillis time of room messages sync or the latest room message timestamp(which came with /history request)
*/
suspend fun saveLastSyncDate(rid: String, timeMillis: Long)
/**
* Get time when the room chat history has been loaded last time.
*
* @param rid The id of the room the messages are.
*
* @return Last Sync time or Null.
*/
suspend fun getLastSyncDate(rid: String): Long?
}
\ No newline at end of file
......@@ -7,8 +7,16 @@ import kotlinx.coroutines.experimental.withContext
class MemoryMessagesRepository : MessagesRepository {
private var lastSyncDates: HashMap<String, Long> = HashMap()
private val messages: HashMap<String, Message> = HashMap()
override suspend fun saveLastSyncDate(rid: String, timeMillis: Long) {
lastSyncDates[rid] = timeMillis
}
override suspend fun getLastSyncDate(rid: String) = lastSyncDates[rid]
override suspend fun getById(id: String): Message? = withContext(CommonPool) {
return@withContext messages[id]
}
......
......@@ -6,41 +6,37 @@ import chat.rocket.android.server.domain.AccountsRepository
import chat.rocket.android.server.domain.model.Account
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.withContext
private const val ACCOUNTS_KEY = "ACCOUNTS_KEY"
class SharedPreferencesAccountsRepository(
private val preferences: SharedPreferences,
private val moshi: Moshi
) : AccountsRepository {
override suspend fun save(newAccount: Account) {
withContext(CommonPool) {
val accounts = load()
override fun save(newAccount: Account) {
val accounts = load()
val newList = accounts.filter { account -> newAccount.serverUrl != account.serverUrl }
.toMutableList()
newList.add(0, newAccount)
save(newList)
}
val newList = accounts.filter { account -> newAccount.serverUrl != account.serverUrl }
.toMutableList()
newList.add(0, newAccount)
save(newList)
}
override suspend fun load(): List<Account> = withContext(CommonPool) {
override fun load(): List<Account> {
val json = preferences.getString(ACCOUNTS_KEY, "[]")
val type = Types.newParameterizedType(List::class.java, Account::class.java)
val adapter = moshi.adapter<List<Account>>(type)
adapter.fromJson(json) ?: emptyList()
return adapter.fromJson(json) ?: emptyList()
}
override suspend fun remove(serverUrl: String) {
withContext(CommonPool) {
val accounts = load()
override fun remove(serverUrl: String) {
val accounts = load()
val newList = accounts.filter { account -> serverUrl != account.serverUrl }
.toMutableList()
save(newList)
}
val newList = accounts.filter { account -> serverUrl != account.serverUrl }
.toMutableList()
save(newList)
}
private fun save(accounts: List<Account>) {
......@@ -50,6 +46,4 @@ class SharedPreferencesAccountsRepository(
putString(ACCOUNTS_KEY, adapter.toJson(accounts))
}
}
}
private const val ACCOUNTS_KEY = "ACCOUNTS_KEY"
\ No newline at end of file
}
\ No newline at end of file
......@@ -13,6 +13,27 @@ class SharedPreferencesMessagesRepository(
private val moshi: Moshi,
private val currentServerInteractor: GetCurrentServerInteractor
) : MessagesRepository {
private val KEY_LAST_SYNC_DATE = "KEY_LAST_SYNC_DATE"
override suspend fun saveLastSyncDate(rid: String, timeMillis: Long) {
withContext(CommonPool) {
currentServerInteractor.get()?.let {
prefs.edit().putLong(getSyncDateKey(it, rid), timeMillis).apply()
}
}
}
override suspend fun getLastSyncDate(rid: String): Long? = withContext(CommonPool) {
currentServerInteractor.get()?.also { server ->
if (!prefs.contains(getSyncDateKey(server, rid)))
return@withContext null
val time = prefs.getLong(getSyncDateKey(server, rid), -1)
return@withContext if (time == -1L) null else time
}
return@withContext null
}
private fun getSyncDateKey(server: String, rid: String) = "${KEY_LAST_SYNC_DATE}_$server $rid"
override suspend fun getById(id: String): Message? = withContext(CommonPool) {
currentServerInteractor.get()?.also { server ->
......
package chat.rocket.android.server.presentation
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.server.domain.GetAccountInteractor
import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
......@@ -11,7 +11,6 @@ import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.common.util.ifNull
import javax.inject.Inject
......@@ -23,7 +22,7 @@ class ChangeServerPresenter @Inject constructor(
private val getCurrentServerInteractor: GetCurrentServerInteractor,
private val getAccountInteractor: GetAccountInteractor,
private val getAccountsInteractor: GetAccountsInteractor,
private val analyticsTrackingInteractor: AnalyticsTrackingInteractor,
private val analyticsManager: AnalyticsManager,
private val settingsRepository: SettingsRepository,
private val tokenRepository: TokenRepository,
private val localRepository: LocalRepository,
......@@ -66,9 +65,7 @@ class ChangeServerPresenter @Inject constructor(
saveCurrentServerInteractor.save(serverUrl)
view.hideProgress()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logServerSwitch(serverUrl, accounts.size)
}
analyticsManager.logServerSwitch()
navigator.toChatRooms(chatRoomId)
}.ifNull {
view.hideProgress()
......
......@@ -27,7 +27,7 @@ class PasswordPresenter @Inject constructor(
val me = retryIO("me") { client.me() }
retryIO("updateProfile(${me.id})") {
client.updateProfile(me.id!!, null, null, password, null)
client.updateProfile(me.id, null, null, password, null)
}
view.showPasswordSuccessfullyUpdatedMessage()
......
......@@ -10,15 +10,14 @@ import android.widget.Toast
import androidx.appcompat.view.ActionMode
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.settings.password.presentation.PasswordPresenter
import chat.rocket.android.settings.password.presentation.PasswordView
import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
......@@ -32,7 +31,7 @@ class PasswordFragment : Fragment(), PasswordView, ActionMode.Callback {
@Inject
lateinit var presenter: PasswordPresenter
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
private var actionMode: ActionMode? = null
private val disposables = CompositeDisposable()
......@@ -56,9 +55,7 @@ class PasswordFragment : Fragment(), PasswordView, ActionMode.Callback {
disposables.add(listenToChanges())
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.Password)
}
analyticsManager.logScreenView(ScreenViewEvent.Password)
}
override fun onDestroyView() {
......
......@@ -11,16 +11,16 @@ import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.about.ui.AboutFragment
import chat.rocket.android.about.ui.TAG_ABOUT_FRAGMENT
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.preferences.ui.PreferencesFragment
import chat.rocket.android.preferences.ui.TAG_PREFERENCES_FRAGMENT
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.settings.password.ui.PasswordActivity
import chat.rocket.android.settings.presentation.SettingsView
import chat.rocket.android.util.extensions.addFragmentBackStack
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.helper.analytics.AnalyticsManager
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_settings.*
import javax.inject.Inject
import kotlin.reflect.KClass
......@@ -29,7 +29,12 @@ internal const val TAG_SETTINGS_FRAGMENT = "SettingsFragment"
class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListener {
@Inject
lateinit var analyticsTrackingInteractor: AnalyticsTrackingInteractor
lateinit var analyticsManager: AnalyticsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
}
override fun onCreateView(
inflater: LayoutInflater,
......@@ -41,10 +46,7 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen
super.onViewCreated(view, savedInstanceState)
setupToolbar()
setupListView()
if (analyticsTrackingInteractor.get()) {
AnalyticsManager.logScreenView(ScreenViewEvent.Settings)
}
analyticsManager.logScreenView(ScreenViewEvent.Settings)
}
override fun onResume() {
......
......@@ -7,18 +7,18 @@ import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.registerPushToken
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext
import timber.log.Timber
suspend fun RocketChatClient.registerPushToken(
suspend fun RocketChatClientFactory.registerPushToken(
token: String,
accounts: List<Account>,
factory: RocketChatClientFactory
accounts: List<Account>
) {
launch(CommonPool) {
withContext(CommonPool) {
accounts.forEach { account ->
try {
retryIO(description = "register push token: ${account.serverUrl}") {
factory.create(account.serverUrl).registerPushToken(token)
create(account.serverUrl).registerPushToken(token)
}
} catch (ex: Exception) {
Timber.d(ex, "Error registering Push token for ${account.serverUrl}")
......
......@@ -10,15 +10,19 @@ import android.provider.DocumentsContract
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.webkit.MimeTypeMap
import java.io.*
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
fun Uri.getFileName(context: Context): String? {
val cursor = context.contentResolver.query(this, null, null, null, null, null)
var fileName: String? = null
cursor.use { cursor ->
if (cursor != null && cursor.moveToFirst()) {
fileName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
cursor?.use {
if (it.moveToFirst()) {
fileName = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
}
}
return fileName
......@@ -29,7 +33,7 @@ fun Uri.getFileSize(context: Context): Int {
if (scheme == ContentResolver.SCHEME_CONTENT) {
try {
val fileInputStream = context.contentResolver.openInputStream(this)
fileSize = fileInputStream.available().toString()
fileSize = fileInputStream?.available().toString()
} catch (e: Exception) {
e.printStackTrace()
}
......@@ -67,14 +71,17 @@ fun Uri.isVirtualFile(context: Context): Boolean {
val cursor = context.contentResolver.query(
this,
arrayOf(DocumentsContract.Document.COLUMN_FLAGS),
null, null, null
null,
null,
null
)
var flags = 0
if (cursor.moveToFirst()) {
flags = cursor.getInt(0)
cursor?.use {
if (it.moveToFirst()) {
flags = it.getInt(0)
}
}
cursor.close()
return flags and DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT != 0
}
......@@ -104,4 +111,4 @@ fun Uri.getInputStream(context: Context): InputStream? {
fun Uri.getBitmpap(context: Context): Bitmap? {
return MediaStore.Images.Media.getBitmap(context.contentResolver, this)
}
}
\ No newline at end of file
......@@ -4,11 +4,8 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.CoroutineScope
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext
import kotlin.coroutines.experimental.CoroutineContext
class WrappedLiveData<Source, Output>(
......
......@@ -11,6 +11,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.ui
import kotlinx.android.synthetic.main.fragment_admin_panel_web_view.*
private const val BUNDLE_WEB_PAGE_URL = "web_page_url"
......@@ -58,8 +59,10 @@ class AdminPanelWebViewFragment : Fragment() {
web_view.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
view_loading.hide()
web_view.evaluateJavascript("Meteor.loginWithToken('$userToken', function() { })") {}
ui { _ ->
view_loading.hide()
web_view.evaluateJavascript("Meteor.loginWithToken('$userToken', function() { })") {}
}
}
}
web_view.loadUrl(webPageUrl)
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="#00000000"
android:fillType="evenOdd"
android:pathData="M11.286,6.143C11.286,7.087 11.136,7.797 10.838,8.273L16.354,13.615L17,15.709L15.708,17L13.62,16.358L13.21,15.949L13.21,14.474L11.735,14.474L11.105,13.844L11.105,12.368L9.629,12.368L8.063,10.796C7.481,11.123 6.84,11.286 6.143,11.286C4.7537,11.286 3.4234,10.7239 2.455,9.7277C1.4867,8.7314 0.9626,7.3858 1.002,5.997C1.077,3.313 3.314,1.077 5.997,1.002C7.3854,0.9628 8.7307,1.4869 9.7267,2.4551C10.7227,3.4232 11.2847,4.753 11.285,6.142L11.286,6.143Z"
android:strokeWidth="1.5"
android:strokeColor="#2F343D" />
<path
android:fillColor="#2F343D"
android:fillType="nonZero"
android:pathData="M5.5,5.5m1.5,0a1.5,1.5 0,1 0,-3 0a1.5,1.5 0,1 0,3 0"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
......@@ -8,32 +8,19 @@
android:translateX="281.28394"
android:translateY="271.51514">
<path
android:fillColor="#CC3333"
android:fillColor="#FFDB2323"
android:pathData="M491.3,255.3c0,-24.1 -7.2,-47.2 -21.4,-68.7c-12.8,-19.3 -30.7,-36.4 -53.2,-50.7c-43.5,-27.8 -100.6,-43.1 -160.9,-43.1c-20.1,0 -40,1.7 -59.2,5.1c-11.9,-11.2 -25.9,-21.2 -40.7,-29.2c-79,-38.3 -144.6,-0.9 -144.6,-0.9s60.9,50.1 51,93.9c-27.3,27 -42,59.6 -42,93.6c0,0.1 0,0.2 0,0.3c0,0.1 0,0.2 0,0.3c0,33.9 14.8,66.6 42,93.6c9.9,43.9 -51,93.9 -51,93.9s65.5,37.4 144.6,-0.9c14.8,-8 28.8,-18 40.7,-29.2c19.2,3.4 39.1,5.1 59.2,5.1c60.3,0 117.4,-15.3 160.9,-43.1c22.5,-14.4 40.4,-31.5 53.2,-50.7c14.2,-21.5 21.4,-44.6 21.4,-68.7c0,-0.1 0,-0.2 0,-0.3C491.3,255.6 491.3,255.4 491.3,255.3z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M255.9,124.2c113.9,0 206.3,59 206.3,131.8c0,72.8 -92.4,131.8 -206.3,131.8c-25.4,0 -49.7,-2.9 -72.1,-8.3c-22.8,27.4 -73,65.6 -121.7,53.3c15.9,-17 39.4,-45.8 34.3,-93.2c-29.2,-22.7 -46.8,-51.8 -46.8,-83.5C49.6,183.2 142,124.2 255.9,124.2" />
<path
android:fillColor="#CC3333"
android:fillColor="#FFDB2323"
android:pathData="M255.9,256m-27.4,0a27.4,27.4 0,1 1,54.8 0a27.4,27.4 0,1 1,-54.8 0" />
<path
android:fillColor="#CC3333"
android:fillColor="#FFDB2323"
android:pathData="M351.2,256m-27.4,0a27.4,27.4 0,1 1,54.8 0a27.4,27.4 0,1 1,-54.8 0" />
<path
android:fillColor="#CC3333"
android:fillColor="#FFDB2323"
android:pathData="M160.6,256m-27.4,0a27.4,27.4 0,1 1,54.8 0a27.4,27.4 0,1 1,-54.8 0" />
<path
android:fillColor="#CCCCCC"
android:pathData="M255.8,372.8c-25.4,0 -56.2,-4.9 -78.7,-9.5c-20.1,21 -53.7,52.7 -99.6,50.3c-5.7,8.6 -10.2,13.5 -15.5,19.2c48.7,12.3 98.9,-25.8 121.7,-53.3c22.4,5.4 46.7,8.3 72.1,8.3c113,0 204.8,-58.1 206.3,-130C460.7,320.1 368.8,372.8 255.8,372.8z" />
<path
android:fillColor="#00000000"
android:pathData="M172,350.9"
android:strokeColor="#000000"
android:strokeWidth="1" />
<path
android:fillColor="#00000000"
android:pathData="M200.4,422.9"
android:strokeColor="#000000"
android:strokeWidth="1" />
</group>
</vector>
</vector>
\ No newline at end of file
......@@ -770,4 +770,4 @@
android:pathData="M89.876,190C88.289,190.003 87.003,191.286 87,192.87C87.004,193.159 87.053,193.445 87.144,193.719C87.639,193.823 88.14,193.916 88.648,194C88.193,193.513 88.073,192.802 88.341,192.193C88.609,191.584 89.215,191.192 89.882,191.196L107.855,191.196C108.586,190.843 109.305,190.466 110,190.066C109.803,190.023 109.602,190.001 109.401,190L89.876,190Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
</vector>
\ No newline at end of file
......@@ -30,7 +30,7 @@
<TextView
android:id="@+id/text_on_boarding_description"
style="@style/Authentication.Description.TextView"
android:text="@string/msg_open_source_communication"
android:text="@string/msg_team_communication"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_on_boarding_title" />
......
<resources>
<!-- Titles -->
<string name="title_sign_in_your_server">Anmelden am Server</string>
<string name="title_log_in">Anmelden</string>
......@@ -75,7 +76,6 @@
<string name="msg_invalid_email">Bitte eine korrekte E-Mail Adresse eingeben</string>
<string name="msg_new_user_agreement">Beim weitergehen akzeptieren Sie usere\n%1$s und %2$s</string>
<string name="msg_2fa_code">2FA Code</string>
<!-- <string name="msg_more_than_ninety_nine_unread_messages" translatable="false">99+</string> -->
<string name="msg_yesterday">Gestern</string>
<string name="msg_today">Heute</string>
<string name="msg_message">Nachricht</string>
......@@ -109,11 +109,8 @@
<string name="msg_no_messages_yet">Noch keine Nachrichten</string>
<string name="msg_ok">OK</string>
<string name="msg_update_app_version_in_order_to_continue">Server Version veraltet. Bitte kontaktieren Sie ihren Server Administrator.</string>
<string name="msg_ver_not_recommended">
Die Server Version scheint älter als die empfolene Version %1$s zu sein.\nSie können sich trotzdem einloggen, aber es kann zu einem unerwartetem Verhalten kommen.</string>
<string name="msg_ver_not_minimum">
Die Server Version scheint älter als die minimale Version %1$s zu sein.\nBitte updaten Sie Ihren Server um sich einloggen zu können!
</string>
<string name="msg_ver_not_recommended">Die Server Version scheint älter als die empfolene Version %1$s zu sein.\nSie können sich trotzdem einloggen, aber es kann zu einem unerwartetem Verhalten kommen.</string>
<string name="msg_ver_not_minimum">Die Server Version scheint älter als die minimale Version %1$s zu sein.\nBitte updaten Sie Ihren Server um sich einloggen zu können!</string>
<string name="msg_no_chat_title">Keine Chat Nachrichten</string>
<string name="msg_no_chat_description">Starte die Konversation um Ihre \nNachrichten hier zu sehen.</string>
<string name="msg_proceed">WEITER</string>
......@@ -136,7 +133,7 @@
<string name="msg_send">Sende</string>
<string name="msg_sent_attachment">Sende Anhang</string>
<string name="msg_welcome_to_rocket_chat">Welcome to Rocket.Chat</string> <!-- TODO Add translation -->
<string name="msg_open_source_communication">Open Source Communication</string> <!-- TODO Add translation -->
<string name="msg_team_communication">Open Source Communication</string> <!-- TODO Add translation -->
<string name="msg_login_with_email">Login with e-mail</string> <!-- TODO Add translation -->
<string name="msg_create_account">Create an account</string> <!-- TODO Add translation -->
<string name="msg_continue_with_facebook">Continue with Facebook</string> <!-- TODO Add translation -->
......
......@@ -133,7 +133,7 @@
<string name="msg_delete_description">Seguro que quieres borrar este mensaje</string>
<string name="msg_no_search_found">No se han encontrado resultados</string>
<string name="msg_welcome_to_rocket_chat">Welcome to Rocket.Chat</string> <!-- TODO Add translation -->
<string name="msg_open_source_communication">Open Source Communication</string> <!-- TODO Add translation -->
<string name="msg_team_communication">Open Source Communication</string> <!-- TODO Add translation -->
<string name="msg_login_with_email">Login with e-mail</string> <!-- TODO Add translation -->
<string name="msg_create_account">Create an account</string> <!-- TODO Add translation -->
<string name="msg_continue_with_facebook">Continue with Facebook</string> <!-- TODO Add translation -->
......
This diff is collapsed.
......@@ -12,9 +12,9 @@
<string name="title_profile">प्रोफाइल</string>
<string name="title_members">सदस्य (%d)</string>
<string name="title_settings">सेटिंग्स</string>
<string name="title_preferences">Preferences</string> <!-- TODO Add translation -->
<string name="title_preferences">प्राथमिकताएँ</string>
<string name="title_change_password">पासवर्ड बदलें</string>
<string name="title_admin_panel">Admin panel</string> <!-- TODO Add translation -->
<string name="title_admin_panel">एडमिन पैनल</string>
<string name="title_password">पासवर्ड बदलें</string>
<string name="title_update_profile">प्रोफ़ाइल अपडेट करें</string>
<string name="title_about">परिचय</string>
......@@ -42,9 +42,9 @@
<string name="action_invisible">अदृश्य</string>
<string name="action_save_to_gallery">गैलरी में सहेजें</string>
<string name="action_drawing">चित्रकारी</string>
<string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_reset_avatar">Reset avatar</string> <!-- TODO Add translation -->
<string name="action_select_photo_from_gallery">गैलरी से फोटो का चयन करें</string>
<string name="action_take_photo">फोटो खेचिये</string>
<string name="action_reset_avatar">अवतार रीसेट करें</string>
<string name="action_connect_server">सर्वर से कनेक्ट करें</string>
<string name="action_join_community">समुदाय में शामिल हों</string>
<string name="action_create_server">नया सर्वर बनाएं</string>
......@@ -53,7 +53,7 @@
<!-- Settings List -->
<string-array name="settings_actions">
<item name="item_preferences">Preferences</item> <!-- TODO Add translation -->
<item name="item_preferences">प्राथमिकताएँ</item>
<item name="item_password">पासवर्ड बदलें</item>
<item name="item_password">परिचय</item>
</string-array>
......@@ -90,7 +90,7 @@
<string name="msg_content_description_log_in_using_meteor">Meteor द्वारा लॉगिन करें</string>
<string name="msg_content_description_log_in_using_twitter">Twitter द्वारा लॉगिन करें</string>
<string name="msg_content_description_log_in_using_gitlab">Gitlab द्वारा लॉगिन करें</string>
<string name="msg_content_description_log_in_using_wordpress">Login using WordPress</string> <!-- TODO Translate-->
<string name="msg_content_description_log_in_using_wordpress">WordPress द्वारा लॉगिन करें</string>
<string name="msg_content_description_send_message">मेसेज भेजें</string>
<string name="msg_content_description_show_attachment_options">अटैचमेंट विकल्प दिखाएं</string>
<string name="msg_you">आप</string>
......@@ -139,7 +139,7 @@
<string name="msg_delete_message">संदेश को हटाएं</string>
<string name="msg_delete_description">क्या आप निश्चित रूप से यह संदेश हटाना चाहते हैं</string>
<string name="msg_welcome_to_rocket_chat">Rocket.Chat में आपका स्वागत है</string>
<string name="msg_open_source_communication">ओपन सोर्स कम्युनिकेशन</string>
<string name="msg_team_communication">ओपन सोर्स कम्युनिकेशन</string>
<string name="msg_login_with_email">ई-मेल के साथ लॉगिन करें</string>
<string name="msg_create_account">खाता बनाएं</string>
<string name="msg_continue_with_facebook">Facebook के साथ जारी रखें</string>
......@@ -163,10 +163,10 @@
<string name="msg_channel_created_successfully">चैनल सफलतापूर्वक बनाया गया</string>
<!-- Preferences messages -->
<string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation -->
<string name="msg_send_analytics_tracking">Send anonymous statics to help improving this app</string> <!-- TODO Add translation -->
<string name="msg_do_not_send_analytics_tracking">Do not send anonymous statics to help improving this app</string> <!-- TODO Add translation -->
<string name="msg_not_applicable_since_it_is_a_foss_version">Not applicable since it is a FOSS version</string> <!-- TODO Add translation -->
<string name="msg_analytics_tracking">एनालिटिक्स ट्रैकिंग</string>
<string name="msg_send_analytics_tracking">इस ऐप को बेहतर बनाने में मदद के लिए अज्ञात स्टेटिक्स भेजें</string>
<string name="msg_do_not_send_analytics_tracking">इस ऐप को बेहतर बनाने में मदद के लिए अनाम स्टेटिक न भेजें</string>
<string name="msg_not_applicable_since_it_is_a_foss_version">लागू नहीं है क्योंकि यह एक FOSS संस्करण है</string>
<!-- System messages -->
<string name="message_room_name_changed">%2$s ने रूम का नाम बदलकर %1$s किया</string>
......@@ -206,8 +206,7 @@
<string name="permission_starring_not_allowed">तारांकित की अनुमति नहीं है</string>
<!-- Search message -->
<!-- TODO Add proper translation-->
<string name="title_search_message">Search message</string>
<string name="title_search_message">संदेश खोजें</string>
<!-- Favorite/Unfavorite chat room -->
<string name="title_favorite_chat">पसंदीदा चैट</string>
......@@ -286,7 +285,7 @@
<string name="dialog_sort_by_activity">गतिविधि</string>
<string name="dialog_group_by_type">प्रकार के आधार पर समूह</string>
<string name="dialog_group_favourites">पसंदीदा समूह</string>
<string name="dialog_button_done">Done</string><!-- TODO Add translation -->
<string name="dialog_button_done">पूर्ण</string>
<string name="chatroom_header">हैडर</string>
<!--ChatRooms Headers-->
......
This diff is collapsed.
......@@ -139,7 +139,7 @@
<string name="msg_delete_message">Delete Message</string>
<string name="msg_delete_description">Are you sure you want to delete this message</string>
<string name="msg_welcome_to_rocket_chat">Welcome to Rocket.Chat</string> <!-- TODO Add translation -->
<string name="msg_open_source_communication">Open Source Communication</string> <!-- TODO Add translation -->
<string name="msg_team_communication">Open Source Communication</string> <!-- TODO Add translation -->
<string name="msg_login_with_email">Login with e-mail</string> <!-- TODO Add translation -->
<string name="msg_create_account">Create an account</string> <!-- TODO Add translation -->
<string name="msg_continue_with_facebook">Continue with Facebook</string> <!-- TODO Add translation -->
......
......@@ -12,9 +12,9 @@
<string name="title_profile">Профиль</string>
<string name="title_members">Пользователи (%d)</string>
<string name="title_settings">Настройки</string>
<string name="title_preferences">Preferences</string> <!-- TODO Add translation -->
<string name="title_preferences">Персональные</string>
<string name="title_change_password">Изменить пароль</string>
<string name="title_admin_panel">Admin panel</string> <!-- TODO Add translation -->
<string name="title_admin_panel">Панель админа</string>
<string name="title_password">Изменить пароль</string>
<string name="title_update_profile">Обновить профиль</string>
<string name="title_about">О программе</string>
......@@ -53,7 +53,7 @@
<!-- Settings List -->
<string-array name="settings_actions">
<item name="item_preferences">Preferences</item> <!-- TODO Add translation -->
<item name="item_preferences">Персональные</item>
<item name="item_password">Изменить пароль</item>
<item name="item_password">О программе</item>
</string-array>
......@@ -136,7 +136,7 @@
<string name="msg_channel_name">Название канала</string>
<string name="msg_search">Поиск</string>
<string name="msg_welcome_to_rocket_chat">Welcome to Rocket.Chat</string> <!-- TODO Add translation -->
<string name="msg_open_source_communication">Open Source Communication</string> <!-- TODO Add translation -->
<string name="msg_team_communication">Open Source Communication</string> <!-- TODO Add translation -->
<string name="msg_login_with_email">Login with e-mail</string> <!-- TODO Add translation -->
<string name="msg_create_account">Create an account</string> <!-- TODO Add translation -->
<string name="msg_continue_with_facebook">Continue with Facebook</string> <!-- TODO Add translation -->
......@@ -160,10 +160,10 @@
<string name="msg_channel_created_successfully">Канал создан успешно</string>
<!-- Preferences messages -->
<string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation -->
<string name="msg_send_analytics_tracking">Send anonymous statics to help improving this app</string> <!-- TODO Add translation -->
<string name="msg_do_not_send_analytics_tracking">Do not send anonymous statics to help improving this app</string> <!-- TODO Add translation -->
<string name="msg_not_applicable_since_it_is_a_foss_version">Not applicable since it is a FOSS version</string> <!-- TODO Add translation -->
<string name="msg_analytics_tracking">Отслеживание Analytics</string>
<string name="msg_send_analytics_tracking">Отправлять анонимную статистику для улучшения приложения.</string>
<string name="msg_do_not_send_analytics_tracking">Не отправлять анонимную статистику для улучшения приложения</string>
<string name="msg_not_applicable_since_it_is_a_foss_version">Не применимо, так как это FOSS версия</string>
<!-- System messages -->
<string name="message_room_name_changed">%2$s изменил название канала на %1$s</string>
......
This diff is collapsed.
<!--
REMARK:
When adding a new string in this file do not forget to add a proper translation for the
corresponding supported language - if applicable.
Please, follow the rules as shown here (by adding a new string in the correct section).
Coding style:
https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strings
-->
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="app_name" translatable="false">Rocket.Chat</string>
......@@ -85,7 +96,6 @@
<string name="msg_invalid_2fa_code">Invalid 2FA Code</string>
<string name="msg_invalid_file">Invalid file</string>
<string name="msg_invalid_server_url">Invalid server URL</string>
<string name="msg_content_description_onboarding">Onboarding image</string>
<string name="msg_content_description_log_in_using_facebook">Login using Facebook</string>
<string name="msg_content_description_log_in_using_github">Login using Github</string>
<string name="msg_content_description_log_in_using_google">Login using Google</string>
......@@ -140,7 +150,7 @@
<string name="msg_send">Send</string>
<string name="msg_sent_attachment">Sent an attachment</string>
<string name="msg_welcome_to_rocket_chat">Welcome to Rocket.Chat</string>
<string name="msg_open_source_communication">Open Source Communication</string>
<string name="msg_team_communication">Team Communication</string>
<string name="msg_login_with_email">Login with e-mail</string>
<string name="msg_create_account">Create an account</string>
<string name="msg_continue_with_facebook">Continue with Facebook</string>
......
......@@ -2,14 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="chat.rocket.android">
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission
android:name="${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<application
android:name=".app.RocketChatApplication"
android:allowBackup="true"
......@@ -20,25 +12,6 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true">
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
<service
android:name=".push.FirebaseTokenService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name=".push.FirebaseMessagingService"
android:enabled="true"
......
package chat.rocket.android.util.helper.analytics
package chat.rocket.android.analytics
import chat.rocket.android.util.helper.analytics.event.AuthenticationEvent
import chat.rocket.android.util.helper.analytics.event.ScreenViewEvent
import chat.rocket.android.util.helper.analytics.event.SubscriptionTypeEvent
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.analytics.event.SubscriptionTypeEvent
import com.crashlytics.android.answers.Answers
import com.crashlytics.android.answers.CustomEvent
import com.crashlytics.android.answers.LoginEvent
import com.crashlytics.android.answers.SignUpEvent
// TODO inject the and analyticsTrackingInteractor and GetCurrentServerInteractor
object AnalyticsManager : Analytics {
class AnswersAnalytics : Analytics {
override fun logLogin(event: AuthenticationEvent, loginSucceeded: Boolean) =
Answers.getInstance()
......
package chat.rocket.android.analytics
import android.content.Context
import android.os.Bundle
import chat.rocket.android.analytics.event.AuthenticationEvent
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.analytics.event.SubscriptionTypeEvent
import com.google.firebase.analytics.FirebaseAnalytics
import javax.inject.Inject
class GoogleAnalyticsForFirebase @Inject constructor(val context: Context) :
Analytics {
private val firebaseAnalytics = FirebaseAnalytics.getInstance(context)
override fun logLogin(event: AuthenticationEvent, loginSucceeded: Boolean) {
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle(1).apply {
putString(FirebaseAnalytics.Param.METHOD, event.methodName)
putLong(FirebaseAnalytics.Param.SUCCESS, if (loginSucceeded) 1 else 0)
})
}
override fun logSignUp(event: AuthenticationEvent, signUpSucceeded: Boolean) {
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SIGN_UP, Bundle(1).apply {
putString(FirebaseAnalytics.Param.METHOD, event.methodName)
putLong(FirebaseAnalytics.Param.SUCCESS, if (signUpSucceeded) 1 else 0)
})
}
override fun logScreenView(event: ScreenViewEvent) {
firebaseAnalytics.logEvent("screen_view", Bundle(1).apply {
putString("screen", event.screenName)
})
}
override fun logMessageSent(event: SubscriptionTypeEvent, serverUrl: String) {
firebaseAnalytics.logEvent("message_sent", Bundle(1).apply {
putString("subscription_type", event.subscriptionTypeName)
putString("server", serverUrl)
})
}
override fun logMediaUploaded(event: SubscriptionTypeEvent, mimeType: String) {
firebaseAnalytics.logEvent("media_upload", Bundle(1).apply {
putString("subscription_type", event.subscriptionTypeName)
putString("media_type", mimeType)
})
}
override fun logReaction(event: SubscriptionTypeEvent) {
firebaseAnalytics.logEvent("reaction", Bundle(1).apply {
putString("subscription_type", event.subscriptionTypeName)
})
}
override fun logServerSwitch(serverUrl: String, serverCount: Int) {
firebaseAnalytics.logEvent("server_switch", Bundle(1).apply {
putString("server_url", serverUrl)
putInt("server_count", serverCount)
})
}
}
package chat.rocket.android.dagger.module
import androidx.work.Worker
import chat.rocket.android.chatroom.di.MessageServiceProvider
import chat.rocket.android.chatroom.service.MessageService
import chat.rocket.android.dagger.qualifier.WorkerKey
import chat.rocket.android.push.FirebaseMessagingService
import chat.rocket.android.push.FirebaseTokenService
import chat.rocket.android.push.di.FirebaseMessagingServiceProvider
import chat.rocket.android.push.di.FirebaseTokenServiceProvider
import chat.rocket.android.push.di.TokenRegistrationSubComponent
import chat.rocket.android.push.worker.TokenRegistrationWorker
import dagger.Binds
import dagger.Module
import dagger.android.AndroidInjector
import dagger.android.ContributesAndroidInjector
import dagger.multibindings.IntoMap
@Module abstract class ServiceBuilder {
@ContributesAndroidInjector(modules = [FirebaseTokenServiceProvider::class])
abstract fun bindFirebaseTokenService(): FirebaseTokenService
@Module(subcomponents = [TokenRegistrationSubComponent::class])
abstract class ServiceBuilder {
@ContributesAndroidInjector(modules = [FirebaseMessagingServiceProvider::class])
abstract fun bindGcmListenerService(): FirebaseMessagingService
@ContributesAndroidInjector(modules = [MessageServiceProvider::class])
abstract fun bindMessageService(): MessageService
@Binds
@IntoMap
@WorkerKey(TokenRegistrationWorker::class)
abstract fun bindTokenRegistrationWorkerFactory(
builder: TokenRegistrationSubComponent.Builder
): AndroidInjector.Factory<out Worker>
}
\ No newline at end of file
package chat.rocket.android.extensions
import com.google.android.gms.tasks.Task
import kotlin.coroutines.experimental.suspendCoroutine
@JvmName("awaitVoid")
suspend fun Task<Void>.await() = suspendCoroutine<Unit> { continuation ->
addOnSuccessListener { continuation.resume(Unit) }
addOnFailureListener { continuation.resumeWithException(it) }
}
suspend fun <TResult> Task<TResult>.await() = suspendCoroutine<TResult> { continuation ->
addOnSuccessListener { continuation.resume(it) }
addOnFailureListener { continuation.resumeWithException(it) }
}
\ No newline at end of file
package chat.rocket.android.push
import androidx.core.os.bundleOf
import androidx.work.Constraints
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.workDataOf
import chat.rocket.android.push.worker.TokenRegistrationWorker
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import dagger.android.AndroidInjection
......@@ -17,8 +23,22 @@ class FirebaseMessagingService : FirebaseMessagingService() {
}
override fun onMessageReceived(message: RemoteMessage) {
// XXX - for now this is ok, if we start to do network calls, use a Worker instead
message.data?.let {
pushManager.handle(bundleOf(*(it.map { Pair(it.key, it.value) }).toTypedArray()))
}
}
override fun onNewToken(token: String) {
val data = workDataOf("token" to token)
val constraint =
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
val work = OneTimeWorkRequestBuilder<TokenRegistrationWorker>()
.setInputData(data)
.setConstraints(constraint)
.build()
// Schedule a job since we are using network...
WorkManager.getInstance().enqueue(work)
}
}
\ No newline at end of file
package chat.rocket.android.push
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
import chat.rocket.core.internal.rest.registerPushToken
import com.google.firebase.iid.FirebaseInstanceId
import com.google.firebase.iid.FirebaseInstanceIdService
import dagger.android.AndroidInjection
import kotlinx.coroutines.experimental.launch
import timber.log.Timber
import javax.inject.Inject
class FirebaseTokenService : FirebaseInstanceIdService() {
@Inject
lateinit var factory: RocketChatClientFactory
@Inject
lateinit var getCurrentServerInteractor: GetCurrentServerInteractor
@Inject
lateinit var localRepository: LocalRepository
override fun onCreate() {
super.onCreate()
AndroidInjection.inject(this)
}
override fun onTokenRefresh() {
try {
val fcmToken = FirebaseInstanceId.getInstance().token
val currentServer = getCurrentServerInteractor.get()
val client = currentServer?.let { factory.create(currentServer) }
fcmToken?.let {
localRepository.save(LocalRepository.KEY_PUSH_TOKEN, fcmToken)
client?.let {
launch {
try {
Timber.d("Registering push token: $fcmToken for ${client.url}")
retryIO("register push token") { client.registerPushToken(fcmToken) }
} catch (ex: RocketChatException) {
Timber.e(ex, "Error registering push token")
}
}
}
}
} catch (ex: Exception) {
Timber.e(ex, "Error refreshing Firebase TOKEN")
}
}
}
\ No newline at end of file
package chat.rocket.android.push
import androidx.work.Constraints
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import chat.rocket.android.push.worker.TokenRegistrationWorker
fun refreshPushToken() {
val constraint =
Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
val work = OneTimeWorkRequestBuilder<TokenRegistrationWorker>()
.setConstraints(constraint)
.build()
// Schedule a job since we are using network...
WorkManager.getInstance().enqueue(work)
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment