From 9170d160fb011c4fbedd32c87163c88038ada11f Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Sun, 1 Sep 2019 16:52:29 -0300 Subject: [PATCH 01/19] Refactor push notification. --- app/build.gradle | 4 +- .../util/{GMSManager.kt => FCMManager.kt} | 2 +- app/src/main/AndroidManifest.xml | 9 - .../android/app/AppLifecycleObserver.kt | 9 +- .../presentation/OnBoardingPresenter.kt | 5 +- .../server/presentation/ServerPresenter.kt | 5 +- .../rocket/android/dagger/module/AppModule.kt | 6 +- .../android/dagger/module/ReceiverBuilder.kt | 5 - .../chat/rocket/android/db/DatabaseManager.kt | 22 +- .../android/infrastructure/LocalRepository.kt | 4 - .../main/presentation/MainPresenter.kt | 43 ++- .../rocket/android/main/ui/MainActivity.kt | 12 +- .../profile/presentation/ProfilePresenter.kt | 22 +- .../profile/presentation/ProfileView.kt | 3 +- .../android/profile/ui/ProfileFragment.kt | 11 +- .../android/push/DirectReplyReceiver.kt | 88 ----- .../push/DirectReplyReceiverProvider.kt | 11 - .../chat/rocket/android/push/GroupedPush.kt | 1 - .../java/chat/rocket/android/push/PushInfo.kt | 30 ++ .../chat/rocket/android/push/PushManager.kt | 342 +++++------------- .../chat/rocket/android/push/PushMessage.kt | 12 + .../chat/rocket/android/push/PushSender.kt | 12 + .../presentation/CheckServerPresenter.kt | 61 +--- .../android/server/presentation/TokenView.kt | 6 - .../presentation/SettingsPresenter.kt | 68 ++-- .../settings/presentation/SettingsView.kt | 3 +- .../android/settings/ui/SettingsFragment.kt | 4 - .../util/extensions/RocketChatClient.kt | 51 --- app/src/play/AndroidManifest.xml | 12 +- .../android/dagger/module/ServiceBuilder.kt | 20 +- .../android/push/FirebaseMessagingService.kt | 48 --- .../chat/rocket/android/push/PushToken.kt | 32 +- .../push/RocketChatMessagingService.kt | 25 ++ .../di/FirebaseMessagingServiceProvider.kt | 8 +- .../push/di/TokenRegistrationSubComponent.kt | 11 - .../push/worker/TokenRegistrationWorker.kt | 52 --- .../chat/rocket/android/util/FCMManager.kt | 9 + .../chat/rocket/android/util/GMSManager.kt | 8 - dependencies.gradle | 2 +- 39 files changed, 353 insertions(+), 725 deletions(-) rename app/src/foss/java/chat/rocket/android/util/{GMSManager.kt => FCMManager.kt} (58%) delete mode 100644 app/src/main/java/chat/rocket/android/push/DirectReplyReceiver.kt delete mode 100644 app/src/main/java/chat/rocket/android/push/DirectReplyReceiverProvider.kt create mode 100644 app/src/main/java/chat/rocket/android/push/PushInfo.kt create mode 100644 app/src/main/java/chat/rocket/android/push/PushMessage.kt create mode 100644 app/src/main/java/chat/rocket/android/push/PushSender.kt delete mode 100644 app/src/main/java/chat/rocket/android/server/presentation/TokenView.kt delete mode 100644 app/src/main/java/chat/rocket/android/util/extensions/RocketChatClient.kt delete mode 100644 app/src/play/java/chat/rocket/android/push/FirebaseMessagingService.kt create mode 100644 app/src/play/java/chat/rocket/android/push/RocketChatMessagingService.kt delete mode 100644 app/src/play/java/chat/rocket/android/push/di/TokenRegistrationSubComponent.kt delete mode 100644 app/src/play/java/chat/rocket/android/push/worker/TokenRegistrationWorker.kt create mode 100644 app/src/play/java/chat/rocket/android/util/FCMManager.kt delete mode 100644 app/src/play/java/chat/rocket/android/util/GMSManager.kt diff --git a/app/build.gradle b/app/build.gradle index 9bfe286740..d1f6656949 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { applicationId "chat.rocket.android" minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk - versionCode 2077 - versionName "3.5.1" + versionCode 2078 + versionName "3.5.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true diff --git a/app/src/foss/java/chat/rocket/android/util/GMSManager.kt b/app/src/foss/java/chat/rocket/android/util/FCMManager.kt similarity index 58% rename from app/src/foss/java/chat/rocket/android/util/GMSManager.kt rename to app/src/foss/java/chat/rocket/android/util/FCMManager.kt index 8346171417..16f7dd8677 100644 --- a/app/src/foss/java/chat/rocket/android/util/GMSManager.kt +++ b/app/src/foss/java/chat/rocket/android/util/FCMManager.kt @@ -1,5 +1,5 @@ package chat.rocket.android.util -fun invalidateFirebaseToken(token: String) { +fun invalidateFirebaseToken() { //Do absolutely nothing } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4aad7ac636..793d1472df 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -109,15 +109,6 @@ android:name=".settings.password.ui.PasswordActivity" android:theme="@style/AppTheme" /> - - - - - - > { - val messageEntity = message.toEntity() + val messageEntity = MessageEntity( + id = message.id, + roomId = message.roomId, + message = message.message, + timestamp = message.timestamp, + senderId = message.sender?.id, + updatedAt = message.updatedAt, + editedAt = message.editedAt, + editedBy = message.editedBy?.id, + senderAlias = message.senderAlias, + avatar = message.avatar, + type = message.type.asString(), + groupable = message.groupable, + parseUrls = message.parseUrls, + pinned = message.pinned, + role = message.role, + synced = message.synced + ) + val list = mutableListOf() createAttachments(message)?.let { list.addAll(it) } createFavoriteRelations(message)?.let { list.addAll(it) } diff --git a/app/src/main/java/chat/rocket/android/infrastructure/LocalRepository.kt b/app/src/main/java/chat/rocket/android/infrastructure/LocalRepository.kt index 2e178db56e..1340a1c781 100644 --- a/app/src/main/java/chat/rocket/android/infrastructure/LocalRepository.kt +++ b/app/src/main/java/chat/rocket/android/infrastructure/LocalRepository.kt @@ -22,7 +22,6 @@ interface LocalRepository { fun getLastChatroomsRefresh(url: String): Long companion object { - const val KEY_PUSH_TOKEN = "KEY_PUSH_TOKEN" const val TOKEN_KEY = "token_" const val SETTINGS_KEY = "settings_" const val PERMISSIONS_KEY = "permissions_" @@ -32,7 +31,4 @@ interface LocalRepository { const val LAST_CHATROOMS_REFRESH = "_chatrooms_refresh" } } - -// FIXME - we are saving the user full name here when the server is UI_Use_Real_Name true -fun LocalRepository.checkIfMyself(username: String) = username() == username fun LocalRepository.username() = get(LocalRepository.CURRENT_USERNAME_KEY) \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt b/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt index a7df0cba77..26c8889a5e 100644 --- a/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt +++ b/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt @@ -2,18 +2,35 @@ package chat.rocket.android.main.presentation import chat.rocket.android.authentication.domain.model.DeepLinkInfo import chat.rocket.android.core.behaviours.AppLanguageView +import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.helper.UserHelper import chat.rocket.android.push.GroupedPush -import chat.rocket.android.server.domain.* +import chat.rocket.android.server.domain.GetCurrentLanguageInteractor +import chat.rocket.android.server.domain.GetSettingsInteractor +import chat.rocket.android.server.domain.RefreshPermissionsInteractor +import chat.rocket.android.server.domain.RefreshSettingsInteractor +import chat.rocket.android.server.domain.RemoveAccountInteractor +import chat.rocket.android.server.domain.SaveAccountInteractor +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.siteName +import chat.rocket.android.server.domain.wideTile import chat.rocket.android.server.infrastructure.ConnectionManagerFactory +import chat.rocket.android.server.infrastructure.RocketChatClientFactory import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.serverLogoUrl +import chat.rocket.core.internal.rest.registerPushToken +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject import javax.inject.Named class MainPresenter @Inject constructor( @Named("currentServer") private val currentServer: String?, + private val strategy: CancelStrategy, private val mainNavigator: MainNavigator, private val appLanguageView: AppLanguageView, private val refreshSettingsInteractor: RefreshSettingsInteractor, @@ -25,7 +42,8 @@ class MainPresenter @Inject constructor( private val tokenRepository: TokenRepository, private val userHelper: UserHelper, private val saveAccountInteractor: SaveAccountInteractor, - private val removeAccountInteractor: RemoveAccountInteractor + private val removeAccountInteractor: RemoveAccountInteractor, + private val factory: RocketChatClientFactory ) { fun connect() = currentServer?.let { @@ -36,15 +54,11 @@ class MainPresenter @Inject constructor( fun clearNotificationsForChatRoom(chatRoomId: String?) { if (chatRoomId == null) return - groupedPush.hostToPushMessageList[currentServer].let { list -> list?.removeAll { it.info.roomId == chatRoomId } } } - fun showChatList(chatRoomId: String? = null, deepLinkInfo: DeepLinkInfo? = null) = - mainNavigator.toChatList(chatRoomId, deepLinkInfo) - fun getAppLanguage() { with(getLanguageInteractor) { getLanguage()?.let { language -> @@ -87,4 +101,21 @@ class MainPresenter @Inject constructor( } } } + + fun registerPushNotificationToken(token: String) { + GlobalScope.launch(Dispatchers.IO + strategy.jobs) { + try { + currentServer?.let { currentServer -> + factory.get(currentServer).registerPushToken(token) + Timber.d("Registered push notification token: $token") + } + } catch (exception: Exception) { + Timber.e("Unable to register push notification: $exception") + } + } + } + + fun showChatList(chatRoomId: String? = null, deepLinkInfo: DeepLinkInfo? = null) = + mainNavigator.toChatList(chatRoomId, deepLinkInfo) + } diff --git a/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt b/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt index 66390b8ed0..9cde3f8277 100644 --- a/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt +++ b/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt @@ -16,8 +16,9 @@ import chat.rocket.android.chatrooms.ui.ChatRoomsFragment import chat.rocket.android.chatrooms.ui.TAG_CHAT_ROOMS_FRAGMENT import chat.rocket.android.core.behaviours.AppLanguageView import chat.rocket.android.main.presentation.MainPresenter -import chat.rocket.android.push.refreshPushToken +import chat.rocket.android.push.retrieveCurrentPushToken import chat.rocket.android.server.ui.INTENT_CHAT_ROOM_ID +import chat.rocket.android.authentication.domain.model.DEEP_LINK_INFO_KEY import dagger.android.AndroidInjection import dagger.android.AndroidInjector import dagger.android.DispatchingAndroidInjector @@ -40,15 +41,14 @@ class MainActivity : AppCompatActivity(), HasActivityInjector, AndroidInjection.inject(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - refreshPushToken() - deepLinkInfo = - intent.getParcelableExtra(chat.rocket.android.authentication.domain.model.DEEP_LINK_INFO_KEY) + deepLinkInfo = intent.getParcelableExtra(DEEP_LINK_INFO_KEY) with(presenter) { connect() getAppLanguage() removeOldAccount() saveNewAccount() + retrieveCurrentPushToken()?.let { token -> registerPushNotificationToken(token) } intent.getStringExtra(INTENT_CHAT_ROOM_ID).let { clearNotificationsForChatRoom(it) showChatList(it, deepLinkInfo) @@ -58,9 +58,7 @@ class MainActivity : AppCompatActivity(), HasActivityInjector, override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) - intent?.getParcelableExtra( - chat.rocket.android.authentication.domain.model.DEEP_LINK_INFO_KEY - )?.let { deepLinkInfo -> + intent?.getParcelableExtra(DEEP_LINK_INFO_KEY)?.let { deepLinkInfo -> (supportFragmentManager.findFragmentByTag(TAG_CHAT_ROOMS_FRAGMENT) as? ChatRoomsFragment) ?.processDeepLink(deepLinkInfo) } diff --git a/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt b/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt index 3c4f561246..31a8b3a5ec 100644 --- a/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt +++ b/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt @@ -5,22 +5,17 @@ import android.net.Uri import chat.rocket.android.chatroom.domain.UriInteractor import chat.rocket.android.core.behaviours.showMessage import chat.rocket.android.core.lifecycle.CancelStrategy -import chat.rocket.android.db.DatabaseManagerFactory import chat.rocket.android.helper.UserHelper import chat.rocket.android.main.presentation.MainNavigator import chat.rocket.android.server.domain.GetCurrentServerInteractor -import chat.rocket.android.server.domain.RemoveAccountInteractor import chat.rocket.android.server.domain.TokenRepository -import chat.rocket.android.server.infrastructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory -import chat.rocket.android.server.presentation.CheckServerPresenter import chat.rocket.android.util.extension.compressImageAndGetByteArray import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.retryIO import chat.rocket.common.RocketChatException import chat.rocket.common.model.UserStatus -import chat.rocket.common.model.userStatusOf import chat.rocket.common.util.ifNull import chat.rocket.core.RocketChatClient import chat.rocket.core.internal.realtime.setDefaultStatus @@ -38,24 +33,9 @@ class ProfilePresenter @Inject constructor( private val navigator: MainNavigator, private val uriInteractor: UriInteractor, val userHelper: UserHelper, - @Named("currentServer") private val currentServer: String?, serverInteractor: GetCurrentServerInteractor, factory: RocketChatClientFactory, - removeAccountInteractor: RemoveAccountInteractor, - tokenRepository: TokenRepository, - dbManagerFactory: DatabaseManagerFactory?, - managerFactory: ConnectionManagerFactory -) : CheckServerPresenter( - strategy = strategy, - factory = factory, - currentSavedServer = currentServer, - serverInteractor = serverInteractor, - removeAccountInteractor = removeAccountInteractor, - tokenRepository = tokenRepository, - dbManagerFactory = dbManagerFactory, - managerFactory = managerFactory, - tokenView = view, - navigator = navigator + tokenRepository: TokenRepository ) { private val serverUrl = serverInteractor.get()!! private val client: RocketChatClient = factory.get(serverUrl) diff --git a/app/src/main/java/chat/rocket/android/profile/presentation/ProfileView.kt b/app/src/main/java/chat/rocket/android/profile/presentation/ProfileView.kt index 2c905810c6..1463964229 100644 --- a/app/src/main/java/chat/rocket/android/profile/presentation/ProfileView.kt +++ b/app/src/main/java/chat/rocket/android/profile/presentation/ProfileView.kt @@ -2,9 +2,8 @@ package chat.rocket.android.profile.presentation import chat.rocket.android.core.behaviours.LoadingView import chat.rocket.android.core.behaviours.MessageView -import chat.rocket.android.server.presentation.TokenView -interface ProfileView : TokenView, LoadingView, MessageView { +interface ProfileView : LoadingView, MessageView { /** * Shows the user profile. diff --git a/app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt b/app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt index 86525d8277..14f263a1b9 100644 --- a/app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt +++ b/app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt @@ -35,7 +35,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.invalidateFirebaseToken import chat.rocket.common.model.UserStatus import chat.rocket.common.model.userStatusOf import com.facebook.drawee.backends.pipeline.Fresco @@ -46,8 +45,6 @@ import io.reactivex.rxkotlin.Observables import kotlinx.android.synthetic.main.app_bar.* import kotlinx.android.synthetic.main.avatar_profile.* import kotlinx.android.synthetic.main.fragment_profile.* -import kotlinx.android.synthetic.main.fragment_profile.view_dim -import kotlinx.android.synthetic.main.fragment_profile.view_loading import kotlinx.android.synthetic.main.update_avatar_options.* import javax.inject.Inject @@ -149,15 +146,17 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { image_avatar?.setImageURI(avatarUrl) } - override fun onProfileUpdatedSuccessfully(updatedEmail: String, updatedName: String, updatedUserName: String) { + override fun onProfileUpdatedSuccessfully( + updatedEmail: String, + updatedName: String, + updatedUserName: String + ) { currentEmail = updatedEmail currentName = updatedName currentUsername = updatedUserName showMessage(getString(R.string.msg_profile_updated_successfully)) } - override fun invalidateToken(token: String) = invalidateFirebaseToken(token) - override fun showLoading() { enableUserInput(false) ui { view_loading.isVisible = true } diff --git a/app/src/main/java/chat/rocket/android/push/DirectReplyReceiver.kt b/app/src/main/java/chat/rocket/android/push/DirectReplyReceiver.kt deleted file mode 100644 index 00c4f694b0..0000000000 --- a/app/src/main/java/chat/rocket/android/push/DirectReplyReceiver.kt +++ /dev/null @@ -1,88 +0,0 @@ -package chat.rocket.android.push - -import android.app.NotificationManager -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.widget.Toast -import androidx.core.app.RemoteInput -import chat.rocket.android.R -import chat.rocket.android.server.infrastructure.ConnectionManagerFactory -import chat.rocket.common.RocketChatException -import chat.rocket.core.internal.rest.sendMessage -import dagger.android.AndroidInjection -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.launch -import timber.log.Timber -import java.util.* -import javax.inject.Inject - -/** - * BroadcastReceiver for direct reply on notifications. - */ -class DirectReplyReceiver : BroadcastReceiver() { - @Inject lateinit var factory: ConnectionManagerFactory - @Inject lateinit var groupedPushes: GroupedPush - @Inject lateinit var pushManager: PushManager - @Inject lateinit var manager: NotificationManager - - override fun onReceive(context: Context, intent: Intent) { - AndroidInjection.inject(this, context) - if (ACTION_REPLY == intent.action) { - val message = intent.getParcelableExtra(EXTRA_PUSH_MESSAGE) - message?.let { - MainScope().launch { - val notificationId = it.notificationId.toInt() - val hostname = it.info.host - try { - sendMessage(it, extractReplyMessage(intent)) - clearNotificationsByHostAndNotificationId(hostname, notificationId) - manager.cancel(notificationId) - val feedback = context.getString(R.string.notif_success_sending, it.title) - Toast.makeText(context, feedback, Toast.LENGTH_SHORT).show() - } catch (ex: RocketChatException) { - Timber.e(ex) - val feedback = context.getString(R.string.notif_error_sending) - Toast.makeText(context, feedback, Toast.LENGTH_SHORT).show() - clearNotificationsByHostAndNotificationId(hostname, notificationId) - pushManager.showNotification(it) - } - } - } - } - } - - private suspend fun sendMessage(message: PushMessage, replyText: CharSequence?) { - replyText?.let { reply -> - val currentServer = message.info.hostname - val roomId = message.info.roomId - val connectionManager = factory.create(currentServer) - val client = connectionManager?.client - val id = UUID.randomUUID().toString() - client?.sendMessage(id, roomId, reply.toString()) - // Do we need to disconnect here? - } - } - - private fun extractReplyMessage(intent: Intent): CharSequence? { - val bundle = RemoteInput.getResultsFromIntent(intent) - if (bundle != null) { - return bundle.getCharSequence(REMOTE_INPUT_REPLY) - } - return null - } - - /** - * Clear notifications by the host they belong to and its unique id. - */ - private fun clearNotificationsByHostAndNotificationId(host: String, notificationId: Int) { - if (groupedPushes.hostToPushMessageList.isNotEmpty()) { - val notifications = groupedPushes.hostToPushMessageList[host] - notifications?.let { - notifications.removeAll { - it.notificationId.toInt() == notificationId - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/push/DirectReplyReceiverProvider.kt b/app/src/main/java/chat/rocket/android/push/DirectReplyReceiverProvider.kt deleted file mode 100644 index 28a201fc08..0000000000 --- a/app/src/main/java/chat/rocket/android/push/DirectReplyReceiverProvider.kt +++ /dev/null @@ -1,11 +0,0 @@ -package chat.rocket.android.push - -import chat.rocket.android.dagger.module.AppModule -import dagger.Module -import dagger.android.ContributesAndroidInjector - -@Module -abstract class DirectReplyReceiverProvider { - @ContributesAndroidInjector(modules = [AppModule::class]) - abstract fun provideDirectReplyReceiver(): DirectReplyReceiver -} \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/push/GroupedPush.kt b/app/src/main/java/chat/rocket/android/push/GroupedPush.kt index d52f381292..cd4a1225a3 100644 --- a/app/src/main/java/chat/rocket/android/push/GroupedPush.kt +++ b/app/src/main/java/chat/rocket/android/push/GroupedPush.kt @@ -1,7 +1,6 @@ package chat.rocket.android.push import java.util.concurrent.atomic.AtomicInteger -import javax.inject.Singleton typealias TupleGroupIdMessageCount = Pair diff --git a/app/src/main/java/chat/rocket/android/push/PushInfo.kt b/app/src/main/java/chat/rocket/android/push/PushInfo.kt new file mode 100644 index 0000000000..2f9d87c111 --- /dev/null +++ b/app/src/main/java/chat/rocket/android/push/PushInfo.kt @@ -0,0 +1,30 @@ +package chat.rocket.android.push + +import chat.rocket.common.model.RoomType +import com.squareup.moshi.Json +import se.ansman.kotshi.JsonSerializable +import se.ansman.kotshi.KotshiConstructor + +@JsonSerializable +data class PushInfo @KotshiConstructor constructor( + @Json(name = "host") val hostname: String, + @Json(name = "rid") val roomId: String, + val type: RoomType, + val name: String?, + val sender: PushSender? +) { + val createdAt: Long + get() = System.currentTimeMillis() + val host by lazy { + sanitizeUrl(hostname) + } + + private fun sanitizeUrl(baseUrl: String): String { + var url = baseUrl.trim() + while (url.endsWith('/')) { + url = url.dropLast(1) + } + + return url + } +} diff --git a/app/src/main/java/chat/rocket/android/push/PushManager.kt b/app/src/main/java/chat/rocket/android/push/PushManager.kt index efd3b84e6c..24d535e98d 100644 --- a/app/src/main/java/chat/rocket/android/push/PushManager.kt +++ b/app/src/main/java/chat/rocket/android/push/PushManager.kt @@ -10,50 +10,62 @@ import android.content.Intent import android.media.RingtoneManager import android.os.Build import android.os.Bundle -import android.os.Parcel -import android.os.Parcelable import android.text.Html import android.text.Spanned import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat -import androidx.core.app.RemoteInput import androidx.core.content.ContextCompat import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY import chat.rocket.android.R -import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.server.domain.GetAccountInteractor import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.siteName +import chat.rocket.android.server.infrastructure.RocketChatClientFactory import chat.rocket.android.server.ui.changeServerIntent import chat.rocket.common.model.RoomType import chat.rocket.common.model.roomTypeOf -import com.squareup.moshi.Json +import chat.rocket.core.internal.rest.registerPushToken import com.squareup.moshi.Moshi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking -import se.ansman.kotshi.JsonSerializable -import se.ansman.kotshi.KotshiConstructor import timber.log.Timber import java.util.* import java.util.concurrent.atomic.AtomicInteger import javax.inject.Inject +import javax.inject.Named class PushManager @Inject constructor( private val groupedPushes: GroupedPush, - private val manager: NotificationManager, + private val notificationManager: NotificationManager, private val moshi: Moshi, private val getAccountInteractor: GetAccountInteractor, private val getSettingsInteractor: GetSettingsInteractor, - private val context: Context + private val context: Context, + @Named("currentServer") private val currentServer: String? ) { - + @Inject lateinit var factory: RocketChatClientFactory private val random = Random() + fun registerPushNotificationToken(token: String) { + GlobalScope.launch(Dispatchers.IO) { + try { + currentServer?.let { + factory.get(it).registerPushToken(token) + Timber.d("Registered push notification token: $token") + } + } catch (exception: Exception) { + Timber.e("Unable to register push notification: $exception") + } + } + } + /** * Handles a receiving push by creating and displaying an appropriate notification based * on the *data* param bundle received. */ - @Synchronized fun handle(data: Bundle) = runBlocking { val message = data["message"] as String? val ejson = data["ejson"] as String? @@ -65,64 +77,76 @@ class PushManager @Inject constructor( val count = data["count"] as String? try { - val adapter = moshi.adapter(PushInfo::class.java) - - val pushMessage = if (ejson != null) { - val info = adapter.fromJson(ejson) - PushMessage(title!!, message!!, info!!, image, count, notId, summaryText, style) - } else { - PushMessage(title!!, message!!, PushInfo.EMPTY, image, count, notId, summaryText, style) + if (title != null && message != null) { + val pushInfo = if (ejson != null) { + moshi.adapter(PushInfo::class.java).fromJson(ejson) + } else { + null + } + val pushMessage = PushMessage( + title = title, + message = message, + info = pushInfo ?: PushInfo( + hostname = "", + roomId = "", + type = roomTypeOf(RoomType.CHANNEL), + name = "", + sender = null + ), + image = image, + count = count, + notificationId = notId, + summaryText = summaryText, + style = style + ) + showNotification(pushMessage) + Timber.d("Received push message: $pushMessage") } - - Timber.d("Received push message: $pushMessage") - - showNotification(pushMessage) } catch (ex: Exception) { - Timber.e(ex, "Error parsing PUSH message: $data") - ex.printStackTrace() + Timber.e(ex, "Error parsing push message: $data") } } @SuppressLint("NewApi") - suspend fun showNotification(pushMessage: PushMessage) { + fun showNotification(pushMessage: PushMessage) { val notId = pushMessage.notificationId.toInt() val host = pushMessage.info.host - if (!hasAccount(host)) { - createSingleNotification(pushMessage)?.let { - NotificationManagerCompat.from(context).notify(notId, it) + createSingleNotification(pushMessage)?.let { notification -> + NotificationManagerCompat.from(context).notify(notId, notification) + if (!hasAccount(host)) { + Timber.d("Test or generic Push message: $pushMessage sent") + return } - Timber.d("ignoring push message: $pushMessage (maybe a test notification?)") - return } - val groupTuple = getGroupForHost(host) + val groupTuple = getGroupForHost(host) groupTuple.second.incrementAndGet() - val notIdListForHostname: MutableList? = groupedPushes.hostToPushMessageList[host] + val notIdListForHostname: MutableList? = + groupedPushes.hostToPushMessageList[host] if (notIdListForHostname == null) { groupedPushes.hostToPushMessageList[host] = arrayListOf(pushMessage) } else { notIdListForHostname.add(0, pushMessage) } - val notification = createSingleNotification(pushMessage) val pushMessageList = groupedPushes.hostToPushMessageList[host] - - notification?.let { - manager.notify(notId, it) - } - pushMessageList?.let { if (pushMessageList.size > 1) { val groupNotification = createGroupNotification(pushMessage) groupNotification?.let { - NotificationManagerCompat.from(context).notify(groupTuple.first, groupNotification) + NotificationManagerCompat.from(context) + .notify(groupTuple.first, groupNotification) } } } } + private fun hasAccount(host: String): Boolean { + return getAccountInteractor.get(host) != null + } + private fun getGroupForHost(host: String): TupleGroupIdMessageCount { val size = groupedPushes.groupMap.size var group = groupedPushes.groupMap[host] @@ -133,10 +157,6 @@ class PushManager @Inject constructor( return group } - private suspend fun hasAccount(host: String): Boolean { - return getAccountInteractor.get(host) != null - } - @SuppressLint("NewApi") @RequiresApi(Build.VERSION_CODES.N) private fun createGroupNotification(pushMessage: PushMessage): Notification? { @@ -183,11 +203,10 @@ class PushManager @Inject constructor( with(pushMessage) { val host = info.host - val builder = createBaseNotificationBuilder(pushMessage) - .setGroupSummary(false) + val builder = createBaseNotificationBuilder(pushMessage).setGroupSummary(false) if (style == null || "inbox" == style) { - val pushMessageList = groupedPushes.hostToPushMessageList.get(host) + val pushMessageList = groupedPushes.hostToPushMessageList[host] if (pushMessageList != null) { val userMessages = pushMessageList.filter { @@ -221,17 +240,19 @@ class PushManager @Inject constructor( return builder.build() } } else { - val bigTextStyle = NotificationCompat.BigTextStyle() - .bigText(message.fromHtml()) + val bigTextStyle = NotificationCompat.BigTextStyle().bigText(message.fromHtml()) builder.setStyle(bigTextStyle) } - return builder.addReplyAction(pushMessage).build() + return builder.build() } } @RequiresApi(Build.VERSION_CODES.O) - private fun createBaseNotificationBuilder(pushMessage: PushMessage, grouped: Boolean = false): NotificationCompat.Builder { + private fun createBaseNotificationBuilder( + pushMessage: PushMessage, + grouped: Boolean = false + ): NotificationCompat.Builder { return with(pushMessage) { val id = notificationId.toInt() val host = info.host @@ -261,12 +282,13 @@ class PushManager @Inject constructor( channelName = host channelId = host } - val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH) + val channel = + NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH) channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC channel.enableLights(false) channel.enableVibration(true) channel.setShowBadge(true) - manager.createNotificationChannel(channel) + notificationManager.createNotificationChannel(channel) builder.setChannelId(channelId) } @@ -293,13 +315,29 @@ class PushManager @Inject constructor( val deleteIntent = Intent(context, DeleteReceiver::class.java) .putExtra(EXTRA_NOT_ID, pushMessage.notificationId.toInt()) .putExtra(EXTRA_HOSTNAME, pushMessage.info.host) - return PendingIntent.getBroadcast(context, pushMessage.notificationId.toInt(), deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT) + return PendingIntent.getBroadcast( + context, + pushMessage.notificationId.toInt(), + deleteIntent, + PendingIntent.FLAG_UPDATE_CURRENT + ) } - private fun getContentIntent(context: Context, notificationId: Int, pushMessage: PushMessage, grouped: Boolean = false): PendingIntent { + private fun getContentIntent( + context: Context, + notificationId: Int, + pushMessage: PushMessage, + grouped: Boolean = false + ): PendingIntent { val roomId = if (!grouped) pushMessage.info.roomId else null - val notificationIntent = context.changeServerIntent(pushMessage.info.host, chatRoomId = roomId) - return PendingIntent.getActivity(context, random.nextInt(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT) + val notificationIntent = + context.changeServerIntent(pushMessage.info.host, chatRoomId = roomId) + return PendingIntent.getActivity( + context, + random.nextInt(), + notificationIntent, + PendingIntent.FLAG_UPDATE_CURRENT + ) } // CharSequence extensions @@ -311,59 +349,12 @@ class PushManager @Inject constructor( } } - // NotificationCompat.Builder extensions - private fun NotificationCompat.Builder.addReplyAction(pushMessage: PushMessage): NotificationCompat.Builder { - val replyTextHint = context.getText(R.string.notif_action_reply_hint) - val replyRemoteInput = RemoteInput.Builder(REMOTE_INPUT_REPLY) - .setLabel(replyTextHint) - .build() - val pendingIntent = getReplyPendingIntent(pushMessage) - val replyAction = NotificationCompat.Action.Builder(R.drawable.ic_action_message_reply_24dp, replyTextHint, pendingIntent) - .addRemoteInput(replyRemoteInput) - .setAllowGeneratedReplies(true) - .build() - - this.addAction(replyAction) - return this - } - - private fun getReplyIntent(pushMessage: PushMessage): Intent { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - Intent(context, DirectReplyReceiver::class.java) - } else { - Intent(context, MainActivity::class.java).also { - it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - } - }.also { - it.action = ACTION_REPLY - it.putExtra(EXTRA_PUSH_MESSAGE, pushMessage) - } - } - - private fun getReplyPendingIntent(pushMessage: PushMessage): PendingIntent { - val replyIntent = getReplyIntent(pushMessage) - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - PendingIntent.getBroadcast( - context, - random.nextInt(), - replyIntent, - PendingIntent.FLAG_UPDATE_CURRENT - ) - } else { - PendingIntent.getActivity( - context, - random.nextInt(), - replyIntent, - PendingIntent.FLAG_UPDATE_CURRENT - ) - } - } - private fun NotificationCompat.Builder.setMessageNotification(): NotificationCompat.Builder { val alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val res = context.resources val smallIcon = res.getIdentifier( - "rocket_chat_notification", "drawable", context.packageName) + "rocket_chat_notification", "drawable", context.packageName + ) with(this) { setAutoCancel(true) setShowWhen(true) @@ -376,144 +367,5 @@ class PushManager @Inject constructor( } } -data class PushMessage( - val title: String, - val message: String, - val info: PushInfo, - val image: String? = null, - val count: String? = null, - val notificationId: String, - val summaryText: String? = null, - val style: String? = null -) : Parcelable { - - constructor(parcel: Parcel) : this( - parcel.readString().orEmpty(), - parcel.readString().orEmpty(), - parcel.readParcelable(PushMessage::class.java.classLoader) ?: PushInfo.EMPTY, - parcel.readString(), - parcel.readString(), - parcel.readString().orEmpty(), - parcel.readString(), - parcel.readString()) - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(title) - parcel.writeString(message) - parcel.writeParcelable(info, flags) - parcel.writeString(image) - parcel.writeString(count) - parcel.writeString(notificationId) - parcel.writeString(summaryText) - parcel.writeString(style) - } - - override fun describeContents(): Int { - return 0 - } - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): PushMessage { - return PushMessage(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } -} - -@JsonSerializable -data class PushInfo @KotshiConstructor constructor( - @Json(name = "host") val hostname: String, - @Json(name = "rid") val roomId: String, - val type: RoomType, - val name: String?, - val sender: PushSender? -) : Parcelable { - val createdAt: Long - get() = System.currentTimeMillis() - val host by lazy { - sanitizeUrl(hostname) - } - - constructor(parcel: Parcel) : this( - parcel.readString().orEmpty(), - parcel.readString().orEmpty(), - roomTypeOf(parcel.readString().orEmpty()), - parcel.readString(), - parcel.readParcelable(PushInfo::class.java.classLoader)) - - private fun sanitizeUrl(baseUrl: String): String { - var url = baseUrl.trim() - while (url.endsWith('/')) { - url = url.dropLast(1) - } - - return url - } - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(hostname) - parcel.writeString(roomId) - parcel.writeString(type.toString()) - parcel.writeString(name) - parcel.writeParcelable(sender, flags) - } - - override fun describeContents(): Int { - return 0 - } - - companion object CREATOR : Parcelable.Creator { - val EMPTY = PushInfo(hostname = "", roomId = "", type = roomTypeOf(RoomType.CHANNEL), name = "", - sender = null) - - override fun createFromParcel(parcel: Parcel): PushInfo { - return PushInfo(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } -} - -@JsonSerializable -data class PushSender @KotshiConstructor constructor( - @Json(name = "_id") val id: String, - val username: String?, - val name: String? -) : Parcelable { - constructor(parcel: Parcel) : this( - parcel.readString().orEmpty(), - parcel.readString(), - parcel.readString()) - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(id) - parcel.writeString(username) - parcel.writeString(name) - } - - override fun describeContents(): Int { - return 0 - } - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): PushSender { - return PushSender(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } -} - const val EXTRA_NOT_ID = "chat.rocket.android.EXTRA_NOT_ID" -const val EXTRA_HOSTNAME = "chat.rocket.android.EXTRA_HOSTNAME" -const val EXTRA_PUSH_MESSAGE = "chat.rocket.android.EXTRA_PUSH_MESSAGE" -const val EXTRA_ROOM_ID = "chat.rocket.android.EXTRA_ROOM_ID" -const val ACTION_REPLY = "chat.rocket.android.ACTION_REPLY" -const val REMOTE_INPUT_REPLY = "REMOTE_INPUT_REPLY" +const val EXTRA_HOSTNAME = "chat.rocket.android.EXTRA_HOSTNAME" \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/push/PushMessage.kt b/app/src/main/java/chat/rocket/android/push/PushMessage.kt new file mode 100644 index 0000000000..7ca88f9cff --- /dev/null +++ b/app/src/main/java/chat/rocket/android/push/PushMessage.kt @@ -0,0 +1,12 @@ +package chat.rocket.android.push + +data class PushMessage( + val title: String, + val message: String, + val info: PushInfo, + val image: String? = null, + val count: String? = null, + val notificationId: String, + val summaryText: String? = null, + val style: String? = null +) diff --git a/app/src/main/java/chat/rocket/android/push/PushSender.kt b/app/src/main/java/chat/rocket/android/push/PushSender.kt new file mode 100644 index 0000000000..b663352af7 --- /dev/null +++ b/app/src/main/java/chat/rocket/android/push/PushSender.kt @@ -0,0 +1,12 @@ +package chat.rocket.android.push + +import com.squareup.moshi.Json +import se.ansman.kotshi.JsonSerializable +import se.ansman.kotshi.KotshiConstructor + +@JsonSerializable +data class PushSender @KotshiConstructor constructor( + @Json(name = "_id") val id: String, + val username: String?, + val name: String? +) \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt b/app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt index 1ab78f1451..171a1b8059 100644 --- a/app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt +++ b/app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt @@ -6,10 +6,9 @@ import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManagerFactory import chat.rocket.android.helper.OauthHelper -import chat.rocket.android.infrastructure.LocalRepository -import chat.rocket.android.main.presentation.MainNavigator import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.PublicSettings +import chat.rocket.android.server.domain.RefreshSettingsInteractor import chat.rocket.android.server.domain.casLoginUrl import chat.rocket.android.server.domain.gitlabUrl import chat.rocket.android.server.domain.isCasAuthenticationEnabled @@ -22,10 +21,6 @@ import chat.rocket.android.server.domain.isLoginFormEnabled import chat.rocket.android.server.domain.isRegistrationEnabledForNewUsers import chat.rocket.android.server.domain.isWordpressAuthenticationEnabled import chat.rocket.android.server.domain.wordpressUrl -import chat.rocket.android.server.domain.GetCurrentServerInteractor -import chat.rocket.android.server.domain.RemoveAccountInteractor -import chat.rocket.android.server.domain.TokenRepository -import chat.rocket.android.server.domain.RefreshSettingsInteractor import chat.rocket.android.server.infrastructure.ConnectionManager import chat.rocket.android.server.infrastructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory @@ -40,17 +35,10 @@ import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatInvalidProtocolException import chat.rocket.common.model.ServerInfo import chat.rocket.core.RocketChatClient -import chat.rocket.core.internal.rest.logout import chat.rocket.core.internal.rest.serverInfo import chat.rocket.core.internal.rest.settingsOauth -import chat.rocket.core.internal.rest.unregisterPushToken -import chat.rocket.core.model.Myself -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.withContext import timber.log.Timber -import javax.inject.Named private const val SERVICE_NAME_FACEBOOK = "facebook" private const val SERVICE_NAME_GITHUB = "github" @@ -62,17 +50,10 @@ private const val SERVICE_NAME_WORDPRESS = "wordpress" abstract class CheckServerPresenter constructor( private val strategy: CancelStrategy, private val factory: RocketChatClientFactory, - @Named("currentServer") private val currentSavedServer: String?, private val settingsInteractor: GetSettingsInteractor? = null, - private val serverInteractor: GetCurrentServerInteractor? = null, - private val localRepository: LocalRepository? = null, - private val removeAccountInteractor: RemoveAccountInteractor? = null, - private val tokenRepository: TokenRepository? = null, private val managerFactory: ConnectionManagerFactory? = null, private val dbManagerFactory: DatabaseManagerFactory? = null, private val versionCheckView: VersionCheckView? = null, - private val tokenView: TokenView? = null, - private val navigator: MainNavigator? = null, private val refreshSettingsInteractor: RefreshSettingsInteractor? = null ) { private lateinit var currentServer: String @@ -202,46 +183,6 @@ abstract class CheckServerPresenter constructor( } } - /** - * Logout the user from the current server. - */ - internal fun logout() { - launchUI(strategy) { - try { - clearTokens() - retryIO("logout") { client?.logout() } - } catch (exception: RocketChatException) { - Timber.e(exception, "Error calling logout") - } - - try { - connectionManager?.disconnect() - currentSavedServer?.let { - removeAccountInteractor?.remove(it) - tokenRepository?.remove(it) - } - withContext(Dispatchers.IO) { dbManager?.logout() } - navigator?.switchOrAddNewServer() - } catch (ex: Exception) { - Timber.e(ex, "Error cleaning up the session...") - } - } - } - - private suspend fun clearTokens() { - serverInteractor?.clear() - val pushToken = localRepository?.get(LocalRepository.KEY_PUSH_TOKEN) - if (pushToken != null) { - try { - retryIO("unregisterPushToken") { client?.unregisterPushToken(pushToken) } - tokenView?.invalidateToken(pushToken) - } catch (ex: Exception) { - Timber.e(ex, "Error unregistering push token") - } - } - localRepository?.clearAllFromServer(currentServer) - } - private fun checkEnabledOauthAccounts(services: List>, serverUrl: String) { if (settings.isFacebookAuthenticationEnabled()) { getServiceMap(services, SERVICE_NAME_FACEBOOK)?.let { serviceMap -> diff --git a/app/src/main/java/chat/rocket/android/server/presentation/TokenView.kt b/app/src/main/java/chat/rocket/android/server/presentation/TokenView.kt deleted file mode 100644 index 72476cacbf..0000000000 --- a/app/src/main/java/chat/rocket/android/server/presentation/TokenView.kt +++ /dev/null @@ -1,6 +0,0 @@ -package chat.rocket.android.server.presentation - -interface TokenView { - - fun invalidateToken(token: String) -} \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt index fe1fa344ff..7f8bed04ef 100644 --- a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt +++ b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt @@ -8,7 +8,9 @@ import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.db.DatabaseManagerFactory import chat.rocket.android.dynamiclinks.DynamicLinksForFirebase import chat.rocket.android.helper.UserHelper +import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.main.presentation.MainNavigator +import chat.rocket.android.push.retrieveCurrentPushToken import chat.rocket.android.server.domain.AnalyticsTrackingInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.PermissionsInteractor @@ -17,16 +19,19 @@ import chat.rocket.android.server.domain.SaveCurrentLanguageInteractor import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.infrastructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory -import chat.rocket.android.server.presentation.CheckServerPresenter import chat.rocket.android.util.extension.HashType import chat.rocket.android.util.extension.hash import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extensions.adminPanelUrl import chat.rocket.android.util.extensions.avatarUrl +import chat.rocket.android.util.invalidateFirebaseToken import chat.rocket.android.util.retryIO +import chat.rocket.common.RocketChatException import chat.rocket.common.util.ifNull import chat.rocket.core.internal.rest.deleteOwnAccount +import chat.rocket.core.internal.rest.logout import chat.rocket.core.internal.rest.serverInfo +import chat.rocket.core.internal.rest.unregisterPushToken import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import timber.log.Timber @@ -46,21 +51,11 @@ class SettingsPresenter @Inject constructor( private val rocketChatClientFactory: RocketChatClientFactory, private val dynamicLinksManager: DynamicLinksForFirebase, private val saveLanguageInteractor: SaveCurrentLanguageInteractor, - getCurrentServerInteractor: GetCurrentServerInteractor, - removeAccountInteractor: RemoveAccountInteractor, - databaseManagerFactory: DatabaseManagerFactory?, - connectionManagerFactory: ConnectionManagerFactory -) : CheckServerPresenter( - strategy = strategy, - factory = rocketChatClientFactory, - currentSavedServer = currentServer, - serverInteractor = getCurrentServerInteractor, - removeAccountInteractor = removeAccountInteractor, - tokenRepository = tokenRepository, - dbManagerFactory = databaseManagerFactory, - managerFactory = connectionManagerFactory, - tokenView = view, - navigator = navigator + private val serverInteractor: GetCurrentServerInteractor, + private val localRepository: LocalRepository, + private val connectionManagerFactory: ConnectionManagerFactory, + private val removeAccountInteractor: RemoveAccountInteractor, + private val dbManagerFactory: DatabaseManagerFactory ) { private val token = currentServer?.let { tokenRepository.get(it) } @@ -106,15 +101,12 @@ class SettingsPresenter @Inject constructor( launchUI(strategy) { view.showLoading() try { - currentServer?.let { + currentServer?.let { currentServer -> withContext(Dispatchers.Default) { // REMARK: Backend API is only working with a lowercase hash. // https://github.com/RocketChat/Rocket.Chat/issues/12573 - retryIO { - rocketChatClientFactory.get(it) - .deleteOwnAccount(password.hash(HashType.Sha256).toLowerCase()) - } - setupConnectionInfo(it) + rocketChatClientFactory.get(currentServer) + .deleteOwnAccount(password.hash(HashType.Sha256).toLowerCase()) logout() } } @@ -178,4 +170,36 @@ class SettingsPresenter @Inject constructor( } fun recreateActivity() = navigator.recreateActivity() + + /** + * Logout the user from the current server. + */ + fun logout() { + launchUI(strategy) { + try { + currentServer?.let { currentServer -> + rocketChatClientFactory.get(currentServer).let { client -> + retrieveCurrentPushToken()?.let { currentPushToken -> + client.unregisterPushToken(currentPushToken) + } + tokenRepository.remove(currentServer) + + serverInteractor.clear() + localRepository.clearAllFromServer(currentServer) + removeAccountInteractor.remove(currentServer) + + withContext(Dispatchers.IO) { + invalidateFirebaseToken() + dbManagerFactory.create(currentServer)?.logout() + } + connectionManagerFactory.create(currentServer)?.disconnect() + client.logout() + navigator.switchOrAddNewServer() + } + } + } catch (exception: RocketChatException) { + Timber.e(exception, "Error while trying to logout") + } + } + } } diff --git a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt index 3fc3b8e413..9dde65dc1a 100644 --- a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt +++ b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt @@ -2,9 +2,8 @@ package chat.rocket.android.settings.presentation import chat.rocket.android.core.behaviours.LoadingView import chat.rocket.android.core.behaviours.MessageView -import chat.rocket.android.server.presentation.TokenView -interface SettingsView : TokenView, LoadingView, MessageView { +interface SettingsView : LoadingView, MessageView { /** * Setups the settings view. diff --git a/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt b/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt index d3d3d20718..57ef40b05e 100644 --- a/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt +++ b/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt @@ -25,10 +25,8 @@ import chat.rocket.android.settings.presentation.SettingsPresenter import chat.rocket.android.settings.presentation.SettingsView import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.showToast -import chat.rocket.android.util.invalidateFirebaseToken import dagger.android.support.AndroidSupportInjection import kotlinx.android.synthetic.main.app_bar.* -import kotlinx.android.synthetic.main.dialog_delete_account.* import kotlinx.android.synthetic.main.fragment_settings.* import timber.log.Timber import javax.inject.Inject @@ -115,8 +113,6 @@ class SettingsFragment : Fragment(), SettingsView, AppLanguageView { presenter.recreateActivity() } - override fun invalidateToken(token: String) = invalidateFirebaseToken(token) - override fun showLoading() { view_loading?.isVisible = true group_settings?.isInvisible = true diff --git a/app/src/main/java/chat/rocket/android/util/extensions/RocketChatClient.kt b/app/src/main/java/chat/rocket/android/util/extensions/RocketChatClient.kt deleted file mode 100644 index 69654be5e8..0000000000 --- a/app/src/main/java/chat/rocket/android/util/extensions/RocketChatClient.kt +++ /dev/null @@ -1,51 +0,0 @@ -package chat.rocket.android.util.extensions - -import chat.rocket.android.db.model.MessageEntity -import chat.rocket.android.server.domain.model.Account -import chat.rocket.android.server.infrastructure.RocketChatClientFactory -import chat.rocket.android.util.retryIO -import chat.rocket.core.internal.rest.registerPushToken -import chat.rocket.core.model.Message -import chat.rocket.core.model.asString -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import timber.log.Timber - -suspend fun RocketChatClientFactory.registerPushToken( - token: String, - accounts: List -) { - withContext(Dispatchers.IO) { - accounts.forEach { account -> - try { - retryIO(description = "register push token: ${account.serverUrl}") { - get(account.serverUrl).registerPushToken(token) - } - } catch (ex: Exception) { - Timber.d(ex, "Error registering Push token for ${account.serverUrl}") - ex.printStackTrace() - } - } - } -} - -fun Message.toEntity(): MessageEntity { - return MessageEntity( - id = id, - roomId = roomId, - message = message, - timestamp = timestamp, - senderId = sender?.id, - updatedAt = updatedAt, - editedAt = editedAt, - editedBy = editedBy?.id, - senderAlias = senderAlias, - avatar = avatar, - type = type.asString(), - groupable = groupable, - parseUrls = parseUrls, - pinned = pinned, - role = role, - synced = synced - ) -} \ No newline at end of file diff --git a/app/src/play/AndroidManifest.xml b/app/src/play/AndroidManifest.xml index e65b346aa9..be18a8f185 100644 --- a/app/src/play/AndroidManifest.xml +++ b/app/src/play/AndroidManifest.xml @@ -13,12 +13,20 @@ android:supportsRtl="true"> + + + + - + \ No newline at end of file diff --git a/app/src/play/java/chat/rocket/android/dagger/module/ServiceBuilder.kt b/app/src/play/java/chat/rocket/android/dagger/module/ServiceBuilder.kt index 50eb542c80..507564d19c 100644 --- a/app/src/play/java/chat/rocket/android/dagger/module/ServiceBuilder.kt +++ b/app/src/play/java/chat/rocket/android/dagger/module/ServiceBuilder.kt @@ -1,32 +1,18 @@ 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.RocketChatMessagingService import chat.rocket.android.push.di.FirebaseMessagingServiceProvider -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(subcomponents = [TokenRegistrationSubComponent::class]) +@Module abstract class ServiceBuilder { @ContributesAndroidInjector(modules = [FirebaseMessagingServiceProvider::class]) - abstract fun bindGcmListenerService(): FirebaseMessagingService + abstract fun bindRocketChatMessagingService(): RocketChatMessagingService @ContributesAndroidInjector(modules = [MessageServiceProvider::class]) abstract fun bindMessageService(): MessageService - - @Binds - @IntoMap - @WorkerKey(TokenRegistrationWorker::class) - abstract fun bindTokenRegistrationWorkerFactory( - builder: TokenRegistrationSubComponent.Builder - ): AndroidInjector.Factory } \ No newline at end of file diff --git a/app/src/play/java/chat/rocket/android/push/FirebaseMessagingService.kt b/app/src/play/java/chat/rocket/android/push/FirebaseMessagingService.kt deleted file mode 100644 index abac90faf2..0000000000 --- a/app/src/play/java/chat/rocket/android/push/FirebaseMessagingService.kt +++ /dev/null @@ -1,48 +0,0 @@ -package chat.rocket.android.push - -import android.os.Bundle -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 -import javax.inject.Inject - -class FirebaseMessagingService : FirebaseMessagingService() { - - @Inject - lateinit var pushManager: PushManager - - override fun onCreate() { - super.onCreate() - AndroidInjection.inject(this) - } - - override fun onMessageReceived(message: RemoteMessage) { - message.data?.let { data -> - val bundle = Bundle() - data.entries.forEach { entry -> - bundle.putString(entry.key, entry.value) - } - pushManager.handle(bundle) - } - } - - override fun onNewToken(token: String) { - val data = workDataOf("token" to token) - val constraint = - Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build() - val work = OneTimeWorkRequestBuilder() - .setInputData(data) - .setConstraints(constraint) - .build() - - // Schedule a job since we are using network... - WorkManager.getInstance().enqueue(work) - } -} \ No newline at end of file diff --git a/app/src/play/java/chat/rocket/android/push/PushToken.kt b/app/src/play/java/chat/rocket/android/push/PushToken.kt index 0e5bd1a793..47f14f51da 100644 --- a/app/src/play/java/chat/rocket/android/push/PushToken.kt +++ b/app/src/play/java/chat/rocket/android/push/PushToken.kt @@ -1,18 +1,24 @@ 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 +import com.google.android.gms.tasks.OnCompleteListener +import com.google.firebase.iid.FirebaseInstanceId +import timber.log.Timber -fun refreshPushToken() { - val constraint = - Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build() - val work = OneTimeWorkRequestBuilder() - .setConstraints(constraint) - .build() +fun retrieveCurrentPushToken(): String? { + var pushNotificationToken: String? = null + FirebaseInstanceId.getInstance().instanceId + .addOnCompleteListener(OnCompleteListener { task -> - // Schedule a job since we are using network... - WorkManager.getInstance().enqueue(work) + if (!task.isSuccessful) { + Timber.w("Unable to retrieve current push notification token") + return@OnCompleteListener + } + + // Get new Instance ID token + task.result?.token?.let { + Timber.d("Retrieve current push notification token: $it") + pushNotificationToken = it + } + }) + return pushNotificationToken } \ No newline at end of file diff --git a/app/src/play/java/chat/rocket/android/push/RocketChatMessagingService.kt b/app/src/play/java/chat/rocket/android/push/RocketChatMessagingService.kt new file mode 100644 index 0000000000..3b73c3904d --- /dev/null +++ b/app/src/play/java/chat/rocket/android/push/RocketChatMessagingService.kt @@ -0,0 +1,25 @@ +package chat.rocket.android.push + +import android.os.Bundle +import com.google.firebase.messaging.FirebaseMessagingService +import com.google.firebase.messaging.RemoteMessage +import dagger.android.AndroidInjection +import javax.inject.Inject + +class RocketChatMessagingService: FirebaseMessagingService() { + @Inject lateinit var pushManager: PushManager + + override fun onCreate() { + AndroidInjection.inject(this) + super.onCreate() + } + + override fun onMessageReceived(message: RemoteMessage) { + Bundle().apply { + message.data.entries.forEach { putString(it.key, it.value) } + pushManager.handle(this) + } + } + + override fun onNewToken(token: String) = pushManager.registerPushNotificationToken(token) +} \ No newline at end of file diff --git a/app/src/play/java/chat/rocket/android/push/di/FirebaseMessagingServiceProvider.kt b/app/src/play/java/chat/rocket/android/push/di/FirebaseMessagingServiceProvider.kt index aa3d0a0049..22bf31fe42 100644 --- a/app/src/play/java/chat/rocket/android/push/di/FirebaseMessagingServiceProvider.kt +++ b/app/src/play/java/chat/rocket/android/push/di/FirebaseMessagingServiceProvider.kt @@ -1,11 +1,13 @@ package chat.rocket.android.push.di import chat.rocket.android.dagger.module.AppModule -import chat.rocket.android.push.FirebaseMessagingService +import chat.rocket.android.push.RocketChatMessagingService import dagger.Module import dagger.android.ContributesAndroidInjector -@Module abstract class FirebaseMessagingServiceProvider { +@Module +abstract class FirebaseMessagingServiceProvider { + @ContributesAndroidInjector(modules = [AppModule::class]) - abstract fun provideFirebaseMessagingService(): FirebaseMessagingService + abstract fun provideFirebaseMessagingService(): RocketChatMessagingService } \ No newline at end of file diff --git a/app/src/play/java/chat/rocket/android/push/di/TokenRegistrationSubComponent.kt b/app/src/play/java/chat/rocket/android/push/di/TokenRegistrationSubComponent.kt deleted file mode 100644 index 8022aa5fb6..0000000000 --- a/app/src/play/java/chat/rocket/android/push/di/TokenRegistrationSubComponent.kt +++ /dev/null @@ -1,11 +0,0 @@ -package chat.rocket.android.push.di - -import chat.rocket.android.push.worker.TokenRegistrationWorker -import dagger.Subcomponent -import dagger.android.AndroidInjector - -@Subcomponent -interface TokenRegistrationSubComponent : AndroidInjector { - @Subcomponent.Builder - abstract class Builder : AndroidInjector.Builder() -} \ No newline at end of file diff --git a/app/src/play/java/chat/rocket/android/push/worker/TokenRegistrationWorker.kt b/app/src/play/java/chat/rocket/android/push/worker/TokenRegistrationWorker.kt deleted file mode 100644 index 2248f05e55..0000000000 --- a/app/src/play/java/chat/rocket/android/push/worker/TokenRegistrationWorker.kt +++ /dev/null @@ -1,52 +0,0 @@ -package chat.rocket.android.push.worker - -import androidx.work.Worker -import chat.rocket.android.dagger.injector.AndroidWorkerInjection -import chat.rocket.android.extensions.await -import chat.rocket.android.infrastructure.LocalRepository -import chat.rocket.android.server.domain.GetAccountsInteractor -import chat.rocket.android.server.infrastructure.RocketChatClientFactory -import chat.rocket.android.util.extensions.registerPushToken -import chat.rocket.common.util.ifNull -import com.google.firebase.iid.FirebaseInstanceId -import kotlinx.coroutines.runBlocking -import timber.log.Timber -import javax.inject.Inject - -class TokenRegistrationWorker : Worker() { - - @Inject - lateinit var factory: RocketChatClientFactory - @Inject - lateinit var getAccountsInteractor: GetAccountsInteractor - @Inject - lateinit var localRepository: LocalRepository - - override fun doWork(): Result { - AndroidWorkerInjection.inject(this) - - runBlocking { - val token = inputData.getString("token") ?: refreshToken() - - token?.let { fcmToken -> - localRepository.save(LocalRepository.KEY_PUSH_TOKEN, fcmToken) - factory.registerPushToken(fcmToken, getAccountsInteractor.get()) - }.ifNull { - Timber.d("Unavailable FCM Token...") - } - } - - return Result.SUCCESS - } - - private fun refreshToken(): String? { - return runBlocking { - try { - FirebaseInstanceId.getInstance().instanceId.await().token - } catch (ex: Exception) { - Timber.e(ex, "Error refreshing Firebase TOKEN") - null - } - } - } -} \ No newline at end of file diff --git a/app/src/play/java/chat/rocket/android/util/FCMManager.kt b/app/src/play/java/chat/rocket/android/util/FCMManager.kt new file mode 100644 index 0000000000..6a9d24b631 --- /dev/null +++ b/app/src/play/java/chat/rocket/android/util/FCMManager.kt @@ -0,0 +1,9 @@ +package chat.rocket.android.util + +import com.google.firebase.iid.FirebaseInstanceId +import timber.log.Timber + +fun invalidateFirebaseToken() { + Timber.d("Invalidating push notification token") + FirebaseInstanceId.getInstance().deleteInstanceId() +} \ No newline at end of file diff --git a/app/src/play/java/chat/rocket/android/util/GMSManager.kt b/app/src/play/java/chat/rocket/android/util/GMSManager.kt deleted file mode 100644 index e064311e26..0000000000 --- a/app/src/play/java/chat/rocket/android/util/GMSManager.kt +++ /dev/null @@ -1,8 +0,0 @@ -package chat.rocket.android.util - -import com.google.firebase.iid.FirebaseInstanceId -import com.google.firebase.messaging.FirebaseMessaging - -fun invalidateFirebaseToken(token: String) { - FirebaseInstanceId.getInstance().deleteToken(token, FirebaseMessaging.INSTANCE_ID_SCOPE) -} diff --git a/dependencies.gradle b/dependencies.gradle index 3f4752e38a..acee7fa47d 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -56,7 +56,7 @@ ext { jitsi : '2.2.2', // Proprietary libraries - firebaseCloudMessage : '19.0.1', + firebaseCloudMessage : '20.0.0', firebaseAnalytics : '17.0.0', firebaseCrashlytics : '2.10.1@aar', firebaseAnswers : '1.4.7@aar', From da14c2f28876392582e21dc734267017fd8c091b Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Sun, 1 Sep 2019 19:53:07 -0300 Subject: [PATCH 02/19] Fixes asynchronous issues while reveiving push token. --- .../rocket/android/dagger/module/AppModule.kt | 4 +-- .../main/presentation/MainPresenter.kt | 21 +++--------- .../rocket/android/main/ui/MainActivity.kt | 3 +- .../chat/rocket/android/push/PushManager.kt | 18 +++------- .../presentation/SettingsPresenter.kt | 7 ++-- .../chat/rocket/android/push/PushToken.kt | 34 ++++++++++++++----- .../push/RocketChatMessagingService.kt | 6 ++-- 7 files changed, 43 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt b/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt index 4f61ccb599..a397ec1bd2 100644 --- a/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt +++ b/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt @@ -343,7 +343,7 @@ class AppModule { moshi: Moshi, getAccountInteractor: GetAccountInteractor, getSettingsInteractor: GetSettingsInteractor, - @Named("currentServer") currentServer: String? + currentServerInteractor: GetCurrentServerInteractor ): PushManager { return PushManager( groupedPushes, @@ -352,7 +352,7 @@ class AppModule { getAccountInteractor, getSettingsInteractor, context, - currentServer + currentServerInteractor ) } diff --git a/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt b/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt index 26c8889a5e..288af9e0b3 100644 --- a/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt +++ b/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt @@ -5,6 +5,7 @@ import chat.rocket.android.core.behaviours.AppLanguageView import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.helper.UserHelper import chat.rocket.android.push.GroupedPush +import chat.rocket.android.push.retrieveCurrentPushNotificationToken import chat.rocket.android.server.domain.GetCurrentLanguageInteractor import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.RefreshPermissionsInteractor @@ -18,13 +19,9 @@ import chat.rocket.android.server.domain.siteName import chat.rocket.android.server.domain.wideTile import chat.rocket.android.server.infrastructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory +import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.serverLogoUrl -import chat.rocket.core.internal.rest.registerPushToken -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import timber.log.Timber import javax.inject.Inject import javax.inject.Named @@ -102,20 +99,10 @@ class MainPresenter @Inject constructor( } } - fun registerPushNotificationToken(token: String) { - GlobalScope.launch(Dispatchers.IO + strategy.jobs) { - try { - currentServer?.let { currentServer -> - factory.get(currentServer).registerPushToken(token) - Timber.d("Registered push notification token: $token") - } - } catch (exception: Exception) { - Timber.e("Unable to register push notification: $exception") - } - } + fun registerPushNotificationToken() = launchUI(strategy) { + currentServer?.let { retrieveCurrentPushNotificationToken(factory.get(it)) } } fun showChatList(chatRoomId: String? = null, deepLinkInfo: DeepLinkInfo? = null) = mainNavigator.toChatList(chatRoomId, deepLinkInfo) - } diff --git a/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt b/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt index 9cde3f8277..8bb58df162 100644 --- a/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt +++ b/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt @@ -16,7 +16,6 @@ import chat.rocket.android.chatrooms.ui.ChatRoomsFragment import chat.rocket.android.chatrooms.ui.TAG_CHAT_ROOMS_FRAGMENT import chat.rocket.android.core.behaviours.AppLanguageView import chat.rocket.android.main.presentation.MainPresenter -import chat.rocket.android.push.retrieveCurrentPushToken import chat.rocket.android.server.ui.INTENT_CHAT_ROOM_ID import chat.rocket.android.authentication.domain.model.DEEP_LINK_INFO_KEY import dagger.android.AndroidInjection @@ -48,7 +47,7 @@ class MainActivity : AppCompatActivity(), HasActivityInjector, getAppLanguage() removeOldAccount() saveNewAccount() - retrieveCurrentPushToken()?.let { token -> registerPushNotificationToken(token) } + registerPushNotificationToken() intent.getStringExtra(INTENT_CHAT_ROOM_ID).let { clearNotificationsForChatRoom(it) showChatList(it, deepLinkInfo) diff --git a/app/src/main/java/chat/rocket/android/push/PushManager.kt b/app/src/main/java/chat/rocket/android/push/PushManager.kt index 24d535e98d..f78fc3e044 100644 --- a/app/src/main/java/chat/rocket/android/push/PushManager.kt +++ b/app/src/main/java/chat/rocket/android/push/PushManager.kt @@ -19,13 +19,13 @@ import androidx.core.content.ContextCompat import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY import chat.rocket.android.R import chat.rocket.android.server.domain.GetAccountInteractor +import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.siteName import chat.rocket.android.server.infrastructure.RocketChatClientFactory import chat.rocket.android.server.ui.changeServerIntent import chat.rocket.common.model.RoomType import chat.rocket.common.model.roomTypeOf -import chat.rocket.core.internal.rest.registerPushToken import com.squareup.moshi.Moshi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope @@ -35,7 +35,6 @@ import timber.log.Timber import java.util.* import java.util.concurrent.atomic.AtomicInteger import javax.inject.Inject -import javax.inject.Named class PushManager @Inject constructor( private val groupedPushes: GroupedPush, @@ -44,21 +43,14 @@ class PushManager @Inject constructor( private val getAccountInteractor: GetAccountInteractor, private val getSettingsInteractor: GetSettingsInteractor, private val context: Context, - @Named("currentServer") private val currentServer: String? + private val serverInteractor: GetCurrentServerInteractor ) { @Inject lateinit var factory: RocketChatClientFactory private val random = Random() - fun registerPushNotificationToken(token: String) { - GlobalScope.launch(Dispatchers.IO) { - try { - currentServer?.let { - factory.get(it).registerPushToken(token) - Timber.d("Registered push notification token: $token") - } - } catch (exception: Exception) { - Timber.e("Unable to register push notification: $exception") - } + fun registerPushNotificationToken(token: String) = GlobalScope.launch(Dispatchers.IO) { + serverInteractor.get()?.let { currentServer -> + registerPushNotificationToken(factory.get(currentServer), token) } } diff --git a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt index 7f8bed04ef..d92dcd8767 100644 --- a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt +++ b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt @@ -10,7 +10,7 @@ import chat.rocket.android.dynamiclinks.DynamicLinksForFirebase import chat.rocket.android.helper.UserHelper import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.main.presentation.MainNavigator -import chat.rocket.android.push.retrieveCurrentPushToken +import chat.rocket.android.push.retrieveCurrentPushNotificationToken import chat.rocket.android.server.domain.AnalyticsTrackingInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.PermissionsInteractor @@ -31,7 +31,6 @@ import chat.rocket.common.util.ifNull import chat.rocket.core.internal.rest.deleteOwnAccount import chat.rocket.core.internal.rest.logout import chat.rocket.core.internal.rest.serverInfo -import chat.rocket.core.internal.rest.unregisterPushToken import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import timber.log.Timber @@ -179,9 +178,7 @@ class SettingsPresenter @Inject constructor( try { currentServer?.let { currentServer -> rocketChatClientFactory.get(currentServer).let { client -> - retrieveCurrentPushToken()?.let { currentPushToken -> - client.unregisterPushToken(currentPushToken) - } + retrieveCurrentPushNotificationToken(client, true) tokenRepository.remove(currentServer) serverInteractor.clear() diff --git a/app/src/play/java/chat/rocket/android/push/PushToken.kt b/app/src/play/java/chat/rocket/android/push/PushToken.kt index 47f14f51da..c16ed5b6ef 100644 --- a/app/src/play/java/chat/rocket/android/push/PushToken.kt +++ b/app/src/play/java/chat/rocket/android/push/PushToken.kt @@ -1,24 +1,40 @@ package chat.rocket.android.push +import chat.rocket.core.RocketChatClient +import chat.rocket.core.internal.rest.registerPushToken +import chat.rocket.core.internal.rest.unregisterPushToken import com.google.android.gms.tasks.OnCompleteListener import com.google.firebase.iid.FirebaseInstanceId +import kotlinx.coroutines.runBlocking import timber.log.Timber -fun retrieveCurrentPushToken(): String? { - var pushNotificationToken: String? = null +fun retrieveCurrentPushNotificationToken( + rocketChatClient: RocketChatClient, + shouldUnregister: Boolean = false +) = FirebaseInstanceId.getInstance().instanceId .addOnCompleteListener(OnCompleteListener { task -> - if (!task.isSuccessful) { - Timber.w("Unable to retrieve current push notification token") + Timber.w("Unable to retrieve the current push notification token") return@OnCompleteListener } - // Get new Instance ID token task.result?.token?.let { - Timber.d("Retrieve current push notification token: $it") - pushNotificationToken = it + Timber.d("Retrieve the current push notification token: $it") + + if (shouldUnregister) { + unregisterPushNotificationToken(rocketChatClient, it) + } else { + registerPushNotificationToken(rocketChatClient, it) + } + } }) - return pushNotificationToken -} \ No newline at end of file + +fun registerPushNotificationToken(rocketChatClient: RocketChatClient, token: String) { + runBlocking { rocketChatClient.registerPushToken(token) } +} + +private fun unregisterPushNotificationToken(rocketChatClient: RocketChatClient, token: String) { + runBlocking { rocketChatClient.unregisterPushToken(token) } +} diff --git a/app/src/play/java/chat/rocket/android/push/RocketChatMessagingService.kt b/app/src/play/java/chat/rocket/android/push/RocketChatMessagingService.kt index 3b73c3904d..546a64eb13 100644 --- a/app/src/play/java/chat/rocket/android/push/RocketChatMessagingService.kt +++ b/app/src/play/java/chat/rocket/android/push/RocketChatMessagingService.kt @@ -6,7 +6,7 @@ import com.google.firebase.messaging.RemoteMessage import dagger.android.AndroidInjection import javax.inject.Inject -class RocketChatMessagingService: FirebaseMessagingService() { +class RocketChatMessagingService : FirebaseMessagingService() { @Inject lateinit var pushManager: PushManager override fun onCreate() { @@ -21,5 +21,7 @@ class RocketChatMessagingService: FirebaseMessagingService() { } } - override fun onNewToken(token: String) = pushManager.registerPushNotificationToken(token) + override fun onNewToken(token: String) { + pushManager.registerPushNotificationToken(token) + } } \ No newline at end of file From 6b934bbc873b27448d4baee03d5f1663b8a3b22d Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Sun, 1 Sep 2019 19:58:19 -0300 Subject: [PATCH 03/19] Update AppLifecycleObserver.kt --- .../java/chat/rocket/android/app/AppLifecycleObserver.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/app/AppLifecycleObserver.kt b/app/src/main/java/chat/rocket/android/app/AppLifecycleObserver.kt index 63a8e9f6a8..85c90af030 100644 --- a/app/src/main/java/chat/rocket/android/app/AppLifecycleObserver.kt +++ b/app/src/main/java/chat/rocket/android/app/AppLifecycleObserver.kt @@ -3,6 +3,7 @@ package chat.rocket.android.app import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent +import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.infrastructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory import chat.rocket.common.model.UserStatus @@ -12,7 +13,7 @@ import javax.inject.Inject import javax.inject.Named class AppLifecycleObserver @Inject constructor( - @Named("currentServer") private val currentServer: String?, + private val serverInteractor: GetCurrentServerInteractor, private val rocketChatClientFactory: RocketChatClientFactory, private val connectionManagerFactory: ConnectionManagerFactory ) : LifecycleObserver { @@ -20,13 +21,13 @@ class AppLifecycleObserver @Inject constructor( @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onEnterForeground() { changeTemporaryStatus(UserStatus.Online()) - currentServer?.let { connectionManagerFactory.create(it)?.resetReconnectionTimer() } + serverInteractor.get()?.let { connectionManagerFactory.create(it)?.resetReconnectionTimer() } } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onEnterBackground() = changeTemporaryStatus(UserStatus.Away()) - private fun changeTemporaryStatus(userStatus: UserStatus) = currentServer?.let { + private fun changeTemporaryStatus(userStatus: UserStatus) = serverInteractor.get()?.let { rocketChatClientFactory.get(it).setTemporaryStatus(userStatus) Timber.d("Changed temporary status to $userStatus") } From 131d6909962424faa2393c7740fff12bea3c3085 Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Sun, 1 Sep 2019 20:06:35 -0300 Subject: [PATCH 04/19] Update PushToken.kt (foss) --- .../foss/java/chat/rocket/android/push/PushToken.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/foss/java/chat/rocket/android/push/PushToken.kt b/app/src/foss/java/chat/rocket/android/push/PushToken.kt index e65dbfd23c..6768b826d3 100644 --- a/app/src/foss/java/chat/rocket/android/push/PushToken.kt +++ b/app/src/foss/java/chat/rocket/android/push/PushToken.kt @@ -1,4 +1,14 @@ package chat.rocket.android.push -fun refreshPushToken() { +import chat.rocket.core.RocketChatClient + +fun retrieveCurrentPushNotificationToken( + rocketChatClient: RocketChatClient, + shouldUnregister: Boolean = false +) { + // Do nothing } + +fun registerPushNotificationToken(rocketChatClient: RocketChatClient, token: String) { + // Do nothing +} \ No newline at end of file From 6fad8f65af263e46cc957c0ae89f14e53851a032 Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Sun, 1 Sep 2019 20:29:42 -0300 Subject: [PATCH 05/19] Add polish language --- .../android/settings/ui/SettingsFragment.kt | 1 + app/src/main/res/values-ar/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fa/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-hi-rIN/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 391 ++++++++++++++++++ app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-pt-rPT/strings.xml | 1 + app/src/main/res/values-ru-rRU/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 20 + app/src/main/res/values/strings.xml | 1 + 18 files changed, 427 insertions(+) create mode 100644 app/src/main/res/values-pl/strings.xml diff --git a/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt b/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt index 57ef40b05e..75e1a3b02c 100644 --- a/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt +++ b/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt @@ -50,6 +50,7 @@ class SettingsFragment : Fragment(), SettingsView, AppLanguageView { "hi,IN", "it", "ja", + "pl", "pt,BR", "pt,PT", "ru,RU", diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 18ad8487db..3a02569a4d 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -88,6 +88,7 @@ الهندية (IN) الإيطالية اليابانية + Polish البرتغالية (BR) البرتغالية (PT) الروسية (RU) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 81bd4024e9..974f892fde 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italienisch Japanisch + Polish Portugiesisch (BR) Portugiesisch (PT) Russisch (RU) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 4af1545fac..89a507b807 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 18b5fa93ac..869fcc861e 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 80c5c17dec..f89e6d7160 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italien Japonais + Polish Portugais (BR) Portugais (PT) Russe (RU) diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index 3482506468..7f35647935 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index dcc85c736c..ef2da43133 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 880d9fba48..9a0fa90db8 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml new file mode 100644 index 0000000000..c9b43f28d4 --- /dev/null +++ b/app/src/main/res/values-pl/strings.xml @@ -0,0 +1,391 @@ + + Rocket.Chat + + + Zaloguj się do serwera + Login + Zarejestruj nazwę użytkownika + Reset hasła + Zarejestruj się + Uwierzytelnianie + Warunki prawne + Czaty + Profil + Członkowie + Członkowie (%d) + Ustawienia + Preferencje + Zmiana hasła + Oceń nas + Panel admina + Zmiana hasła + Aktualizacja profilu + Tworzenie kanału + Licencja + Jesteś pewien? + Wybierz język + Szczegóły kanału + Temat + Ogłoszenie + Opis + + + Połącz + Użyj tej nazwy użytkownika + Warunki korzystania + Polityka prywatności + Nowy kanał + Szukaj + Aktualizuj + Ustawienia + Utwórz kanał + Utwórz + Wyloguj + Dołącz plik + Potwierdź zmianę hasła + Dołącz do czatu + Dostępny + Nieobecny + Zajęty + Niewidoczny + Rysunek + Zapisz w galerii + Wybierz zdjęcie z galerii + Zobacz zdjęcie profilu + Zrób zdjęcie + Resetuj awatar + Połącz z serwerem + Dołącz do społeczności + Utwórz nowy serwer + Zarejestruj + Potwierdź + Dodaj do ulubionych + Usuń z ulubionych + + + Skontaktuj się z nami + Język + Oceń tę aplikację + Udostępnij tę aplikację + Administracja + Licencja + Wersja: %1$s (%2$d) + Wersja serwera: %1$s + Wyślij dane analityczne + Wysyłaj anonimowe statystyki w celu poprawy tej aplikacji + Nie wysyłaj anonimowych statystyk w celu poprawy tej aplikacji + Nie dotyczy, ponieważ jest to wersja FOSS + Wyloguj się z Rocket.Chat + Usuń konto + Zmień status + + + Angielski + Arabski + Niemiecki + Hiszpański + Perski + Francuski + Hindi (IN) + Włoski + Japoński + Język polski + Portugalski (BR) + Portugalski (PT) + Rosyjski (RU) + Turecki + Ukraiński + Chiński (CN) + Chiński (TW) + + + + Przepraszamy, wystąpił błąd, spróbuj później + Twoja sesja jest nieprawidłowa. Zaloguj się ponownie + Brak danych do wyświetlenia + Sprawdź to + Udostępnij używając + Rozmowa z %1$s dnia %2$s + Profil zaktualizowany pomyślnie + Nazwa użytkownika + Proszę podać swoją nazwę użytkownika + Nazwa użytkownika lub e-mail + Hasło + Imię + Proszę podać imię… + E-mail + Proszę podać swój adres e-mail + URL do awatara + Lub kontynuuj używając konta społecznościowego + Nowy użytkownik? %1$s + Zapomniałeś hasła? + Reset + E-mail wysłany! Sprawdź skrzynkę aby zresetować hasło. + Proszę podać poprawny adres e-mail + Kontynuując wyrażasz zgodę na nasze\n%1$s i %2$s + 99+ + Wczoraj + Dzisiaj + Wiadomość + Rozmowa wideo + Dołącz do rozmowy wideo + Ten pokój jest wyłącznie do odczytu + Nieprawidłowy kod 2FA + Nieprawidłowy plik + Nieprawidłowy URL serwera + Zaloguj używając Facebook + Zaloguj używając GitHub + Zaloguj używając Google + Zaloguj używając LinkedIn + Zaloguj używając Meteor + Zaloguj używając Twitter + Zaloguj używając GitLab + Zaloguj używając WordPress + Wyślij wiadomość + Pokaż więcej opcji logowania + Pokaż opcje załączników + Ty + Nieznany + Adres e-mail + UTC offset + Podaj nowe hasło + Potwierdź nowe hasło + Nazwa kanału + Szukaj + Nieprzeczytane wiadomości + Wideo + Audio + Foto + Plik + Brak wiadomości + Build %1$d - %2$s - %3$s + Nieaktualna wersja serswera. Skontaktuj się z administratorem serwera aby go zaktualizował. + + Wersja serwera jest niższa niż zalecana wersja %1$s.\nMożesz się zalogować, ale możesz doświadczyć niespodziewanych zachowań. + + Wersja serwera jest niższa niż minimalna wymagana wersja %1$s.\nProszę zaktualizuj serwer aby się zalogować! + + Brak wiadomości czatu + Zacznij rozmowę aby zobaczyć tutaj\nswoje wiadomości. + Używając HTTP łączysz się do niezabezpieczonego serwera. Nie polecamy tego robić. + Wystąpił błąd podczas sprawdzania wersji twojego serwera, spróbuj ponownie + Wybrany protokół nie jest akceptowany przez serwer, spróbuj użyć HTTPS + Obraz zapisano w galerii + Nie powiodło się zapisanie obrazu + (edytowany) + \u0020i\u0020 + \u0020pisze… + \u0020piszą… + Kilku użytkowników pisze… + Nie znaleziono wyniku + Wylogowanie… + Wgraj plik + Opis pliku + Wyślij + Wysłano załącznik + Witamy w Rocket.Chat + Komunikacja zespołowa + Zaloguj używając e-mail + Utwórz konto + Kontynuuj z Facebook + Kontynuuj z GitHub + Kontynuuj z Google + Kontynuuj z LinkedIn + Kontynuuj z GitLab + Kontynuuj z WordPress + Uwierzytelnianie dwuskładnikowe + Jaki jest Twój kod 2FA? + Skopiowano permalink + Brak tematu + Brak ogłoszenia + Brak opisu + Wyślij e-mail + Wsparcie dla Android app + Nie można zaktualizować hasła. Błąd: %1$s + Hasło zostało pomyślnie zaktualizowane + + %1$s zareagował z %2$s + %1$s zareagował z %2$s + + Dane logowania zostały pomyślnie zapisane + Aby uruchomić kamerę wymagane jest uprawnienie do aparatu. + Aby uruchomić rysunek wymagane jest uprawenienie do pamięci. + Serwer + Dodaj nowy serwer + Katalog + Zmiany nie zostały zapisane. Chcesz je zapisać? + Zapisz + + + Prywatny + Publiczny + Dostęp do tego kanału masz Ty i zaproszeni członkowie + Do tego kanału mają dostęp wszyscy + Kanał tylko do odczytu + Tylko admin może pisać nowe wiadomości + Zaproś użytkowników do kanału + Już zaznaczyłeś tego użytkownika + Nie znaleziono członka + Kanał utworzony pomyślnie + Wiadomość skopiowana + Usuń wiadomość + Naprawdę chcesz usunąć tę wiadomość? + zobacz więcej + zobacz mniej + Zostałeś wyciszony na tym kanale + + + Nazwa pokoju zmieniona na: %1$s przez %2$s + Użytkownik %1$s dodany przez %2$s + Użytkownik %1$s usunięty przez %2$s + Opuścił kanał. + Dołączył do kanału. + Witamy %s + Wiadomość usunięta + Wiadomość przypięta: + Użytkownik %1$s wyciszony przez %2$s + Wyciszenie użytkownika %1$s wyłączone przez %2$s + %1$s ustawione %2$s przez %3$s + %1$s już nie jest %2$s przez %3$s + Rozmowa wideo rozpoczęta przez %1$s + + + Odpowiedz + Info + Edytuj + Skopiuj + Cytuj + Usuń + Przypnij + Odepnij + Oznacz gwiazdką + Odznacz gwiazdkę + Udostępnij + Edycja wiadomości + Dodaj reakcję + Permalink + Raportuj + + + Edycja niedozwolona + Usuwanie niedozwolone + Przypinanie niedozwolone + Oznaczanie gwiazdką niedozwolone + + + Wyszukaj wiadomość + + + Członkowie + + + Wybierz przynajmniej jednego użytkownika + Użytkownicy zaproszeni poprawnie + Użytkownik usunięty poprawnie + Zaproś użytkowników + Usuń użytkownika z pokoju + + + Wzmianki + Brak wzmianki + Wszystkie wzmianki\npojawiają się tutaj + + + Przypięte wiadomości + Brak przypiętych wiadomości + Wszystkie przypięte wiadomości\npojawiają się tutaj + + + Ulubione wiadomości + Brak ulubionych wiadomości + Wszystkie ulubione wiadomości\npojawiają się tutaj + + + Pliki + Pliki (%d) + Brak plików + Wszystkie pliki pojawiają się tutaj + + + Wielkość pliku %1$d bajtów przekracza maksymalną dopuszczalną wielkość %2$d bajtów + + + Połączony + Rozłączony + Łączenie + Uwierzytelnianie + Rozłączanie + Łączenie za %d sekund + + + Powiadom wszystkich użytkowników w tym pokoju + Powiadom aktywnych użytkowników w tym pokoju + + + Wyświetla ༼ つ ◕_◕ ༽つ przed Twoją wiadomością + Wyświetla ( ͡° ͜ʖ ͡°) po Twojej wiadomości + Wyświetla ¯\_(ツ)_/¯ po Twojej wiadomości + Wyświetla (╯°□°)╯︵ ┻━┻ + Wyświetla ┬─┬ ノ( ゜-゜ノ) + Utwórz nowy kanał + Pokaż listę skrótów klawiszowych + Zaproś wszystkich użytkowników z [#channel] by dołączyli do tego kanału + Zaproś wszystkich użytkowników tego kanału by dołączyli do [#channel] + Zarchiwizuj + Usuń kogoś z pokoju + Opuść bieżący kanał + Pokaż tekst akcji + Wyślij komuś bezpośrednią wiadomość + Wycisz kogoś w pokoju + Wyłącz wyciszenie kogoś w pokoju + Zaproś użytkownika aby dołączył do tego kanału + Odarchiwizuj + Dołącz do podanego kanału + Tworzy gifa z podanego tekstu + Ustaw temat + + + Brak ostatnich emoji + Standardowy odcień skóry + + + Sortowanie po %1$s + Sortowanie po + Aktywność + Nazwa + Nieprzeczytane na górze + Grupowanie po typie + Grupowanie po ulubionych + + + Ulubione + Kanały + Użytkownicy + Wyszukaj globalnych użytkowników + Jeśli włączone, możesz wyszukiwać dowolnych użytkowników z innych firm lub serwerów. + Prywatne grupy + Bezpośrednie wiadomości + Czaty na żywo + Nieznany + + + Edytuj udostępnioną wiadomość + ODPOWIEDZ + Wysłanie odpowiedzi się nie powiodło. Spróbuj ponownie. + Wiadomość do %1$s wysłana! + Czytaj przez + Informacja o wiadomości + Typ pokoju zmieniony na: %1$s przez %2$s + + (FOSS) + + + Strefa czasowa + Status: %1$s + Status + + + Zatwierdź + *wymagane + Twój raport został wysłany! + diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 5ed0bb0dcd..8215b6739d 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 9ff0bea9be..23bf51b841 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -87,6 +87,7 @@ Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index c6d739df4c..cccb99633b 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -88,6 +88,7 @@ Хинди (IN) Итальянский Японский + Polish Португальский (BR) Португальский (PT) Русский (RU) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 5d689a7940..fea6e125bb 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 294a6eb8a1..079d958425 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 9dc7b0fa28..daf40f4e24 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -88,6 +88,7 @@ Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index e7ad15bbe3..4a2726af38 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -77,6 +77,26 @@ Delete account Change status + + English + Arabic + German + Spanish + Persian + French + Hindi (IN) + Italian + Japanese + Polish + Portuguese (BR) + Portuguese (PT) + Russian (RU) + Turkish + Ukrainian + Chinese (CN) + Chinese (TW) + + 發生了錯誤,請稍後試試 沒有資料 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4fc8fcf9e7..73564aac0d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -100,6 +100,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin Hindi (IN) Italian Japanese + Polish Portuguese (BR) Portuguese (PT) Russian (RU) From fc840f0d5df4ff534b3cd9e14d56a532428bae8d Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Tue, 17 Sep 2019 10:55:38 -0300 Subject: [PATCH 06/19] Fixes an issue that makes the chat room list not being updated properly. --- .../server/infrastructure/ConnectionManager.kt | 17 ++++------------- .../android/suggestions/ui/SuggestionsView.kt | 4 +--- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/server/infrastructure/ConnectionManager.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/ConnectionManager.kt index b889354309..d7e5f96ba0 100644 --- a/app/src/main/java/chat/rocket/android/server/infrastructure/ConnectionManager.kt +++ b/app/src/main/java/chat/rocket/android/server/infrastructure/ConnectionManager.kt @@ -126,23 +126,14 @@ class ConnectionManager( dbManager.processUsersBatch(users) } - launch { - for (room in client.roomsChannel) { - Timber.d("Got room streamed") - roomsActor.send(room) - } + launch { for (room in client.roomsChannel) roomsActor.send(room) } - for (subscription in client.subscriptionsChannel) { - Timber.d("Got subscription streamed") - roomsActor.send(subscription) - } + launch { for (subscription in client.subscriptionsChannel) roomsActor.send(subscription) } - for (user in client.activeUsersChannel) { - userActor.send(user) - } - } + launch { for (user in client.activeUsersChannel) userActor.send(user) } } + fun addStateChannel(channel: Channel) = stateChannelList.add(channel) fun removeStateChannel(channel: Channel) = stateChannelList.remove(channel) diff --git a/suggestions/src/main/java/chat/rocket/android/suggestions/ui/SuggestionsView.kt b/suggestions/src/main/java/chat/rocket/android/suggestions/ui/SuggestionsView.kt index 74c5767118..55e971531b 100644 --- a/suggestions/src/main/java/chat/rocket/android/suggestions/ui/SuggestionsView.kt +++ b/suggestions/src/main/java/chat/rocket/android/suggestions/ui/SuggestionsView.kt @@ -196,9 +196,7 @@ class SuggestionsView : FrameLayout, TextWatcher { } fun addSuggestionProviderAction(token: String, provider: (query: String) -> Unit): SuggestionsView { - if (adaptersByToken[token] == null) { - throw IllegalStateException("token \"$token\" suggestion provider added without adapter") - } + checkNotNull(adaptersByToken[token]) { "token \"$token\" suggestion provider added without adapter" } externalProvidersByToken.getOrPut(token, { provider }) return this } From d8f9d75d550ced002210022f3975fd6e9829e8d4 Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Tue, 17 Sep 2019 12:27:04 -0300 Subject: [PATCH 07/19] Fixes showing wrong user status on settings screen. --- .../profile/presentation/ProfilePresenter.kt | 2 +- .../presentation/SettingsPresenter.kt | 43 ++++++++----------- 2 files changed, 18 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt b/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt index 31a8b3a5ec..ba28ea9e1c 100644 --- a/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt +++ b/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt @@ -46,7 +46,7 @@ class ProfilePresenter @Inject constructor( launchUI(strategy) { view.showLoading() try { - val me = retryIO(description = "serverInfo", times = 5) { + val me = retryIO(description = "me", times = 5) { client.me() } diff --git a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt index d92dcd8767..26e6596b63 100644 --- a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt +++ b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt @@ -1,13 +1,10 @@ package chat.rocket.android.settings.presentation import android.content.Context -import android.content.Intent import android.os.Build -import chat.rocket.android.R import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.db.DatabaseManagerFactory import chat.rocket.android.dynamiclinks.DynamicLinksForFirebase -import chat.rocket.android.helper.UserHelper import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.main.presentation.MainNavigator import chat.rocket.android.push.retrieveCurrentPushNotificationToken @@ -30,7 +27,9 @@ import chat.rocket.common.RocketChatException import chat.rocket.common.util.ifNull import chat.rocket.core.internal.rest.deleteOwnAccount import chat.rocket.core.internal.rest.logout +import chat.rocket.core.internal.rest.me import chat.rocket.core.internal.rest.serverInfo +import chat.rocket.core.model.Myself import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import timber.log.Timber @@ -43,7 +42,6 @@ class SettingsPresenter @Inject constructor( private val strategy: CancelStrategy, private val navigator: MainNavigator, @Named("currentServer") private val currentServer: String?, - private val userHelper: UserHelper, private val analyticsTrackingInteractor: AnalyticsTrackingInteractor, private val tokenRepository: TokenRepository, private val permissions: PermissionsInteractor, @@ -57,21 +55,26 @@ class SettingsPresenter @Inject constructor( private val dbManagerFactory: DatabaseManagerFactory ) { private val token = currentServer?.let { tokenRepository.get(it) } + private lateinit var me: Myself fun setupView() { launchUI(strategy) { try { view.showLoading() - currentServer?.let { + currentServer?.let { serverUrl -> val serverInfo = retryIO(description = "serverInfo", times = 5) { - rocketChatClientFactory.get(it).serverInfo() + rocketChatClientFactory.get(serverUrl).serverInfo() } - userHelper.user()?.let { user -> + me = retryIO(description = "me", times = 5) { + rocketChatClientFactory.get(serverUrl).me() + } + + me.username?.let { username -> view.setupSettingsView( - it.avatarUrl(user.username!!, token?.userId, token?.authToken), - userHelper.displayName(user) ?: user.username ?: "", - user.status.toString(), + serverUrl.avatarUrl(username, token?.userId, token?.authToken), + username, + me.status.toString(), permissions.isAdministrationEnabled(), analyticsTrackingInteractor.get(), true, @@ -144,26 +147,14 @@ class SettingsPresenter @Inject constructor( fun toLicense(licenseUrl: String, licenseTitle: String) = navigator.toLicense(licenseUrl, licenseTitle) - fun shareViaApp(context: Context?) { + fun prepareShareApp() { launchUI(strategy) { - val user = userHelper.user() - val deepLinkCallback = { returnedString: String? -> - val link = returnedString ?: context?.getString(R.string.play_store_link) - with(Intent(Intent.ACTION_SEND)) { - type = "text/plain" - putExtra(Intent.EXTRA_SUBJECT, context?.getString(R.string.msg_check_this_out)) - putExtra(Intent.EXTRA_TEXT, link) - context?.startActivity( - Intent.createChooser( - this, - context.getString(R.string.msg_share_using) - ) - ) - } + view.openShareApp(returnedString) } + currentServer?.let { - dynamicLinksManager.createDynamicLink(user?.username, it, deepLinkCallback) + dynamicLinksManager.createDynamicLink(me.username, it, deepLinkCallback) } } } From 414cc69671a9c61ee73963367714b66f2db976dc Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Tue, 17 Sep 2019 12:27:24 -0300 Subject: [PATCH 08/19] Removes context reference from presenter. --- .../settings/presentation/SettingsView.kt | 2 ++ .../android/settings/ui/SettingsFragment.kt | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt index 9dde65dc1a..5cf416ab99 100644 --- a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt +++ b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt @@ -25,4 +25,6 @@ interface SettingsView : LoadingView, MessageView { isDeleteAccountEnabled: Boolean, serverVersion: String ) + + fun openShareApp(link: String?) } diff --git a/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt b/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt index 75e1a3b02c..97570c598e 100644 --- a/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt +++ b/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt @@ -109,6 +109,20 @@ class SettingsFragment : Fragment(), SettingsView, AppLanguageView { text_delete_account.isVisible = isDeleteAccountEnabled } + override fun openShareApp(link: String?) { + with(Intent(Intent.ACTION_SEND)) { + type = "text/plain" + putExtra(Intent.EXTRA_SUBJECT, context?.getString(R.string.msg_check_this_out)) + putExtra(Intent.EXTRA_TEXT, link ?: getString(R.string.play_store_link)) + context?.startActivity( + Intent.createChooser( + this, + getString(R.string.msg_share_using) + ) + ) + } + } + override fun updateLanguage(language: String, country: String?) { presenter.saveLocale(language, country) presenter.recreateActivity() @@ -234,7 +248,7 @@ class SettingsFragment : Fragment(), SettingsView, AppLanguageView { private fun shareApp() { // We can't know for sure at this point that the invitation was sent successfully since they will now be outside our app analyticsManager.logInviteSent(InviteType.ViaApp) - presenter.shareViaApp(context) + presenter.prepareShareApp() } private fun showLogoutDialog() { From b50e9e7cc082fee12ef3a20997a44e6938a7c105 Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Thu, 19 Sep 2019 11:39:59 -0300 Subject: [PATCH 09/19] Update libraries version and track changes on SDK --- .../chat.rocket.android.db.RCDatabase/14.json | 1117 +++++++++++++++++ .../android/app/RocketChatApplication.kt | 102 +- .../authentication/di/AuthenticationModule.kt | 2 +- .../server/ui/ServerFragment.kt | 4 +- .../di/MessageInfoFragmentModule.kt | 2 +- .../android/chatroom/di/ChatRoomModule.kt | 2 +- .../presentation/ChatRoomNavigator.kt | 4 +- .../presentation/ChatRoomPresenter.kt | 2 +- .../android/chatroom/ui/ChatRoomActivity.kt | 4 +- .../android/chatroom/uimodel/UiModelMapper.kt | 7 +- .../chatrooms/adapter/RoomUiModelMapper.kt | 9 +- .../chatrooms/adapter/model/RoomUiModel.kt | 2 +- .../presentation/ChatRoomsPresenter.kt | 2 +- .../chat/rocket/android/db/DatabaseManager.kt | 4 +- .../java/chat/rocket/android/db/RCDatabase.kt | 2 +- .../rocket/android/db/model/ChatRoomEntity.kt | 6 +- .../chat/rocket/android/main/di/MainModule.kt | 2 +- .../main/presentation/MainNavigator.kt | 4 +- .../java/chat/rocket/android/push/PushInfo.kt | 3 +- .../chat/rocket/android/push/PushSender.kt | 3 +- .../android/server/di/ChangeServerModule.kt | 2 +- .../server/domain/ChatRoomsInteractor.kt | 2 +- .../infrastructure/RocketChatClientFactory.kt | 3 +- .../password/di/PasswordFragmentModule.kt | 2 +- .../android/util/AppJsonAdapterFactory.kt | 2 +- .../util/BasicAuthenticatorInterceptor.kt | 8 +- .../android/util/HttpLoggingInterceptor.kt | 47 +- .../rocket/android/util/extensions/Numbers.kt | 7 + .../rocket/android/util/extensions/String.kt | 5 +- .../di/VideoConferenceModule.kt | 2 +- dependencies.gradle | 8 +- .../rocket/android/draw/main/di/DrawModule.kt | 2 +- .../1.json | 8 +- .../java/chat/rocket/android/emoji/Emoji.kt | 4 +- .../chat/rocket/android/emoji/EmojiParser.kt | 2 +- .../rocket/android/emoji/EmojiRepository.kt | 2 +- 36 files changed, 1239 insertions(+), 150 deletions(-) create mode 100644 app/schemas/chat.rocket.android.db.RCDatabase/14.json diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/14.json b/app/schemas/chat.rocket.android.db.RCDatabase/14.json new file mode 100644 index 0000000000..12f96013a2 --- /dev/null +++ b/app/schemas/chat.rocket.android.db.RCDatabase/14.json @@ -0,0 +1,1117 @@ +{ + "formatVersion": 1, + "database": { + "version": 14, + "identityHash": "c7462d4b4f9ad32f9d8d2e53a7abd535", + "entities": [ + { + "tableName": "users", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "REAL", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_users_username", + "unique": false, + "columnNames": [ + "username" + ], + "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "chatrooms", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `parentId` TEXT, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `topic` TEXT, `announcement` TEXT, `description` TEXT, `open` INTEGER, `alert` INTEGER, `unread` INTEGER, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, `muted` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subscriptionId", + "columnName": "subscriptionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fullname", + "columnName": "fullname", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "ownerId", + "columnName": "ownerId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "readonly", + "columnName": "readonly", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isDefault", + "columnName": "isDefault", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "favorite", + "columnName": "favorite", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "topic", + "columnName": "topic", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "announcement", + "columnName": "announcement", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "open", + "columnName": "open", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "alert", + "columnName": "alert", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "userMentions", + "columnName": "userMentions", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "groupMentions", + "columnName": "groupMentions", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastSeen", + "columnName": "lastSeen", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastMessageText", + "columnName": "lastMessageText", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastMessageUserId", + "columnName": "lastMessageUserId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastMessageTimestamp", + "columnName": "lastMessageTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "broadcast", + "columnName": "broadcast", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "muted", + "columnName": "muted", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_chatrooms_userId", + "unique": false, + "columnNames": [ + "userId" + ], + "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)" + }, + { + "name": "index_chatrooms_ownerId", + "unique": false, + "columnNames": [ + "ownerId" + ], + "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)" + }, + { + "name": "index_chatrooms_subscriptionId", + "unique": true, + "columnNames": [ + "subscriptionId" + ], + "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)" + }, + { + "name": "index_chatrooms_updatedAt", + "unique": false, + "columnNames": [ + "updatedAt" + ], + "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)" + }, + { + "name": "index_chatrooms_lastMessageUserId", + "unique": false, + "columnNames": [ + "lastMessageUserId" + ], + "createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)" + } + ], + "foreignKeys": [ + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "ownerId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "userId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "lastMessageUserId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roomId` TEXT NOT NULL, `message` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `senderId` TEXT, `updatedAt` INTEGER, `editedAt` INTEGER, `editedBy` TEXT, `senderAlias` TEXT, `avatar` TEXT, `type` TEXT, `groupable` INTEGER NOT NULL, `parseUrls` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `role` TEXT, `synced` INTEGER NOT NULL, `unread` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`senderId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`editedBy`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomId", + "columnName": "roomId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "senderId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "editedAt", + "columnName": "editedAt", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "editedBy", + "columnName": "editedBy", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "senderAlias", + "columnName": "senderAlias", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "avatar", + "columnName": "avatar", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "groupable", + "columnName": "groupable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parseUrls", + "columnName": "parseUrls", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "synced", + "columnName": "synced", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "senderId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "editedBy" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "message_favorites", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "messageId", + "userId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "messageId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "userId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "message_mentions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "messageId", + "userId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "messageId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "userId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "message_channels", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `roomId` TEXT NOT NULL, `roomName` TEXT, PRIMARY KEY(`messageId`, `roomId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomId", + "columnName": "roomId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomName", + "columnName": "roomName", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "messageId", + "roomId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "messageId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "attachments", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` TEXT NOT NULL, `message_id` TEXT NOT NULL, `title` TEXT, `type` TEXT, `description` TEXT, `text` TEXT, `author_name` TEXT, `author_icon` TEXT, `author_link` TEXT, `thumb_url` TEXT, `color` TEXT, `fallback` TEXT, `title_link` TEXT, `title_link_download` INTEGER NOT NULL, `image_url` TEXT, `image_type` TEXT, `image_size` INTEGER, `video_url` TEXT, `video_type` TEXT, `video_size` INTEGER, `audio_url` TEXT, `audio_type` TEXT, `audio_size` INTEGER, `message_link` TEXT, `timestamp` INTEGER, `has_actions` INTEGER NOT NULL, `has_fields` INTEGER NOT NULL, `button_alignment` TEXT, PRIMARY KEY(`_id`), FOREIGN KEY(`message_id`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "_id", + "columnName": "_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "authorName", + "columnName": "author_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "authorIcon", + "columnName": "author_icon", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "authorLink", + "columnName": "author_link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbUrl", + "columnName": "thumb_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "fallback", + "columnName": "fallback", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "titleLink", + "columnName": "title_link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "titleLinkDownload", + "columnName": "title_link_download", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "imageUrl", + "columnName": "image_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "imageType", + "columnName": "image_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "imageSize", + "columnName": "image_size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "videoUrl", + "columnName": "video_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "videoType", + "columnName": "video_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "videoSize", + "columnName": "video_size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "audioUrl", + "columnName": "audio_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "audioType", + "columnName": "audio_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "audioSize", + "columnName": "audio_size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "messageLink", + "columnName": "message_link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "hasActions", + "columnName": "has_actions", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasFields", + "columnName": "has_fields", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "buttonAlignment", + "columnName": "button_alignment", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "message_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "attachment_fields", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `title` TEXT NOT NULL, `value` TEXT NOT NULL, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "attachmentId", + "columnName": "attachmentId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_attachment_fields_attachmentId", + "unique": false, + "columnNames": [ + "attachmentId" + ], + "createSql": "CREATE INDEX `index_attachment_fields_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)" + } + ], + "foreignKeys": [ + { + "table": "attachments", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "attachmentId" + ], + "referencedColumns": [ + "_id" + ] + } + ] + }, + { + "tableName": "attachment_action", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `type` TEXT NOT NULL, `text` TEXT, `url` TEXT, `isWebView` INTEGER, `webViewHeightRatio` TEXT, `imageUrl` TEXT, `message` TEXT, `isMessageInChatWindow` INTEGER, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "attachmentId", + "columnName": "attachmentId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isWebView", + "columnName": "isWebView", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "webViewHeightRatio", + "columnName": "webViewHeightRatio", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isMessageInChatWindow", + "columnName": "isMessageInChatWindow", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_attachment_action_attachmentId", + "unique": false, + "columnNames": [ + "attachmentId" + ], + "createSql": "CREATE INDEX `index_attachment_action_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)" + } + ], + "foreignKeys": [ + { + "table": "attachments", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "attachmentId" + ], + "referencedColumns": [ + "_id" + ] + } + ] + }, + { + "tableName": "urls", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`urlId` INTEGER PRIMARY KEY AUTOINCREMENT, `messageId` TEXT NOT NULL, `url` TEXT NOT NULL, `hostname` TEXT, `title` TEXT, `description` TEXT, `imageUrl` TEXT, FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "urlId", + "columnName": "urlId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hostname", + "columnName": "hostname", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "urlId" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_urls_messageId", + "unique": false, + "columnNames": [ + "messageId" + ], + "createSql": "CREATE INDEX `index_urls_messageId` ON `${TABLE_NAME}` (`messageId`)" + } + ], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "messageId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "reactions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `messageId` TEXT NOT NULL, `count` INTEGER NOT NULL, `usernames` TEXT NOT NULL, `names` TEXT NOT NULL, PRIMARY KEY(`reaction`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "reaction", + "columnName": "reaction", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usernames", + "columnName": "usernames", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "names", + "columnName": "names", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "reaction" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_reactions_messageId", + "unique": false, + "columnNames": [ + "messageId" + ], + "createSql": "CREATE INDEX `index_reactions_messageId` ON `${TABLE_NAME}` (`messageId`)" + } + ], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "messageId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "messages_sync", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`roomId` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`roomId`))", + "fields": [ + { + "fieldPath": "roomId", + "columnName": "roomId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "roomId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"c7462d4b4f9ad32f9d8d2e53a7abd535\")" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt b/app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt index 5410d3d7f2..6de3d1cbba 100644 --- a/app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt +++ b/app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt @@ -22,7 +22,6 @@ import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.server.domain.AccountsRepository 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.infrastructure.RocketChatClientFactory import chat.rocket.android.util.retryIO @@ -37,8 +36,7 @@ import dagger.android.DispatchingAndroidInjector import dagger.android.HasActivityInjector import dagger.android.HasBroadcastReceiverInjector import dagger.android.HasServiceInjector -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import timber.log.Timber import java.lang.ref.WeakReference import javax.inject.Inject @@ -104,45 +102,24 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje setupFresco() setupTimber() - if (localRepository.needOldMessagesCleanUp()) { - messagesPrefs.edit { - clear() - } - localRepository.setOldMessagesCleanedUp() - } - - // TODO - remove REALM files. - // TODO - remove this - checkCurrentServer() - // TODO - FIXME - we need to properly inject and initialize the EmojiRepository loadEmojis() } - private fun checkCurrentServer() { - val currentServer = getCurrentServerInteractor.get() ?: "" + override fun activityInjector() = activityDispatchingAndroidInjector - if (currentServer == "") { - val message = "null currentServer" - Timber.d(IllegalStateException(message), message) - } + override fun serviceInjector() = serviceDispatchingAndroidInjector - val settings = settingsInteractor.get(currentServer) - if (settings.isEmpty()) { - val message = "Empty settings for: $currentServer" - Timber.d(IllegalStateException(message), message) - } - val baseUrl = settings[SITE_URL] - if (baseUrl == null) { - val message = "Server $currentServer SITE_URL" - Timber.d(IllegalStateException(message), message) - } - } + override fun broadcastReceiverInjector() = broadcastReceiverInjector + + override fun workerInjector() = workerInjector - private fun setupFresco() { - Fresco.initialize(this, imagePipelineConfig, draweeConfig) + companion object { + var context: WeakReference? = null } + private fun setupFresco() = Fresco.initialize(this, imagePipelineConfig, draweeConfig) + private fun setupTimber() { if (BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) @@ -151,20 +128,6 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje } } - override fun activityInjector() = activityDispatchingAndroidInjector - - override fun serviceInjector() = serviceDispatchingAndroidInjector - - override fun broadcastReceiverInjector() = broadcastReceiverInjector - - override fun workerInjector() = workerInjector - - companion object { - var context: WeakReference? = null - fun getAppContext(): Context? { - return context?.get() - } - } // TODO - FIXME - This is a big Workaround /** @@ -173,28 +136,32 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje */ fun loadEmojis() { EmojiRepository.init(this) - val currentServer = getCurrentServerInteractor.get() - currentServer?.let { server -> - GlobalScope.launch { - val client = factory.get(server) + runBlocking { + getCurrentServerInteractor.get()?.let { server -> EmojiRepository.setCurrentServerUrl(server) + val customEmojis = retryIO("getCustomEmojis()") { + factory.get(server).getCustomEmojis().update + } val customEmojiList = mutableListOf() 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 - )) + if (customEmojis != null) { + for (customEmoji in customEmojis) { + customEmojiList.add( + Emoji( + shortname = ":${customEmoji.name}:", + category = EmojiCategory.CUSTOM.name, + url = "$server/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) @@ -204,8 +171,3 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje } } } - -private fun LocalRepository.needOldMessagesCleanUp() = getBoolean(CLEANUP_OLD_MESSAGES_NEEDED, true) -private fun LocalRepository.setOldMessagesCleanedUp() = save(CLEANUP_OLD_MESSAGES_NEEDED, false) - -private const val CLEANUP_OLD_MESSAGES_NEEDED = "CLEANUP_OLD_MESSAGES_NEEDED" diff --git a/app/src/main/java/chat/rocket/android/authentication/di/AuthenticationModule.kt b/app/src/main/java/chat/rocket/android/authentication/di/AuthenticationModule.kt index 2dc436a27f..da73919453 100644 --- a/app/src/main/java/chat/rocket/android/authentication/di/AuthenticationModule.kt +++ b/app/src/main/java/chat/rocket/android/authentication/di/AuthenticationModule.kt @@ -19,7 +19,7 @@ class AuthenticationModule { @Provides @PerActivity - fun provideJob() = Job() + fun provideJob(): Job = Job() @Provides @PerActivity diff --git a/app/src/main/java/chat/rocket/android/authentication/server/ui/ServerFragment.kt b/app/src/main/java/chat/rocket/android/authentication/server/ui/ServerFragment.kt index eb8668ac58..32833d3c99 100644 --- a/app/src/main/java/chat/rocket/android/authentication/server/ui/ServerFragment.kt +++ b/app/src/main/java/chat/rocket/android/authentication/server/ui/ServerFragment.kt @@ -236,13 +236,13 @@ class ServerFragment : Fragment(), ServerView { override fun updateServerUrl(url: HttpUrl) { ui { - if (url.scheme() == "https") { + if (url.scheme == "https") { spinner_server_protocol.setSelection(0) } else { spinner_server_protocol.setSelection(1) } - protocol = "${url.scheme()}://" + protocol = "${url.scheme}://" text_server_url.textContent = url.toString().removePrefix(protocol) } } diff --git a/app/src/main/java/chat/rocket/android/chatinformation/di/MessageInfoFragmentModule.kt b/app/src/main/java/chat/rocket/android/chatinformation/di/MessageInfoFragmentModule.kt index bb5e55eb0c..0a7c8d784d 100644 --- a/app/src/main/java/chat/rocket/android/chatinformation/di/MessageInfoFragmentModule.kt +++ b/app/src/main/java/chat/rocket/android/chatinformation/di/MessageInfoFragmentModule.kt @@ -14,7 +14,7 @@ class MessageInfoFragmentModule { @Provides @PerFragment - fun provideJob() = Job() + fun provideJob(): Job = Job() @Provides @PerFragment diff --git a/app/src/main/java/chat/rocket/android/chatroom/di/ChatRoomModule.kt b/app/src/main/java/chat/rocket/android/chatroom/di/ChatRoomModule.kt index a013430044..84a27d4540 100644 --- a/app/src/main/java/chat/rocket/android/chatroom/di/ChatRoomModule.kt +++ b/app/src/main/java/chat/rocket/android/chatroom/di/ChatRoomModule.kt @@ -18,7 +18,7 @@ class ChatRoomModule { @Provides @PerActivity - fun provideJob() = Job() + fun provideJob(): Job = Job() @Provides @PerActivity diff --git a/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomNavigator.kt b/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomNavigator.kt index 96b1d39b9f..6beb72f056 100644 --- a/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomNavigator.kt +++ b/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomNavigator.kt @@ -37,7 +37,7 @@ class ChatRoomNavigator(internal val activity: ChatRoomActivity) { chatRoomType: String, isReadOnly: Boolean, chatRoomLastSeen: Long, - isSubscribed: Boolean, + isSubscribed: Boolean?, isCreator: Boolean, isFavorite: Boolean ) { @@ -127,7 +127,7 @@ class ChatRoomNavigator(internal val activity: ChatRoomActivity) { chatRoomType: String, isChatRoomReadOnly: Boolean, chatRoomLastSeen: Long, - isChatRoomSubscribed: Boolean, + isChatRoomSubscribed: Boolean?, isChatRoomCreator: Boolean, isChatRoomFavorite: Boolean, chatRoomMessage: String diff --git a/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt b/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt index 1b65510aa3..759d9b24fb 100644 --- a/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt +++ b/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt @@ -954,7 +954,7 @@ class ChatRoomPresenter @Inject constructor( it.type is RoomType.DirectMessage || it.type is RoomType.LiveChat } .map { chatRoom -> - val name = chatRoom.name + val name = chatRoom.name ?: "" val fullName = chatRoom.fullName ?: "" ChatRoomSuggestionUiModel( text = name, diff --git a/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt b/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt index 2af6fb6f95..59d8cc41b9 100644 --- a/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt +++ b/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt @@ -25,9 +25,9 @@ fun Context.chatRoomIntent( chatRoomId: String, chatRoomName: String, chatRoomType: String, - isReadOnly: Boolean, + isReadOnly: Boolean?, chatRoomLastSeen: Long, - isSubscribed: Boolean = true, + isSubscribed: Boolean? = true, isCreator: Boolean = false, isFavorite: Boolean = false, chatRoomMessage: String? = null diff --git a/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt b/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt index cfd01ed5a3..f4cbe9c8ea 100644 --- a/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt +++ b/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt @@ -47,6 +47,7 @@ import chat.rocket.core.model.url.Url import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.HttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import java.security.InvalidParameterException import java.util.* import java.util.Collections.emptyList @@ -415,9 +416,9 @@ class UiModelMapper @Inject constructor( title?.let { return it } url.filterNotNull().forEach { - val fileUrl = HttpUrl.parse(it) + val fileUrl = it.toHttpUrlOrNull() fileUrl?.let { httpUrl -> - return httpUrl.pathSegments().last() + return httpUrl.pathSegments.last() } } @@ -429,7 +430,7 @@ class UiModelMapper @Inject constructor( if (url.startsWith("http")) return url val fullUrl = "$baseUrl$url" - val httpUrl = HttpUrl.parse(fullUrl) + val httpUrl = fullUrl.toHttpUrlOrNull() httpUrl?.let { return it.newBuilder().apply { addQueryParameter("rc_uid", token?.userId) diff --git a/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomUiModelMapper.kt b/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomUiModelMapper.kt index 739f4adbc6..ba3431a181 100644 --- a/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomUiModelMapper.kt +++ b/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomUiModelMapper.kt @@ -14,12 +14,14 @@ import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useSpecialCharsOnRoom import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.date +import chat.rocket.android.util.extensions.isGreaterThan import chat.rocket.android.util.extensions.isNotNullNorEmpty import chat.rocket.android.util.extensions.localDateTime import chat.rocket.common.model.RoomType import chat.rocket.common.model.User import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.userStatusOf +import chat.rocket.common.util.ifNull import chat.rocket.core.model.Room import chat.rocket.core.model.SpotlightResult import ru.noties.markwon.Markwon @@ -101,7 +103,7 @@ class RoomUiModelMapper( RoomUiModel( id = id, name = name!!, - type = type, + type = type!!, avatar = serverUrl.avatarUrl(name!!, token?.userId, token?.authToken, isGroupOrChannel = true), lastMessage = if (showLastMessage) { mapLastMessage( @@ -121,7 +123,7 @@ class RoomUiModelMapper( fun map(chatRoom: ChatRoom, showLastMessage: Boolean = true): RoomUiModel = with(chatRoom.chatRoom) { - val isUnread = alert || unread > 0 + val isUnread = alert == true || unread.isGreaterThan(0) val type = roomTypeOf(type) val status = chatRoom.status?.let { userStatusOf(it) } val roomName = mapName(name, fullname) @@ -133,7 +135,7 @@ class RoomUiModelMapper( } else { serverUrl.avatarUrl(name, token?.userId, token?.authToken, isGroupOrChannel = true) } - val unread = mapUnread(unread) + val unread = unread?.let { mapUnread(it) } val lastMessage = if (showLastMessage) { mapLastMessage( lastMessageUserId, @@ -146,7 +148,6 @@ class RoomUiModelMapper( null } val hasMentions = mapMentions(userMentions, groupMentions) - val open = open val lastMessageMarkdown = lastMessage?.let { Markwon.markdown(context, it.toString()).toString() } diff --git a/app/src/main/java/chat/rocket/android/chatrooms/adapter/model/RoomUiModel.kt b/app/src/main/java/chat/rocket/android/chatrooms/adapter/model/RoomUiModel.kt index 4b536b3d4f..236f46847f 100644 --- a/app/src/main/java/chat/rocket/android/chatrooms/adapter/model/RoomUiModel.kt +++ b/app/src/main/java/chat/rocket/android/chatrooms/adapter/model/RoomUiModel.kt @@ -9,7 +9,7 @@ data class RoomUiModel( val type: RoomType, val name: CharSequence, val avatar: String, - val open: Boolean = false, + val open: Boolean? = false, val date: CharSequence? = null, val unread: String? = null, val alert: Boolean = false, diff --git a/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt b/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt index a5041928b8..48d97e409f 100644 --- a/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt +++ b/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt @@ -128,7 +128,7 @@ class ChatRoomsPresenter @Inject constructor( if (myself?.username == null) { view.showMessage(R.string.msg_generic_error) } else { - val id = if (isDirectMessage && !open) { + val id = if (isDirectMessage && open == false) { // If from local database, we already have the roomId, no need to concatenate if (local) { retryIO { diff --git a/app/src/main/java/chat/rocket/android/db/DatabaseManager.kt b/app/src/main/java/chat/rocket/android/db/DatabaseManager.kt index 5f28806fa5..2185f455ac 100644 --- a/app/src/main/java/chat/rocket/android/db/DatabaseManager.kt +++ b/app/src/main/java/chat/rocket/android/db/DatabaseManager.kt @@ -94,7 +94,7 @@ class DatabaseManager(val context: Application, val serverUrl: String, val token } suspend fun sendOperation(operation: Operation) { - Timber.d("writerChannel: $writeChannel, closedForSend: ${writeChannel.isClosedForSend}, closedForReceive: ${writeChannel.isClosedForReceive}, empty: ${writeChannel.isEmpty}, full: ${writeChannel.isFull}") + Timber.d("writerChannel: $writeChannel, closedForSend: ${writeChannel.isClosedForSend}, closedForReceive: ${writeChannel.isClosedForReceive}, empty: ${writeChannel.isEmpty}") writeChannel.send(operation) } @@ -552,7 +552,7 @@ class DatabaseManager(val context: Application, val serverUrl: String, val token subscriptionId = subscriptionId, parentId = parentId, type = type.toString(), - name = name, + name = name.toString(), fullname = fullName, userId = userId, ownerId = user?.id, diff --git a/app/src/main/java/chat/rocket/android/db/RCDatabase.kt b/app/src/main/java/chat/rocket/android/db/RCDatabase.kt index 78178a34a6..65a2e5b5c6 100644 --- a/app/src/main/java/chat/rocket/android/db/RCDatabase.kt +++ b/app/src/main/java/chat/rocket/android/db/RCDatabase.kt @@ -32,7 +32,7 @@ import chat.rocket.android.emoji.internal.db.StringListConverter ReactionEntity::class, MessagesSync::class ], - version = 13, + version = 14, exportSchema = true ) @TypeConverters(StringListConverter::class) diff --git a/app/src/main/java/chat/rocket/android/db/model/ChatRoomEntity.kt b/app/src/main/java/chat/rocket/android/db/model/ChatRoomEntity.kt index e709003705..5185f168ad 100644 --- a/app/src/main/java/chat/rocket/android/db/model/ChatRoomEntity.kt +++ b/app/src/main/java/chat/rocket/android/db/model/ChatRoomEntity.kt @@ -38,9 +38,9 @@ data class ChatRoomEntity( var topic: String? = null, var announcement: String? = null, var description: String? = null, - var open: Boolean = true, - var alert: Boolean = false, - var unread: Long = 0, + var open: Boolean? = true, + var alert: Boolean? = false, + var unread: Long? = 0, var userMentions: Long? = 0, var groupMentions: Long? = 0, var updatedAt: Long? = -1, diff --git a/app/src/main/java/chat/rocket/android/main/di/MainModule.kt b/app/src/main/java/chat/rocket/android/main/di/MainModule.kt index ab8819e171..ae65a1b1b5 100644 --- a/app/src/main/java/chat/rocket/android/main/di/MainModule.kt +++ b/app/src/main/java/chat/rocket/android/main/di/MainModule.kt @@ -25,7 +25,7 @@ class MainModule { @Provides @PerActivity - fun provideJob() = Job() + fun provideJob(): Job = Job() @Provides fun provideLifecycleOwner(activity: MainActivity): LifecycleOwner = activity diff --git a/app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt b/app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt index 983f55bd28..f6044a9467 100644 --- a/app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt +++ b/app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt @@ -70,9 +70,9 @@ class MainNavigator(internal val activity: MainActivity) { chatRoomId: String, chatRoomName: String, chatRoomType: String, - isReadOnly: Boolean, + isReadOnly: Boolean?, chatRoomLastSeen: Long, - isSubscribed: Boolean, + isSubscribed: Boolean?, isCreator: Boolean, isFavorite: Boolean ) { diff --git a/app/src/main/java/chat/rocket/android/push/PushInfo.kt b/app/src/main/java/chat/rocket/android/push/PushInfo.kt index 2f9d87c111..5622052b44 100644 --- a/app/src/main/java/chat/rocket/android/push/PushInfo.kt +++ b/app/src/main/java/chat/rocket/android/push/PushInfo.kt @@ -3,10 +3,9 @@ package chat.rocket.android.push import chat.rocket.common.model.RoomType import com.squareup.moshi.Json import se.ansman.kotshi.JsonSerializable -import se.ansman.kotshi.KotshiConstructor @JsonSerializable -data class PushInfo @KotshiConstructor constructor( +data class PushInfo constructor( @Json(name = "host") val hostname: String, @Json(name = "rid") val roomId: String, val type: RoomType, diff --git a/app/src/main/java/chat/rocket/android/push/PushSender.kt b/app/src/main/java/chat/rocket/android/push/PushSender.kt index b663352af7..556aac9646 100644 --- a/app/src/main/java/chat/rocket/android/push/PushSender.kt +++ b/app/src/main/java/chat/rocket/android/push/PushSender.kt @@ -2,10 +2,9 @@ package chat.rocket.android.push import com.squareup.moshi.Json import se.ansman.kotshi.JsonSerializable -import se.ansman.kotshi.KotshiConstructor @JsonSerializable -data class PushSender @KotshiConstructor constructor( +data class PushSender constructor( @Json(name = "_id") val id: String, val username: String?, val name: String? diff --git a/app/src/main/java/chat/rocket/android/server/di/ChangeServerModule.kt b/app/src/main/java/chat/rocket/android/server/di/ChangeServerModule.kt index bc0b67cb4d..7764b058e1 100644 --- a/app/src/main/java/chat/rocket/android/server/di/ChangeServerModule.kt +++ b/app/src/main/java/chat/rocket/android/server/di/ChangeServerModule.kt @@ -15,7 +15,7 @@ class ChangeServerModule { @Provides @PerActivity - fun provideJob() = Job() + fun provideJob(): Job = Job() @Provides @PerActivity diff --git a/app/src/main/java/chat/rocket/android/server/domain/ChatRoomsInteractor.kt b/app/src/main/java/chat/rocket/android/server/domain/ChatRoomsInteractor.kt index e57bbafb87..9b4dde8b0b 100644 --- a/app/src/main/java/chat/rocket/android/server/domain/ChatRoomsInteractor.kt +++ b/app/src/main/java/chat/rocket/android/server/domain/ChatRoomsInteractor.kt @@ -30,7 +30,7 @@ class ChatRoomsInteractor @Inject constructor(private val repository: ChatRoomsR return@withContext allChatRooms } return@withContext allChatRooms.filter { - it.name.contains(name, true) + it.name?.contains(name, true) == true } } diff --git a/app/src/main/java/chat/rocket/android/server/infrastructure/RocketChatClientFactory.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/RocketChatClientFactory.kt index 0c5ab18cbb..a35c2c9039 100644 --- a/app/src/main/java/chat/rocket/android/server/infrastructure/RocketChatClientFactory.kt +++ b/app/src/main/java/chat/rocket/android/server/infrastructure/RocketChatClientFactory.kt @@ -5,6 +5,7 @@ import chat.rocket.android.BuildConfig import chat.rocket.android.server.domain.TokenRepository import chat.rocket.common.util.PlatformLogger import chat.rocket.core.RocketChatClient +import chat.rocket.core.createRocketChatClient import okhttp3.OkHttpClient import timber.log.Timber import javax.inject.Inject @@ -24,7 +25,7 @@ class RocketChatClientFactory @Inject constructor( return it } - val client = RocketChatClient.create { + val client = createRocketChatClient { httpClient = okHttpClient restUrl = url userAgent = "RC Mobile; Android ${Build.VERSION.RELEASE}; v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" diff --git a/app/src/main/java/chat/rocket/android/settings/password/di/PasswordFragmentModule.kt b/app/src/main/java/chat/rocket/android/settings/password/di/PasswordFragmentModule.kt index 63c19b105a..9604945d08 100644 --- a/app/src/main/java/chat/rocket/android/settings/password/di/PasswordFragmentModule.kt +++ b/app/src/main/java/chat/rocket/android/settings/password/di/PasswordFragmentModule.kt @@ -14,7 +14,7 @@ class PasswordFragmentModule { @Provides @PerFragment - fun provideJob() = Job() + fun provideJob(): Job = Job() @Provides @PerFragment diff --git a/app/src/main/java/chat/rocket/android/util/AppJsonAdapterFactory.kt b/app/src/main/java/chat/rocket/android/util/AppJsonAdapterFactory.kt index 3393a04a4a..f5c4d450bf 100644 --- a/app/src/main/java/chat/rocket/android/util/AppJsonAdapterFactory.kt +++ b/app/src/main/java/chat/rocket/android/util/AppJsonAdapterFactory.kt @@ -6,6 +6,6 @@ import se.ansman.kotshi.KotshiJsonAdapterFactory @KotshiJsonAdapterFactory abstract class AppJsonAdapterFactory : JsonAdapter.Factory { companion object { - val INSTANCE: AppJsonAdapterFactory = KotshiAppJsonAdapterFactory() + val INSTANCE: AppJsonAdapterFactory = KotshiAppJsonAdapterFactory } } diff --git a/app/src/main/java/chat/rocket/android/util/BasicAuthenticatorInterceptor.kt b/app/src/main/java/chat/rocket/android/util/BasicAuthenticatorInterceptor.kt index 69d54288f1..0cfc9410b7 100644 --- a/app/src/main/java/chat/rocket/android/util/BasicAuthenticatorInterceptor.kt +++ b/app/src/main/java/chat/rocket/android/util/BasicAuthenticatorInterceptor.kt @@ -43,12 +43,12 @@ class BasicAuthenticatorInterceptor @Inject constructor ( @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { var request = chain.request() - val url = request.url() - val host = url.host() - val username = url.username() + val url = request.url + val host = url.host + val username = url.username if (!username.isNullOrEmpty()) { - saveCredentials(host, Credentials.basic(username, url.password())) + saveCredentials(host, Credentials.basic(username, url.password)) request = request.newBuilder().url( url.newBuilder().username("").password("").build() ).build() diff --git a/app/src/main/java/chat/rocket/android/util/HttpLoggingInterceptor.kt b/app/src/main/java/chat/rocket/android/util/HttpLoggingInterceptor.kt index 36a6c33771..3b67dd1050 100644 --- a/app/src/main/java/chat/rocket/android/util/HttpLoggingInterceptor.kt +++ b/app/src/main/java/chat/rocket/android/util/HttpLoggingInterceptor.kt @@ -6,7 +6,8 @@ import okhttp3.Interceptor import okhttp3.MediaType import okhttp3.OkHttpClient import okhttp3.Response -import okhttp3.internal.http.HttpHeaders +import okhttp3.internal.http.hasBody +import okhttp3.internal.http.promisesBody import okio.Buffer import okio.GzipSource import java.io.EOFException @@ -111,11 +112,11 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept val logBody = level == Level.BODY val logHeaders = logBody || level == Level.HEADERS - val requestBody = request.body() + val requestBody = request.body val hasRequestBody = requestBody != null val connection = chain.connection() - var requestStartMessage = ("--> ${request.method()} ${request.url()}" + var requestStartMessage = ("--> ${request.method} ${request.url}" + if (connection != null) " " + connection.protocol() else "") if (!logHeaders && hasRequestBody) { requestStartMessage += " (${requestBody!!.contentLength()}-byte body)" @@ -134,9 +135,9 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept } } - val headers = request.headers() + val headers = request.headers var i = 0 - val count = headers.size() + val count = headers.size while (i < count) { val name = headers.name(i) // Skip headers from the request body as they are explicitly logged above. @@ -151,11 +152,11 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept } if (!logBody || !hasRequestBody) { - logger.log("--> END ${request.method()}") - } else if (bodyHasUnknownEncoding(request.headers())) { - logger.log("--> END ${request.method()} (encoded body omitted)") + logger.log("--> END ${request.method}") + } else if (bodyHasUnknownEncoding(request.headers)) { + logger.log("--> END ${request.method} (encoded body omitted)") } else if (isMultipart(requestBody?.contentType())) {//requestBody?.contentType()?.toString()?.contains("multipart/form-data", ignoreCase = true)) { - logger.log("--> END ${request.method()} (multipart body omitted)") + logger.log("--> END ${request.method} (multipart body omitted)") } else if (hasRequestBody) { val buffer = Buffer() requestBody!!.writeTo(buffer) @@ -169,10 +170,10 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept logger.log("") if (isPlaintext(buffer)) { logger.log(buffer.readString(charset!!)) - logger.log("--> END " + request.method() + logger.log("--> END " + request.method + " (" + requestBody.contentLength() + "-byte body)") } else { - logger.log("--> END " + request.method() + " (binary " + logger.log("--> END " + request.method + " (binary " + requestBody.contentLength() + "-byte body omitted)") } } @@ -189,25 +190,25 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept val tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs) - val responseBody = response.body() + val responseBody = response.body val contentLength = responseBody!!.contentLength() val bodySize = if (contentLength != -1L) "$contentLength-byte" else "unknown-length" - val responseStr = if (response.message().isEmpty()) "" else " ${response.message()}" - logger.log("<-- ${response.code()}$responseStr ${response.request().url()}" + val responseStr = if (response.message.isEmpty()) "" else " ${response.message}" + logger.log("<-- ${response.code}$responseStr ${response.request.url}" + " (" + tookMs + "ms" + (if (!logHeaders) ", $bodySize body" else "") + ')'.toString()) if (logHeaders) { - val headers = response.headers() + val headers = response.headers var i = 0 - val count = headers.size() + val count = headers.size while (i < count) { logger.log(headers.name(i) + ": " + headers.value(i)) i++ } - if (!logBody || !HttpHeaders.hasBody(response)) { + if (!logBody || !response.promisesBody()) { logger.log("<-- END HTTP") - } else if (bodyHasUnknownEncoding(response.headers())) { + } else if (bodyHasUnknownEncoding(response.headers)) { logger.log("<-- END HTTP (encoded body omitted)") } else { val source = responseBody.source() @@ -216,7 +217,7 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept var gzippedLength: Long? = null if (headers.get("Content-Encoding")?.equals("gzip", ignoreCase = true) == true) { - gzippedLength = buffer.size() + gzippedLength = buffer.size var gzippedResponseBody: GzipSource? = null try { gzippedResponseBody = GzipSource(buffer.clone()) @@ -237,7 +238,7 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept if (!isPlaintext(buffer)) { logger.log("") - logger.log("<-- END HTTP (binary " + buffer.size() + "-byte body omitted)") + logger.log("<-- END HTTP (binary " + buffer.size + "-byte body omitted)") return response } @@ -247,10 +248,10 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept } if (gzippedLength != null) { - logger.log("<-- END HTTP (" + buffer.size() + "-byte, " + logger.log("<-- END HTTP (" + buffer.size + "-byte, " + gzippedLength + "-gzipped-byte body)") } else { - logger.log("<-- END HTTP (" + buffer.size() + "-byte body)") + logger.log("<-- END HTTP (" + buffer.size + "-byte body)") } } } @@ -287,7 +288,7 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept internal fun isPlaintext(buffer: Buffer): Boolean { try { val prefix = Buffer() - val byteCount = if (buffer.size() < 64) buffer.size() else 64 + val byteCount = if (buffer.size < 64) buffer.size else 64 buffer.copyTo(prefix, 0, byteCount) for (i in 0..15) { if (prefix.exhausted()) { diff --git a/app/src/main/java/chat/rocket/android/util/extensions/Numbers.kt b/app/src/main/java/chat/rocket/android/util/extensions/Numbers.kt index 0872b35d57..172fa7ea8a 100644 --- a/app/src/main/java/chat/rocket/android/util/extensions/Numbers.kt +++ b/app/src/main/java/chat/rocket/android/util/extensions/Numbers.kt @@ -6,4 +6,11 @@ fun Long?.localDateTime(): LocalDateTime? { return this?.let { DateTimeHelper.getLocalDateTime(it) } +} + +fun Long?.isGreaterThan(value: Int): Boolean { + this?.let { + return it > value + } + return false } \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/util/extensions/String.kt b/app/src/main/java/chat/rocket/android/util/extensions/String.kt index 78b2d9c846..4ed2d3224d 100644 --- a/app/src/main/java/chat/rocket/android/util/extensions/String.kt +++ b/app/src/main/java/chat/rocket/android/util/extensions/String.kt @@ -4,6 +4,7 @@ import android.graphics.Color import android.util.Patterns import chat.rocket.common.model.Token import okhttp3.HttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import timber.log.Timber fun String.removeTrailingSlash(): String { @@ -71,8 +72,8 @@ fun String.userId(userId: String?): String? { return userId?.let { this.replace(it, "") } } -fun String.lowercaseUrl(): String? = HttpUrl.parse(this)?.run { - newBuilder().scheme(scheme().toLowerCase()).build().toString() +fun String.lowercaseUrl(): String? = this.toHttpUrlOrNull()?.run { + newBuilder().scheme(scheme.toLowerCase()).build().toString() } fun String?.isNotNullNorEmpty(): Boolean = this != null && this.isNotEmpty() diff --git a/app/src/main/java/chat/rocket/android/videoconference/di/VideoConferenceModule.kt b/app/src/main/java/chat/rocket/android/videoconference/di/VideoConferenceModule.kt index 22bc6ea901..73b8060b2c 100644 --- a/app/src/main/java/chat/rocket/android/videoconference/di/VideoConferenceModule.kt +++ b/app/src/main/java/chat/rocket/android/videoconference/di/VideoConferenceModule.kt @@ -20,7 +20,7 @@ class VideoConferenceModule { @Provides @PerActivity - fun provideJob() = Job() + fun provideJob(): Job = Job() @Provides @PerActivity diff --git a/dependencies.gradle b/dependencies.gradle index acee7fa47d..8db5e27c37 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -9,8 +9,8 @@ ext { dokka : '0.9.16', // For app - kotlin : '1.3.41', - coroutine : '1.1.1', + kotlin : '1.3.50', + coroutine : '1.3.1', appCompat : '1.0.2', recyclerview : '1.0.0', @@ -34,7 +34,7 @@ ext { rxAndroid : '2.1.0', moshi : '1.8.0', - okhttp : '3.12.1', + okhttp : '4.2.0', timber : '4.7.1', threeTenABP : '1.1.0', @@ -42,7 +42,7 @@ ext { fresco : '1.10.0', - kotshi : '1.0.6', + kotshi : '2.0.1', frescoImageViewer : '0.5.1', diff --git a/draw/src/main/java/chat/rocket/android/draw/main/di/DrawModule.kt b/draw/src/main/java/chat/rocket/android/draw/main/di/DrawModule.kt index bb159a7e06..4ca08ef323 100644 --- a/draw/src/main/java/chat/rocket/android/draw/main/di/DrawModule.kt +++ b/draw/src/main/java/chat/rocket/android/draw/main/di/DrawModule.kt @@ -15,7 +15,7 @@ class DrawModule { fun provideMainView(activity: DrawingActivity): DrawView = activity @Provides - fun provideJob() = Job() + fun provideJob(): Job = Job() @Provides fun provideLifecycleOwner(activity: DrawingActivity): LifecycleOwner = activity diff --git a/emoji/schemas/chat.rocket.android.emoji.internal.db.EmojiDatabase/1.json b/emoji/schemas/chat.rocket.android.emoji.internal.db.EmojiDatabase/1.json index 151b5cd75d..7774fc0a27 100644 --- a/emoji/schemas/chat.rocket.android.emoji.internal.db.EmojiDatabase/1.json +++ b/emoji/schemas/chat.rocket.android.emoji.internal.db.EmojiDatabase/1.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 1, - "identityHash": "5d591429a85289a5fe608ab2c4d77b0b", + "identityHash": "0b9c384faa4daef62de6f9b9f321696a", "entities": [ { "tableName": "Emoji", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`shortname` TEXT NOT NULL, `shortnameAlternates` TEXT NOT NULL, `unicode` TEXT NOT NULL, `category` TEXT NOT NULL, `count` INTEGER NOT NULL, `siblings` TEXT NOT NULL, `fitzpatrick` TEXT NOT NULL, `url` TEXT, `isDefault` INTEGER NOT NULL, PRIMARY KEY(`shortname`))", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`shortname` TEXT NOT NULL, `shortnameAlternates` TEXT, `unicode` TEXT NOT NULL, `category` TEXT NOT NULL, `count` INTEGER NOT NULL, `siblings` TEXT NOT NULL, `fitzpatrick` TEXT NOT NULL, `url` TEXT, `isDefault` INTEGER NOT NULL, PRIMARY KEY(`shortname`))", "fields": [ { "fieldPath": "shortname", @@ -18,7 +18,7 @@ "fieldPath": "shortnameAlternates", "columnName": "shortnameAlternates", "affinity": "TEXT", - "notNull": true + "notNull": false }, { "fieldPath": "unicode", @@ -75,7 +75,7 @@ ], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"5d591429a85289a5fe608ab2c4d77b0b\")" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"0b9c384faa4daef62de6f9b9f321696a\")" ] } } \ No newline at end of file diff --git a/emoji/src/main/java/chat/rocket/android/emoji/Emoji.kt b/emoji/src/main/java/chat/rocket/android/emoji/Emoji.kt index 49e753f911..d8768f38c0 100644 --- a/emoji/src/main/java/chat/rocket/android/emoji/Emoji.kt +++ b/emoji/src/main/java/chat/rocket/android/emoji/Emoji.kt @@ -8,9 +8,9 @@ import androidx.room.PrimaryKey data class Emoji( @PrimaryKey var shortname: String = "", - var shortnameAlternates: List = listOf(), + var shortnameAlternates: List? = listOf(), var unicode: String = "", - @Ignore val keywords: List = listOf(), + @Ignore val keywords: List? = listOf(), var category: String = "", var count: Int = 0, var siblings: MutableList = mutableListOf(), // Siblings are the same emoji with different skin tones. diff --git a/emoji/src/main/java/chat/rocket/android/emoji/EmojiParser.kt b/emoji/src/main/java/chat/rocket/android/emoji/EmojiParser.kt index b77dd4c9c6..4c24d810c0 100644 --- a/emoji/src/main/java/chat/rocket/android/emoji/EmojiParser.kt +++ b/emoji/src/main/java/chat/rocket/android/emoji/EmojiParser.kt @@ -134,7 +134,7 @@ class EmojiParser { if (it.shortname == text) { return true } else { - it.shortnameAlternates.forEach { + it.shortnameAlternates?.forEach { if (":$it:" == text) { return true } diff --git a/emoji/src/main/java/chat/rocket/android/emoji/EmojiRepository.kt b/emoji/src/main/java/chat/rocket/android/emoji/EmojiRepository.kt index bf339883b0..18dfc580de 100644 --- a/emoji/src/main/java/chat/rocket/android/emoji/EmojiRepository.kt +++ b/emoji/src/main/java/chat/rocket/android/emoji/EmojiRepository.kt @@ -110,7 +110,7 @@ object EmojiRepository { shortNameToUnicode.apply { put(emoji.shortname, unicode) - emoji.shortnameAlternates.forEach { alternate -> put(alternate, unicode) } + emoji.shortnameAlternates?.forEach { alternate -> put(alternate, unicode) } } } From 43bf1b172c26a88bb1184a3ead2f505074d6d72d Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Thu, 19 Sep 2019 16:16:03 -0300 Subject: [PATCH 10/19] Fix sending empty message when replying of quoting --- .../rocket/android/chatroom/ui/ChatRoomFragment.kt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt b/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt index 72f123b008..911c5d341c 100644 --- a/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt +++ b/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt @@ -474,12 +474,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR override fun sendMessage(text: String) { ui { if (!text.isBlank()) { - if (text.startsWith("/")) { - presenter.runCommand(text, chatRoomId) - } else if (text.startsWith("+")) { - presenter.reactToLastMessage(text, chatRoomId) - } else { - presenter.sendMessage(chatRoomId, text, editingMessageId) + when { + text.startsWith("/") -> presenter.runCommand(text, chatRoomId) + text.startsWith("+") -> presenter.reactToLastMessage(text, chatRoomId) + else -> presenter.sendMessage(chatRoomId, text, editingMessageId) } } } @@ -932,7 +930,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR button_send.setOnClickListener { text_message.textContent.run { if(this.isNotBlank()) { - sendMessage(citation ?: "" + this) + sendMessage((citation ?: "") + this) } } } From 364852a8f74228830e7bc0dfb09c4cf1ae1263a8 Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Thu, 19 Sep 2019 17:10:06 -0300 Subject: [PATCH 11/19] Injects RocketChatClientFactory on PushManager from AppModule.kt --- .../java/chat/rocket/android/dagger/module/AppModule.kt | 9 +++++++-- .../main/java/chat/rocket/android/push/PushManager.kt | 4 ++-- .../android/push/di/FirebaseMessagingServiceProvider.kt | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt b/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt index a397ec1bd2..c45d576d1d 100644 --- a/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt +++ b/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt @@ -17,6 +17,7 @@ import chat.rocket.android.authentication.infrastructure.SharedPreferencesTokenR import chat.rocket.android.chatroom.service.MessageService import chat.rocket.android.dagger.qualifier.ForAuthentication import chat.rocket.android.dagger.qualifier.ForMessages +import chat.rocket.android.dagger.scope.PerFragment import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManagerFactory import chat.rocket.android.dynamiclinks.DynamicLinksForFirebase @@ -52,6 +53,7 @@ import chat.rocket.android.server.infrastructure.DatabaseMessagesRepository import chat.rocket.android.server.infrastructure.JobSchedulerInteractorImpl import chat.rocket.android.server.infrastructure.MemoryChatRoomsRepository import chat.rocket.android.server.infrastructure.MemoryUsersRepository +import chat.rocket.android.server.infrastructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.SharedPreferencesAccountsRepository import chat.rocket.android.server.infrastructure.SharedPreferencesPermissionsRepository import chat.rocket.android.server.infrastructure.SharedPreferencesSettingsRepository @@ -70,6 +72,7 @@ import chat.rocket.common.model.TimestampAdapter import chat.rocket.common.util.CalendarISO8601Converter import chat.rocket.common.util.NoOpLogger import chat.rocket.common.util.PlatformLogger +import chat.rocket.core.RocketChatClient import chat.rocket.core.internal.AttachmentAdapterFactory import chat.rocket.core.internal.ReactionsAdapter import com.facebook.drawee.backends.pipeline.DraweeConfig @@ -343,7 +346,8 @@ class AppModule { moshi: Moshi, getAccountInteractor: GetAccountInteractor, getSettingsInteractor: GetSettingsInteractor, - currentServerInteractor: GetCurrentServerInteractor + currentServerInteractor: GetCurrentServerInteractor, + factory: RocketChatClientFactory ): PushManager { return PushManager( groupedPushes, @@ -352,7 +356,8 @@ class AppModule { getAccountInteractor, getSettingsInteractor, context, - currentServerInteractor + currentServerInteractor, + factory ) } diff --git a/app/src/main/java/chat/rocket/android/push/PushManager.kt b/app/src/main/java/chat/rocket/android/push/PushManager.kt index f78fc3e044..74b3568dff 100644 --- a/app/src/main/java/chat/rocket/android/push/PushManager.kt +++ b/app/src/main/java/chat/rocket/android/push/PushManager.kt @@ -43,9 +43,9 @@ class PushManager @Inject constructor( private val getAccountInteractor: GetAccountInteractor, private val getSettingsInteractor: GetSettingsInteractor, private val context: Context, - private val serverInteractor: GetCurrentServerInteractor + private val serverInteractor: GetCurrentServerInteractor, + private val factory: RocketChatClientFactory ) { - @Inject lateinit var factory: RocketChatClientFactory private val random = Random() fun registerPushNotificationToken(token: String) = GlobalScope.launch(Dispatchers.IO) { diff --git a/app/src/play/java/chat/rocket/android/push/di/FirebaseMessagingServiceProvider.kt b/app/src/play/java/chat/rocket/android/push/di/FirebaseMessagingServiceProvider.kt index 22bf31fe42..58123706f2 100644 --- a/app/src/play/java/chat/rocket/android/push/di/FirebaseMessagingServiceProvider.kt +++ b/app/src/play/java/chat/rocket/android/push/di/FirebaseMessagingServiceProvider.kt @@ -9,5 +9,5 @@ import dagger.android.ContributesAndroidInjector abstract class FirebaseMessagingServiceProvider { @ContributesAndroidInjector(modules = [AppModule::class]) - abstract fun provideFirebaseMessagingService(): RocketChatMessagingService + abstract fun provideRocketChatMessagingService(): RocketChatMessagingService } \ No newline at end of file From 892b7fb98179a60909346dd567d44f80a5961016 Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Thu, 19 Sep 2019 17:13:14 -0300 Subject: [PATCH 12/19] Update app version --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index d1f6656949..eadd851b5d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,7 +18,7 @@ android { applicationId "chat.rocket.android" minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk - versionCode 2078 + versionCode 2079 versionName "3.5.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true From 7938d64f8f1df9846305392f74234690af863dee Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Mon, 23 Sep 2019 18:04:45 -0300 Subject: [PATCH 13/19] Fixes the wrong parameter order. --- .../login/presentation/LoginPresenter.kt | 17 +++++++++-------- .../presentation/LoginOptionsPresenter.kt | 16 ++++++++-------- .../presentation/RegisterUsernamePresenter.kt | 16 ++++++++-------- .../signup/presentation/SignupPresenter.kt | 16 ++++++++-------- .../twofactor/presentation/TwoFAPresenter.kt | 16 ++++++++-------- .../android/main/presentation/MainPresenter.kt | 17 +++++++++-------- 6 files changed, 50 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt index 3d2c8ecdf8..d06b52ef2b 100644 --- a/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt @@ -144,15 +144,16 @@ class LoginPresenter @Inject constructor( } val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken) val account = Account( - settings.siteName() ?: currentServer, - currentServer, - icon, - logo, - username, - thumb, - token?.userId, - token?.authToken + serverName = settings.siteName() ?: currentServer, + serverUrl = currentServer, + serverLogoUrl = icon, + serverBackgroundImageUrl = logo, + userName = username, + userAvatarUrl = thumb, + authToken = token?.authToken, + userId = token?.userId ) + saveAccountInteractor.save(account) } diff --git a/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt index 06d4e6fcb4..a6373c68fa 100644 --- a/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt @@ -185,14 +185,14 @@ class LoginOptionsPresenter @Inject constructor( } val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken) val account = Account( - settings.siteName() ?: currentServer, - currentServer, - icon, - logo, - username, - thumb, - token?.userId, - token?.authToken + serverName = settings.siteName() ?: currentServer, + serverUrl = currentServer, + serverLogoUrl = icon, + serverBackgroundImageUrl = logo, + userName = username, + userAvatarUrl = thumb, + authToken = token?.authToken, + userId = token?.userId ) saveAccountInteractor.save(account) } diff --git a/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt b/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt index a39790f5c6..56106b2bbc 100644 --- a/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt @@ -83,14 +83,14 @@ class RegisterUsernamePresenter @Inject constructor( } val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken) val account = Account( - settings.siteName() ?: currentServer, - currentServer, - icon, - logo, - username, - thumb, - token?.userId, - token?.authToken + serverName = settings.siteName() ?: currentServer, + serverUrl = currentServer, + serverLogoUrl = icon, + serverBackgroundImageUrl = logo, + userName = username, + userAvatarUrl = thumb, + authToken = token?.authToken, + userId = token?.userId ) saveAccountInteractor.save(account) } diff --git a/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt index 3c0d9014e1..702c4da511 100644 --- a/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt @@ -104,14 +104,14 @@ class SignupPresenter @Inject constructor( } val thumb = currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken) val account = Account( - settings.siteName() ?: currentServer, - currentServer, - icon, - logo, - me.username!!, - thumb, - token?.userId, - token?.authToken + serverName = settings.siteName() ?: currentServer, + serverUrl = currentServer, + serverLogoUrl = icon, + serverBackgroundImageUrl = logo, + userName = me.username!!, + userAvatarUrl = thumb, + authToken = token?.authToken, + userId = token?.userId ) saveAccountInteractor.save(account) } diff --git a/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt index 107f12eb03..72d9eaa948 100644 --- a/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt +++ b/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt @@ -105,14 +105,14 @@ class TwoFAPresenter @Inject constructor( } val thumb = currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken) val account = Account( - settings.siteName() ?: currentServer, - currentServer, - icon, - logo, - me.username!!, - thumb, - token?.userId, - token?.authToken + serverName = settings.siteName() ?: currentServer, + serverUrl = currentServer, + serverLogoUrl = icon, + serverBackgroundImageUrl = logo, + userName = me.username!!, + userAvatarUrl = thumb, + authToken = token?.authToken, + userId = token?.userId ) saveAccountInteractor.save(account) } diff --git a/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt b/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt index 288af9e0b3..1fb2093117 100644 --- a/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt +++ b/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt @@ -85,15 +85,16 @@ class MainPresenter @Inject constructor( ) val account = Account( - siteName() ?: currentServer, - currentServer, - icon, - logo, - userHelper.username() ?: "", - thumb, - token?.userId, - token?.authToken + serverName = siteName() ?: currentServer, + serverUrl = currentServer, + serverLogoUrl = icon, + serverBackgroundImageUrl = logo, + userName = userHelper.username() ?: "", + userAvatarUrl = thumb, + authToken = token?.authToken, + userId = token?.userId ) + saveAccountInteractor.save(account) } } From 49ba6a6a6aa87b8e978ebd8b63787b18a6033a3d Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Tue, 24 Sep 2019 11:03:14 -0300 Subject: [PATCH 14/19] Update schema version --- .../chat.rocket.android.db.RCDatabase/15.json | 1117 +++++++++++++++++ .../java/chat/rocket/android/db/RCDatabase.kt | 2 +- 2 files changed, 1118 insertions(+), 1 deletion(-) create mode 100644 app/schemas/chat.rocket.android.db.RCDatabase/15.json diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/15.json b/app/schemas/chat.rocket.android.db.RCDatabase/15.json new file mode 100644 index 0000000000..95eed60122 --- /dev/null +++ b/app/schemas/chat.rocket.android.db.RCDatabase/15.json @@ -0,0 +1,1117 @@ +{ + "formatVersion": 1, + "database": { + "version": 15, + "identityHash": "c7462d4b4f9ad32f9d8d2e53a7abd535", + "entities": [ + { + "tableName": "users", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "REAL", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_users_username", + "unique": false, + "columnNames": [ + "username" + ], + "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "chatrooms", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `parentId` TEXT, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `topic` TEXT, `announcement` TEXT, `description` TEXT, `open` INTEGER, `alert` INTEGER, `unread` INTEGER, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, `muted` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subscriptionId", + "columnName": "subscriptionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fullname", + "columnName": "fullname", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "ownerId", + "columnName": "ownerId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "readonly", + "columnName": "readonly", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isDefault", + "columnName": "isDefault", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "favorite", + "columnName": "favorite", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "topic", + "columnName": "topic", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "announcement", + "columnName": "announcement", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "open", + "columnName": "open", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "alert", + "columnName": "alert", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "userMentions", + "columnName": "userMentions", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "groupMentions", + "columnName": "groupMentions", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastSeen", + "columnName": "lastSeen", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastMessageText", + "columnName": "lastMessageText", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastMessageUserId", + "columnName": "lastMessageUserId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastMessageTimestamp", + "columnName": "lastMessageTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "broadcast", + "columnName": "broadcast", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "muted", + "columnName": "muted", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_chatrooms_userId", + "unique": false, + "columnNames": [ + "userId" + ], + "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)" + }, + { + "name": "index_chatrooms_ownerId", + "unique": false, + "columnNames": [ + "ownerId" + ], + "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)" + }, + { + "name": "index_chatrooms_subscriptionId", + "unique": true, + "columnNames": [ + "subscriptionId" + ], + "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)" + }, + { + "name": "index_chatrooms_updatedAt", + "unique": false, + "columnNames": [ + "updatedAt" + ], + "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)" + }, + { + "name": "index_chatrooms_lastMessageUserId", + "unique": false, + "columnNames": [ + "lastMessageUserId" + ], + "createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)" + } + ], + "foreignKeys": [ + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "ownerId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "userId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "lastMessageUserId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roomId` TEXT NOT NULL, `message` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `senderId` TEXT, `updatedAt` INTEGER, `editedAt` INTEGER, `editedBy` TEXT, `senderAlias` TEXT, `avatar` TEXT, `type` TEXT, `groupable` INTEGER NOT NULL, `parseUrls` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `role` TEXT, `synced` INTEGER NOT NULL, `unread` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`senderId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`editedBy`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomId", + "columnName": "roomId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "senderId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "editedAt", + "columnName": "editedAt", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "editedBy", + "columnName": "editedBy", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "senderAlias", + "columnName": "senderAlias", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "avatar", + "columnName": "avatar", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "groupable", + "columnName": "groupable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parseUrls", + "columnName": "parseUrls", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "synced", + "columnName": "synced", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "senderId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "editedBy" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "message_favorites", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "messageId", + "userId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "messageId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "userId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "message_mentions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "messageId", + "userId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "messageId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "users", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "userId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "message_channels", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `roomId` TEXT NOT NULL, `roomName` TEXT, PRIMARY KEY(`messageId`, `roomId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomId", + "columnName": "roomId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomName", + "columnName": "roomName", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "messageId", + "roomId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "messageId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "attachments", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` TEXT NOT NULL, `message_id` TEXT NOT NULL, `title` TEXT, `type` TEXT, `description` TEXT, `text` TEXT, `author_name` TEXT, `author_icon` TEXT, `author_link` TEXT, `thumb_url` TEXT, `color` TEXT, `fallback` TEXT, `title_link` TEXT, `title_link_download` INTEGER NOT NULL, `image_url` TEXT, `image_type` TEXT, `image_size` INTEGER, `video_url` TEXT, `video_type` TEXT, `video_size` INTEGER, `audio_url` TEXT, `audio_type` TEXT, `audio_size` INTEGER, `message_link` TEXT, `timestamp` INTEGER, `has_actions` INTEGER NOT NULL, `has_fields` INTEGER NOT NULL, `button_alignment` TEXT, PRIMARY KEY(`_id`), FOREIGN KEY(`message_id`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "_id", + "columnName": "_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "authorName", + "columnName": "author_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "authorIcon", + "columnName": "author_icon", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "authorLink", + "columnName": "author_link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbUrl", + "columnName": "thumb_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "fallback", + "columnName": "fallback", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "titleLink", + "columnName": "title_link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "titleLinkDownload", + "columnName": "title_link_download", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "imageUrl", + "columnName": "image_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "imageType", + "columnName": "image_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "imageSize", + "columnName": "image_size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "videoUrl", + "columnName": "video_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "videoType", + "columnName": "video_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "videoSize", + "columnName": "video_size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "audioUrl", + "columnName": "audio_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "audioType", + "columnName": "audio_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "audioSize", + "columnName": "audio_size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "messageLink", + "columnName": "message_link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "hasActions", + "columnName": "has_actions", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasFields", + "columnName": "has_fields", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "buttonAlignment", + "columnName": "button_alignment", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "_id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "message_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "attachment_fields", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `title` TEXT NOT NULL, `value` TEXT NOT NULL, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "attachmentId", + "columnName": "attachmentId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_attachment_fields_attachmentId", + "unique": false, + "columnNames": [ + "attachmentId" + ], + "createSql": "CREATE INDEX `index_attachment_fields_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)" + } + ], + "foreignKeys": [ + { + "table": "attachments", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "attachmentId" + ], + "referencedColumns": [ + "_id" + ] + } + ] + }, + { + "tableName": "attachment_action", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `type` TEXT NOT NULL, `text` TEXT, `url` TEXT, `isWebView` INTEGER, `webViewHeightRatio` TEXT, `imageUrl` TEXT, `message` TEXT, `isMessageInChatWindow` INTEGER, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "attachmentId", + "columnName": "attachmentId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isWebView", + "columnName": "isWebView", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "webViewHeightRatio", + "columnName": "webViewHeightRatio", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isMessageInChatWindow", + "columnName": "isMessageInChatWindow", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_attachment_action_attachmentId", + "unique": false, + "columnNames": [ + "attachmentId" + ], + "createSql": "CREATE INDEX `index_attachment_action_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)" + } + ], + "foreignKeys": [ + { + "table": "attachments", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "attachmentId" + ], + "referencedColumns": [ + "_id" + ] + } + ] + }, + { + "tableName": "urls", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`urlId` INTEGER PRIMARY KEY AUTOINCREMENT, `messageId` TEXT NOT NULL, `url` TEXT NOT NULL, `hostname` TEXT, `title` TEXT, `description` TEXT, `imageUrl` TEXT, FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "urlId", + "columnName": "urlId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hostname", + "columnName": "hostname", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "urlId" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_urls_messageId", + "unique": false, + "columnNames": [ + "messageId" + ], + "createSql": "CREATE INDEX `index_urls_messageId` ON `${TABLE_NAME}` (`messageId`)" + } + ], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "messageId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "reactions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `messageId` TEXT NOT NULL, `count` INTEGER NOT NULL, `usernames` TEXT NOT NULL, `names` TEXT NOT NULL, PRIMARY KEY(`reaction`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "reaction", + "columnName": "reaction", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usernames", + "columnName": "usernames", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "names", + "columnName": "names", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "reaction" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_reactions_messageId", + "unique": false, + "columnNames": [ + "messageId" + ], + "createSql": "CREATE INDEX `index_reactions_messageId` ON `${TABLE_NAME}` (`messageId`)" + } + ], + "foreignKeys": [ + { + "table": "messages", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "messageId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "messages_sync", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`roomId` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`roomId`))", + "fields": [ + { + "fieldPath": "roomId", + "columnName": "roomId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "roomId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"c7462d4b4f9ad32f9d8d2e53a7abd535\")" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/rocket/android/db/RCDatabase.kt b/app/src/main/java/chat/rocket/android/db/RCDatabase.kt index 65a2e5b5c6..2e177f94aa 100644 --- a/app/src/main/java/chat/rocket/android/db/RCDatabase.kt +++ b/app/src/main/java/chat/rocket/android/db/RCDatabase.kt @@ -32,7 +32,7 @@ import chat.rocket.android.emoji.internal.db.StringListConverter ReactionEntity::class, MessagesSync::class ], - version = 14, + version = 15, exportSchema = true ) @TypeConverters(StringListConverter::class) From 74c65f4a0339d42e5cf8544906a920822cc54a1f Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Tue, 24 Sep 2019 11:03:38 -0300 Subject: [PATCH 15/19] Change event name (the previous one is reserved). --- .../play/java/chat/rocket/android/analytics/AnswersAnalytics.kt | 2 +- .../chat/rocket/android/analytics/GoogleAnalyticsForFirebase.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/play/java/chat/rocket/android/analytics/AnswersAnalytics.kt b/app/src/play/java/chat/rocket/android/analytics/AnswersAnalytics.kt index 1ef131431c..bf880445d6 100644 --- a/app/src/play/java/chat/rocket/android/analytics/AnswersAnalytics.kt +++ b/app/src/play/java/chat/rocket/android/analytics/AnswersAnalytics.kt @@ -30,7 +30,7 @@ class AnswersAnalytics : Analytics { override fun logScreenView(event: ScreenViewEvent) = Answers.getInstance() - .logCustom(CustomEvent("screen_view").putCustomAttribute("screen", event.screenName)) + .logCustom(CustomEvent("screen_visualization").putCustomAttribute("screen", event.screenName)) override fun logMessageSent(event: SubscriptionTypeEvent, serverUrl: String) = diff --git a/app/src/play/java/chat/rocket/android/analytics/GoogleAnalyticsForFirebase.kt b/app/src/play/java/chat/rocket/android/analytics/GoogleAnalyticsForFirebase.kt index b0ca82c7c0..9ed55f8b19 100644 --- a/app/src/play/java/chat/rocket/android/analytics/GoogleAnalyticsForFirebase.kt +++ b/app/src/play/java/chat/rocket/android/analytics/GoogleAnalyticsForFirebase.kt @@ -28,7 +28,7 @@ class GoogleAnalyticsForFirebase @Inject constructor(val context: Context) : } override fun logScreenView(event: ScreenViewEvent) { - firebaseAnalytics.logEvent("screen_view", Bundle(1).apply { + firebaseAnalytics.logEvent("screen_visualization", Bundle(1).apply { putString("screen", event.screenName) }) } From b7520e48ab5e8126cbf5b69eac76749c6475b38b Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Tue, 24 Sep 2019 11:03:51 -0300 Subject: [PATCH 16/19] Update app version code. --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index eadd851b5d..fa95dbac5f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,7 +18,7 @@ android { applicationId "chat.rocket.android" minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk - versionCode 2079 + versionCode 2080 versionName "3.5.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true From 80a0d4358826ee0b67fb3bd8d354ce590b919753 Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Tue, 24 Sep 2019 11:33:01 -0300 Subject: [PATCH 17/19] Update library versions. --- .../rocket/android/dynamiclinks/DynamicLinks.kt | 2 +- .../settings/presentation/SettingsPresenter.kt | 6 ++++-- .../dynamiclinks/DynamicLinksForFirebase.kt | 2 +- dependencies.gradle | 14 +++++++------- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/chat/rocket/android/dynamiclinks/DynamicLinks.kt b/app/src/main/java/chat/rocket/android/dynamiclinks/DynamicLinks.kt index 582ea8d993..2576c663c3 100644 --- a/app/src/main/java/chat/rocket/android/dynamiclinks/DynamicLinks.kt +++ b/app/src/main/java/chat/rocket/android/dynamiclinks/DynamicLinks.kt @@ -7,5 +7,5 @@ interface DynamicLinks { fun getDynamicLink(intent: Intent, deepLinkCallback: (Uri?) -> Unit? ) - fun createDynamicLink(username: String?, server: String, deepLinkCallback: (String?) -> Unit?) + fun createDynamicLink(username: String, server: String, deepLinkCallback: (String?) -> Unit?) } diff --git a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt index 26e6596b63..4ed16fe5ee 100644 --- a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt +++ b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt @@ -153,8 +153,10 @@ class SettingsPresenter @Inject constructor( view.openShareApp(returnedString) } - currentServer?.let { - dynamicLinksManager.createDynamicLink(me.username, it, deepLinkCallback) + currentServer?.let { currentServer -> + me.username?.let { username -> + dynamicLinksManager.createDynamicLink(username, currentServer, deepLinkCallback) + } } } } diff --git a/app/src/play/java/chat/rocket/android/dynamiclinks/DynamicLinksForFirebase.kt b/app/src/play/java/chat/rocket/android/dynamiclinks/DynamicLinksForFirebase.kt index 4b7a07aedf..036a4ea1d6 100644 --- a/app/src/play/java/chat/rocket/android/dynamiclinks/DynamicLinksForFirebase.kt +++ b/app/src/play/java/chat/rocket/android/dynamiclinks/DynamicLinksForFirebase.kt @@ -28,7 +28,7 @@ class DynamicLinksForFirebase @Inject constructor(private var context: Context) } override fun createDynamicLink( - username: String?, + username: String, server: String, deepLinkCallback: (String?) -> Unit? ) { diff --git a/dependencies.gradle b/dependencies.gradle index 8db5e27c37..88c7908b99 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -57,11 +57,11 @@ ext { // Proprietary libraries firebaseCloudMessage : '20.0.0', - firebaseAnalytics : '17.0.0', - firebaseCrashlytics : '2.10.1@aar', + firebaseAnalytics : '17.2.0', + firebaseCrashlytics : '2.10.1', + firebaseDynamicLinks : '19.0.0', + playServicesAuth : '17.0.0', firebaseAnswers : '1.4.7@aar', - firebaseDynamicLinks : '18.0.0', - playServicesAuth : '16.0.1', // For testing junit : '4.12', @@ -134,11 +134,11 @@ ext { // Proprietary libraries fcm : "com.google.firebase:firebase-messaging:${versions.firebaseCloudMessage}", - firebaseAnalytics : "com.google.firebase:firebase-core:${versions.firebaseAnalytics}", - firebaseCrashlytics : "com.crashlytics.sdk.android:crashlytics:${versions.firebaseCrashlytics}", - firebaseAnswers : "com.crashlytics.sdk.android:answers:${versions.firebaseAnswers}", + firebaseAnalytics : "com.google.firebase:firebase-analytics:${versions.firebaseAnalytics}", dynamiclinks : "com.google.firebase:firebase-dynamic-links:${versions.firebaseDynamicLinks}", playServicesAuth : "com.google.android.gms:play-services-auth:${versions.playServicesAuth}", + firebaseCrashlytics : "com.crashlytics.sdk.android:crashlytics:${versions.firebaseCrashlytics}", + firebaseAnswers : "com.crashlytics.sdk.android:answers:${versions.firebaseAnswers}", // For testing junit : "junit:junit:${versions.junit}", From c4181f67437756d8e83b49945920c41fca07cd6d Mon Sep 17 00:00:00 2001 From: Filipe Brito Date: Tue, 24 Sep 2019 11:41:38 -0300 Subject: [PATCH 18/19] Update DynamicLinksForFirebase.kt --- .../android/dynamiclinks/DynamicLinksForFirebase.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/foss/java/chat/rocket/android/dynamiclinks/DynamicLinksForFirebase.kt b/app/src/foss/java/chat/rocket/android/dynamiclinks/DynamicLinksForFirebase.kt index a78c0da247..276530af8e 100644 --- a/app/src/foss/java/chat/rocket/android/dynamiclinks/DynamicLinksForFirebase.kt +++ b/app/src/foss/java/chat/rocket/android/dynamiclinks/DynamicLinksForFirebase.kt @@ -7,11 +7,15 @@ import javax.inject.Inject class DynamicLinksForFirebase @Inject constructor(private val context: Context) : DynamicLinks { - override fun getDynamicLink(intent: Intent, deepLinkCallback: (Uri?) -> Unit? ) { + override fun getDynamicLink(intent: Intent, deepLinkCallback: (Uri?) -> Unit?) { deepLinkCallback(null) } - override fun createDynamicLink(username: String?, server: String, deepLinkCallback: (String?) -> Unit?) { + override fun createDynamicLink( + username: String, + server: String, + deepLinkCallback: (String?) -> Unit? + ) { deepLinkCallback(null) } } From f394b3dcff3f065bead1958825f865f72532a88e Mon Sep 17 00:00:00 2001 From: SingLi Date: Tue, 15 Oct 2019 11:11:24 -0300 Subject: [PATCH 19/19] EOL notification to wider community --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9100752170..12cb75fc5a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,16 @@ ![Rocket.Chat logo](https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/logo-dark.svg?sanitize=true) -# Rocket.Chat Android native application +# IMPORTANT: PLEASE READ THIS FIRST + +Rocket.Chat mobile is [moving to React Native](https://rocket.chat/2019/10/11/moving-mobile-apps-to-react/). Development on this repository by Rocket.Chat has now ceased. If your team is interested in taking over and maintaining this Android native client repository then please [contact us](https://rocket.chat/contact). + +# Legacy Rocket.Chat Android native application [![CircleCI](https://circleci.com/gh/RocketChat/Rocket.Chat.Android/tree/develop.svg?style=shield)](https://circleci.com/gh/RocketChat/Rocket.Chat.Android/tree/develop) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a81156a8682e4649994270d3670c3c83)](https://www.codacy.com/app/matheusjardimb/Rocket.Chat.Android) ## Get it from the stores -[![](https://user-images.githubusercontent.com/551004/48210434-74c07100-e35e-11e8-8eee-3ba84ffa74d7.png)](https://play.google.com/store/apps/details?id=chat.rocket.android) [![](https://user-images.githubusercontent.com/551004/48210349-50649480-e35e-11e8-97d9-74a4331faf3a.png)](https://f-droid.org/en/packages/chat.rocket.android/) +[![](https://user-images.githubusercontent.com/551004/48210349-50649480-e35e-11e8-97d9-74a4331faf3a.png)](https://f-droid.org/en/packages/chat.rocket.android/) ## Description