Commit 1e5148ce authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Refactor user details.

 - Fix for #3408 bug (Fabric);
 - Changing from Activity to fragment;
 - Logs user details view;
 - Removes lots of needless code;
 - Follows desing for widgets;
 - UI still needs some tweaks.
parent 12db177e
...@@ -87,84 +87,66 @@ android { ...@@ -87,84 +87,66 @@ android {
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation project(':player') implementation project(':player')
implementation project(':emoji') implementation project(':emoji')
implementation project(':draw') implementation project(':draw')
implementation project(':util') implementation project(':util')
implementation project(':core') implementation project(':core')
implementation project(':suggestions') implementation project(':suggestions')
implementation libraries.kotlin implementation libraries.kotlin
implementation libraries.coroutines implementation libraries.coroutines
implementation libraries.coroutinesAndroid implementation libraries.coroutinesAndroid
implementation libraries.appCompat implementation libraries.appCompat
implementation libraries.recyclerview implementation libraries.recyclerview
implementation libraries.constraintlayout implementation libraries.constraintlayout
implementation libraries.cardview implementation libraries.cardview
implementation libraries.browser implementation libraries.browser
implementation libraries.androidKtx implementation libraries.androidKtx
implementation libraries.fragmentsKtx implementation libraries.fragmentsKtx
implementation libraries.dagger implementation libraries.dagger
implementation libraries.daggerSupport implementation libraries.daggerSupport
kapt libraries.daggerProcessor kapt libraries.daggerProcessor
kapt libraries.daggerAndroidApt kapt libraries.daggerAndroidApt
implementation libraries.flexbox implementation libraries.flexbox
implementation libraries.material implementation libraries.material
implementation libraries.room implementation libraries.room
kapt libraries.roomProcessor kapt libraries.roomProcessor
implementation libraries.lifecycleExtensions implementation libraries.lifecycleExtensions
kapt libraries.lifecycleCompiler kapt libraries.lifecycleCompiler
implementation libraries.viewmodelKtx implementation libraries.viewmodelKtx
implementation libraries.workmanager implementation libraries.workmanager
implementation libraries.rxKotlin implementation libraries.rxKotlin
implementation libraries.rxAndroid implementation libraries.rxAndroid
implementation libraries.moshi implementation libraries.moshi
implementation libraries.okhttp implementation libraries.okhttp
implementation libraries.okhttpLogger implementation libraries.okhttpLogger
implementation libraries.timber implementation libraries.timber
implementation libraries.threeTenABP implementation libraries.threeTenABP
implementation libraries.fresco implementation libraries.fresco
api libraries.frescoOkHttp api libraries.frescoOkHttp
implementation libraries.frescoAnimatedGif implementation libraries.frescoAnimatedGif
implementation libraries.frescoWebP implementation libraries.frescoWebP
implementation libraries.frescoAnimatedWebP implementation libraries.frescoAnimatedWebP
implementation libraries.glide implementation libraries.glide
kapt libraries.kotshiCompiler kapt libraries.kotshiCompiler
implementation libraries.kotshiApi implementation libraries.kotshiApi
implementation libraries.frescoImageViewer implementation libraries.frescoImageViewer
implementation libraries.markwon implementation libraries.markwon
implementation libraries.aVLoadingIndicatorView implementation libraries.aVLoadingIndicatorView
implementation libraries.livedataKtx implementation libraries.livedataKtx
implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation 'com.google.code.findbugs:jsr305:3.0.2'
// Proprietary libraries // Proprietary libraries
playImplementation libraries.fcm playImplementation libraries.fcm
playImplementation libraries.firebaseAnalytics playImplementation libraries.firebaseAnalytics
playImplementation libraries.playServicesAuth playImplementation libraries.playServicesAuth
playImplementation('com.crashlytics.sdk.android:crashlytics:2.9.5@aar') { transitive = true } playImplementation('com.crashlytics.sdk.android:crashlytics:2.9.5@aar') { transitive = true }
playImplementation('com.crashlytics.sdk.android:answers:1.4.3@aar') { transitive = true } playImplementation('com.crashlytics.sdk.android:answers:1.4.3@aar') { transitive = true }
testImplementation libraries.junit testImplementation libraries.junit
testImplementation libraries.truth testImplementation libraries.truth
androidTestImplementation libraries.espressoCore androidTestImplementation libraries.espressoCore
androidTestImplementation libraries.espressoIntents androidTestImplementation libraries.espressoIntents
implementation files('libs/common-54676f5.jar')
implementation files('libs/core-54676f5.jar')
} }
kotlin { kotlin {
......
...@@ -93,16 +93,6 @@ ...@@ -93,16 +93,6 @@
android:name=".settings.password.ui.PasswordActivity" android:name=".settings.password.ui.PasswordActivity"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme" />
<activity
android:name=".userdetails.ui.UserDetailsActivity"
android:theme="@style/AppTheme"
android:windowSoftInputMode="stateAlwaysHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".chatroom.ui.ChatRoomActivity" />
</activity>
<receiver <receiver
android:name=".push.DirectReplyReceiver" android:name=".push.DirectReplyReceiver"
android:enabled="true" android:enabled="true"
......
...@@ -16,6 +16,7 @@ sealed class ScreenViewEvent(val screenName: String) { ...@@ -16,6 +16,7 @@ sealed class ScreenViewEvent(val screenName: String) {
object ChatRoom : ScreenViewEvent("ChatRoomFragment") object ChatRoom : ScreenViewEvent("ChatRoomFragment")
object ChatRooms : ScreenViewEvent("ChatRoomsFragment") object ChatRooms : ScreenViewEvent("ChatRoomsFragment")
object CreateChannel : ScreenViewEvent("CreateChannelFragment") object CreateChannel : ScreenViewEvent("CreateChannelFragment")
object UserDetails : ScreenViewEvent("UserDetailsFragment")
object FavoriteMessages : ScreenViewEvent("FavoriteMessagesFragment") object FavoriteMessages : ScreenViewEvent("FavoriteMessagesFragment")
object Files : ScreenViewEvent("FilesFragment") object Files : ScreenViewEvent("FilesFragment")
object MemberBottomSheet : ScreenViewEvent("MemberBottomSheetFragment") object MemberBottomSheet : ScreenViewEvent("MemberBottomSheetFragment")
......
...@@ -5,7 +5,8 @@ import chat.rocket.android.dagger.scope.PerFragment ...@@ -5,7 +5,8 @@ import chat.rocket.android.dagger.scope.PerFragment
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
@Module abstract class TwoFAFragmentProvider { @Module
abstract class TwoFAFragmentProvider {
@ContributesAndroidInjector(modules = [TwoFAFragmentModule::class]) @ContributesAndroidInjector(modules = [TwoFAFragmentModule::class])
@PerFragment @PerFragment
......
package chat.rocket.android.chatroom.adapter package chat.rocket.android.chatroom.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.uimodel.* import chat.rocket.android.chatroom.presentation.ChatRoomNavigator
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.chatroom.uimodel.AttachmentUiModel
import chat.rocket.android.chatroom.uimodel.BaseUiModel
import chat.rocket.android.chatroom.uimodel.MessageReplyUiModel
import chat.rocket.android.chatroom.uimodel.MessageUiModel
import chat.rocket.android.chatroom.uimodel.UrlPreviewUiModel
import chat.rocket.android.chatroom.uimodel.toViewType
import chat.rocket.android.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.openTabbedUrl import chat.rocket.android.util.extensions.openTabbedUrl
import chat.rocket.core.model.Message
import chat.rocket.core.model.attachment.actions.Action import chat.rocket.core.model.attachment.actions.Action
import chat.rocket.core.model.attachment.actions.ButtonAction import chat.rocket.core.model.attachment.actions.ButtonAction
import chat.rocket.core.model.Message
import chat.rocket.core.model.isSystemMessage import chat.rocket.core.model.isSystemMessage
import timber.log.Timber import timber.log.Timber
import java.security.InvalidParameterException import java.security.InvalidParameterException
...@@ -22,7 +28,8 @@ class ChatRoomAdapter( ...@@ -22,7 +28,8 @@ class ChatRoomAdapter(
private val roomName: String? = null, private val roomName: String? = null,
private val actionSelectListener: OnActionSelected? = null, private val actionSelectListener: OnActionSelected? = null,
private val enableActions: Boolean = true, private val enableActions: Boolean = true,
private val reactionListener: EmojiReactionListener? = null private val reactionListener: EmojiReactionListener? = null,
private val navigator: ChatRoomNavigator? = null
) : RecyclerView.Adapter<BaseViewHolder<*>>() { ) : RecyclerView.Adapter<BaseViewHolder<*>>() {
private val dataSet = ArrayList<BaseUiModel<*>>() private val dataSet = ArrayList<BaseUiModel<*>>()
...@@ -34,7 +41,11 @@ class ChatRoomAdapter( ...@@ -34,7 +41,11 @@ class ChatRoomAdapter(
return when (viewType.toViewType()) { return when (viewType.toViewType()) {
BaseUiModel.ViewType.MESSAGE -> { BaseUiModel.ViewType.MESSAGE -> {
val view = parent.inflate(R.layout.item_message) val view = parent.inflate(R.layout.item_message)
MessageViewHolder(view, actionsListener, reactionListener) MessageViewHolder(
view,
actionsListener,
reactionListener
) { userId -> navigator?.toUserDetails(userId) }
} }
BaseUiModel.ViewType.URL_PREVIEW -> { BaseUiModel.ViewType.URL_PREVIEW -> {
val view = parent.inflate(R.layout.message_url_preview) val view = parent.inflate(R.layout.message_url_preview)
...@@ -42,11 +53,20 @@ class ChatRoomAdapter( ...@@ -42,11 +53,20 @@ class ChatRoomAdapter(
} }
BaseUiModel.ViewType.ATTACHMENT -> { BaseUiModel.ViewType.ATTACHMENT -> {
val view = parent.inflate(R.layout.item_message_attachment) val view = parent.inflate(R.layout.item_message_attachment)
AttachmentViewHolder(view, actionsListener, reactionListener, actionAttachmentOnClickListener) AttachmentViewHolder(
view,
actionsListener,
reactionListener,
actionAttachmentOnClickListener
)
} }
BaseUiModel.ViewType.MESSAGE_REPLY -> { BaseUiModel.ViewType.MESSAGE_REPLY -> {
val view = parent.inflate(R.layout.item_message_reply) val view = parent.inflate(R.layout.item_message_reply)
MessageReplyViewHolder(view, actionsListener, reactionListener) { roomName, permalink -> MessageReplyViewHolder(
view,
actionsListener,
reactionListener
) { roomName, permalink ->
actionSelectListener?.openDirectMessage(roomName, permalink) actionSelectListener?.openDirectMessage(roomName, permalink)
} }
} }
...@@ -117,7 +137,8 @@ class ChatRoomAdapter( ...@@ -117,7 +137,8 @@ class ChatRoomAdapter(
fun prependData(dataSet: List<BaseUiModel<*>>) { fun prependData(dataSet: List<BaseUiModel<*>>) {
//---At first we will update all already saved elements with received updated ones //---At first we will update all already saved elements with received updated ones
val filteredDataSet = dataSet.filter { newItem -> val filteredDataSet = dataSet.filter { newItem ->
val matchedIndex = this.dataSet.indexOfFirst { it.messageId == newItem.messageId && it.viewType == newItem.viewType } val matchedIndex =
this.dataSet.indexOfFirst { it.messageId == newItem.messageId && it.viewType == newItem.viewType }
if (matchedIndex > -1) { if (matchedIndex > -1) {
this.dataSet[matchedIndex] = newItem this.dataSet[matchedIndex] = newItem
notifyItemChanged(matchedIndex) notifyItemChanged(matchedIndex)
...@@ -266,7 +287,12 @@ class ChatRoomAdapter( ...@@ -266,7 +287,12 @@ class ChatRoomAdapter(
fun showMessageInfo(id: String) fun showMessageInfo(id: String)
fun citeMessage(roomName: String, roomType: String, messageId: String, mentionAuthor: Boolean) fun citeMessage(
roomName: String,
roomType: String,
messageId: String,
mentionAuthor: Boolean
)
fun copyMessage(id: String) fun copyMessage(id: String)
......
package chat.rocket.android.chatroom.adapter package chat.rocket.android.chatroom.adapter
import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.text.Spannable import android.text.Spannable
...@@ -11,7 +10,6 @@ import androidx.core.view.isVisible ...@@ -11,7 +10,6 @@ import androidx.core.view.isVisible
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.uimodel.MessageUiModel import chat.rocket.android.chatroom.uimodel.MessageUiModel
import chat.rocket.android.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.userdetails.ui.userDetailsIntent
import chat.rocket.core.model.isSystemMessage import chat.rocket.core.model.isSystemMessage
import com.bumptech.glide.load.resource.gif.GifDrawable import com.bumptech.glide.load.resource.gif.GifDrawable
import kotlinx.android.synthetic.main.avatar.view.* import kotlinx.android.synthetic.main.avatar.view.*
...@@ -20,7 +18,8 @@ import kotlinx.android.synthetic.main.item_message.view.* ...@@ -20,7 +18,8 @@ import kotlinx.android.synthetic.main.item_message.view.*
class MessageViewHolder( class MessageViewHolder(
itemView: View, itemView: View,
listener: ActionsListener, listener: ActionsListener,
reactionListener: EmojiReactionListener? = null reactionListener: EmojiReactionListener? = null,
private val avatarListener: (String) -> Unit
) : BaseViewHolder<MessageUiModel>(itemView, listener, reactionListener), Drawable.Callback { ) : BaseViewHolder<MessageUiModel>(itemView, listener, reactionListener), Drawable.Callback {
init { init {
...@@ -73,24 +72,14 @@ class MessageViewHolder( ...@@ -73,24 +72,14 @@ class MessageViewHolder(
read_receipt_view.isVisible = true read_receipt_view.isVisible = true
} }
val senderId = data.message.sender?.id
val subscriptionId = data.subscriptionId
text_sender.setOnClickListener {
toUserDetails(context, senderId, subscriptionId)
}
image_avatar.setOnClickListener { image_avatar.setOnClickListener {
toUserDetails(context, senderId, subscriptionId) data.message.sender?.id?.let { userId ->
avatarListener(userId)
}
} }
} }
} }
private fun toUserDetails(context: Context, userId: String?, subscriptionId: String) {
userId?.let { context.startActivity(context.userDetailsIntent(it, subscriptionId)) }
}
override fun unscheduleDrawable(who: Drawable?, what: Runnable?) { override fun unscheduleDrawable(who: Drawable?, what: Runnable?) {
with(itemView) { with(itemView) {
text_content.removeCallbacks(what) text_content.removeCallbacks(what)
......
...@@ -5,7 +5,6 @@ import androidx.lifecycle.LifecycleOwner ...@@ -5,7 +5,6 @@ import androidx.lifecycle.LifecycleOwner
import chat.rocket.android.chatroom.presentation.ChatRoomView import chat.rocket.android.chatroom.presentation.ChatRoomView
import chat.rocket.android.chatroom.ui.ChatRoomFragment import chat.rocket.android.chatroom.ui.ChatRoomFragment
import chat.rocket.android.chatrooms.adapter.RoomUiModelMapper import chat.rocket.android.chatrooms.adapter.RoomUiModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerFragment import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.db.ChatRoomDao import chat.rocket.android.db.ChatRoomDao
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
...@@ -16,16 +15,11 @@ import chat.rocket.android.server.domain.SettingsRepository ...@@ -16,16 +15,11 @@ import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import kotlinx.coroutines.experimental.Job
import javax.inject.Named import javax.inject.Named
@Module @Module
class ChatRoomFragmentModule { class ChatRoomFragmentModule {
@Provides
@PerFragment
fun provideJob() = Job()
@Provides @Provides
@PerFragment @PerFragment
fun chatRoomView(frag: ChatRoomFragment): ChatRoomView { fun chatRoomView(frag: ChatRoomFragment): ChatRoomView {
...@@ -38,12 +32,6 @@ class ChatRoomFragmentModule { ...@@ -38,12 +32,6 @@ class ChatRoomFragmentModule {
return frag return frag
} }
@Provides
@PerFragment
fun provideCancelStrategy(owner: LifecycleOwner, jobs: Job): CancelStrategy {
return CancelStrategy(owner, jobs)
}
@Provides @Provides
@PerFragment @PerFragment
fun provideChatRoomDao(manager: DatabaseManager): ChatRoomDao = manager.chatRoomDao() fun provideChatRoomDao(manager: DatabaseManager): ChatRoomDao = manager.chatRoomDao()
...@@ -71,6 +59,12 @@ class ChatRoomFragmentModule { ...@@ -71,6 +59,12 @@ class ChatRoomFragmentModule {
@Named("currentServer") serverUrl: String, @Named("currentServer") serverUrl: String,
permissionsInteractor: PermissionsInteractor permissionsInteractor: PermissionsInteractor
): RoomUiModelMapper { ): RoomUiModelMapper {
return RoomUiModelMapper(context, repository.get(serverUrl), userInteractor, serverUrl, permissionsInteractor) return RoomUiModelMapper(
context,
repository.get(serverUrl),
userInteractor,
serverUrl,
permissionsInteractor
)
} }
} }
package chat.rocket.android.chatroom.di package chat.rocket.android.chatroom.di
import androidx.lifecycle.LifecycleOwner
import chat.rocket.android.chatroom.presentation.ChatRoomNavigator import chat.rocket.android.chatroom.presentation.ChatRoomNavigator
import chat.rocket.android.chatroom.ui.ChatRoomActivity import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerActivity import chat.rocket.android.dagger.scope.PerActivity
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import kotlinx.coroutines.experimental.Job
@Module @Module
class ChatRoomModule { class ChatRoomModule {
@Provides @Provides
@PerActivity @PerActivity
fun provideChatRoomNavigator(activity: ChatRoomActivity) = ChatRoomNavigator(activity) fun provideChatRoomNavigator(activity: ChatRoomActivity) = ChatRoomNavigator(activity)
@Provides
@PerActivity
fun provideJob() = Job()
@Provides
@PerActivity
fun provideLifecycleOwner(activity: ChatRoomActivity): LifecycleOwner = activity
@Provides
@PerActivity
fun provideCancelStrategy(owner: LifecycleOwner, jobs: Job): CancelStrategy {
return CancelStrategy(owner, jobs)
}
} }
\ No newline at end of file
...@@ -6,6 +6,7 @@ import dagger.Module ...@@ -6,6 +6,7 @@ import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
@Module abstract class MessageServiceProvider { @Module abstract class MessageServiceProvider {
@ContributesAndroidInjector(modules = [AppModule::class]) @ContributesAndroidInjector(modules = [AppModule::class])
abstract fun provideMessageService(): MessageService abstract fun provideMessageService(): MessageService
} }
\ No newline at end of file
...@@ -5,15 +5,44 @@ import chat.rocket.android.chatdetails.ui.chatDetailsIntent ...@@ -5,15 +5,44 @@ import chat.rocket.android.chatdetails.ui.chatDetailsIntent
import chat.rocket.android.chatinformation.ui.messageInformationIntent import chat.rocket.android.chatinformation.ui.messageInformationIntent
import chat.rocket.android.chatroom.ui.ChatRoomActivity import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.chatroom.ui.chatRoomIntent import chat.rocket.android.chatroom.ui.chatRoomIntent
import chat.rocket.android.favoritemessages.ui.TAG_FAVORITE_MESSAGES_FRAGMENT
import chat.rocket.android.files.ui.TAG_FILES_FRAGMENT
import chat.rocket.android.members.ui.TAG_MEMBERS_FRAGMENT
import chat.rocket.android.mentions.ui.TAG_MENTIONS_FRAGMENT
import chat.rocket.android.pinnedmessages.ui.TAG_PINNED_MESSAGES_FRAGMENT
import chat.rocket.android.server.ui.changeServerIntent import chat.rocket.android.server.ui.changeServerIntent
import chat.rocket.android.userdetails.ui.TAG_USER_DETAILS_FRAGMENT
import chat.rocket.android.util.extensions.addFragmentBackStack import chat.rocket.android.util.extensions.addFragmentBackStack
import javax.inject.Inject
class ChatRoomNavigator @Inject constructor(internal val activity: ChatRoomActivity) {
fun toUserDetails(userId: String) {
activity.addFragmentBackStack(TAG_USER_DETAILS_FRAGMENT, R.id.fragment_container) {
chat.rocket.android.userdetails.ui.newInstance(userId)
}
}
fun toChatRoom(
chatRoomId: String,
chatRoomName: String,
chatRoomType: String,
isReadOnly: Boolean,
chatRoomLastSeen: Long,
isSubscribed: Boolean,
isCreator: Boolean,
isFavorite: Boolean
) {
activity.startActivity(
activity.chatRoomIntent(
chatRoomId,
chatRoomName,
chatRoomType,
isReadOnly,
chatRoomLastSeen,
isSubscribed,
isCreator,
isFavorite
)
)
activity.overridePendingTransition(R.anim.open_enter, R.anim.open_exit)
}
class ChatRoomNavigator(internal val activity: ChatRoomActivity) {
fun toChatDetails( fun toChatDetails(
chatRoomId: String, chatRoomId: String,
chatRoomType: String, chatRoomType: String,
......
...@@ -40,6 +40,7 @@ import chat.rocket.android.chatroom.adapter.EmojiSuggestionsAdapter ...@@ -40,6 +40,7 @@ import chat.rocket.android.chatroom.adapter.EmojiSuggestionsAdapter
import chat.rocket.android.chatroom.adapter.PEOPLE import chat.rocket.android.chatroom.adapter.PEOPLE
import chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter import chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter
import chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter import chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter
import chat.rocket.android.chatroom.presentation.ChatRoomNavigator
import chat.rocket.android.chatroom.presentation.ChatRoomPresenter import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import chat.rocket.android.chatroom.presentation.ChatRoomView import chat.rocket.android.chatroom.presentation.ChatRoomView
import chat.rocket.android.chatroom.ui.bottomsheet.MessageActionsBottomSheet import chat.rocket.android.chatroom.ui.bottomsheet.MessageActionsBottomSheet
...@@ -68,6 +69,7 @@ import chat.rocket.android.helper.MessageParser ...@@ -68,6 +69,7 @@ import chat.rocket.android.helper.MessageParser
import chat.rocket.android.util.extension.asObservable import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extension.createImageFile import chat.rocket.android.util.extension.createImageFile
import chat.rocket.android.util.extensions.circularRevealOrUnreveal import chat.rocket.android.util.extensions.circularRevealOrUnreveal
import chat.rocket.android.util.extensions.clearLightStatusBar
import chat.rocket.android.util.extensions.fadeIn import chat.rocket.android.util.extensions.fadeIn
import chat.rocket.android.util.extensions.fadeOut import chat.rocket.android.util.extensions.fadeOut
import chat.rocket.android.util.extensions.getBitmpap import chat.rocket.android.util.extensions.getBitmpap
...@@ -85,6 +87,7 @@ import dagger.android.support.AndroidSupportInjection ...@@ -85,6 +87,7 @@ import dagger.android.support.AndroidSupportInjection
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.app_bar_chat_room.*
import kotlinx.android.synthetic.main.emoji_image_row_item.view.* import kotlinx.android.synthetic.main.emoji_image_row_item.view.*
import kotlinx.android.synthetic.main.emoji_row_item.view.* import kotlinx.android.synthetic.main.emoji_row_item.view.*
import kotlinx.android.synthetic.main.fragment_chat_room.* import kotlinx.android.synthetic.main.fragment_chat_room.*
...@@ -145,13 +148,14 @@ internal const val MENU_ACTION_SHOW_DETAILS = 2 ...@@ -145,13 +148,14 @@ internal const val MENU_ACTION_SHOW_DETAILS = 2
class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiReactionListener, class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiReactionListener,
ChatRoomAdapter.OnActionSelected, Drawable.Callback { ChatRoomAdapter.OnActionSelected, Drawable.Callback {
@Inject @Inject
lateinit var presenter: ChatRoomPresenter lateinit var presenter: ChatRoomPresenter
@Inject @Inject
lateinit var parser: MessageParser lateinit var parser: MessageParser
@Inject @Inject
lateinit var analyticsManager: AnalyticsManager lateinit var analyticsManager: AnalyticsManager
@Inject
lateinit var navigator: ChatRoomNavigator
private lateinit var adapter: ChatRoomAdapter private lateinit var adapter: ChatRoomAdapter
internal lateinit var chatRoomId: String internal lateinit var chatRoomId: String
private lateinit var chatRoomName: String private lateinit var chatRoomName: String
...@@ -284,7 +288,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -284,7 +288,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" } requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
} }
adapter = ChatRoomAdapter(chatRoomId, chatRoomType, chatRoomName, this, reactionListener = this) adapter = ChatRoomAdapter(chatRoomId, chatRoomType, chatRoomName, this, reactionListener = this, navigator = navigator)
} }
override fun onCreateView( override fun onCreateView(
...@@ -1057,7 +1061,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -1057,7 +1061,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
private fun setupToolbar(toolbarTitle: String) { private fun setupToolbar(toolbarTitle: String) {
(activity as ChatRoomActivity).showToolbarTitle(toolbarTitle) with(activity as ChatRoomActivity) {
this.clearLightStatusBar()
this.showToolbarTitle(toolbarTitle)
toolbar.isVisible = true
}
} }
override fun unscheduleDrawable(who: Drawable?, what: Runnable?) { override fun unscheduleDrawable(who: Drawable?, what: Runnable?) {
......
...@@ -38,14 +38,14 @@ import chat.rocket.android.server.ui.ChangeServerActivity ...@@ -38,14 +38,14 @@ import chat.rocket.android.server.ui.ChangeServerActivity
import chat.rocket.android.settings.di.SettingsFragmentProvider import chat.rocket.android.settings.di.SettingsFragmentProvider
import chat.rocket.android.settings.password.di.PasswordFragmentProvider import chat.rocket.android.settings.password.di.PasswordFragmentProvider
import chat.rocket.android.settings.password.ui.PasswordActivity import chat.rocket.android.settings.password.ui.PasswordActivity
import chat.rocket.android.userdetails.di.UserDetailsModule import chat.rocket.android.userdetails.di.UserDetailsFragmentProvider
import chat.rocket.android.userdetails.ui.UserDetailsActivity
import chat.rocket.android.webview.adminpanel.di.AdminPanelWebViewFragmentProvider import chat.rocket.android.webview.adminpanel.di.AdminPanelWebViewFragmentProvider
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
@Module @Module
abstract class ActivityBuilder { abstract class ActivityBuilder {
@PerActivity @PerActivity
@ContributesAndroidInjector( @ContributesAndroidInjector(
modules = [AuthenticationModule::class, modules = [AuthenticationModule::class,
...@@ -77,9 +77,9 @@ abstract class ActivityBuilder { ...@@ -77,9 +77,9 @@ abstract class ActivityBuilder {
@PerActivity @PerActivity
@ContributesAndroidInjector( @ContributesAndroidInjector(
modules = [ modules = [ChatRoomModule::class,
ChatRoomModule::class, ChatRoomFragmentProvider::class,
ChatRoomFragmentProvider::class UserDetailsFragmentProvider::class
] ]
) )
abstract fun bindChatRoomActivity(): ChatRoomActivity abstract fun bindChatRoomActivity(): ChatRoomActivity
...@@ -113,8 +113,4 @@ abstract class ActivityBuilder { ...@@ -113,8 +113,4 @@ abstract class ActivityBuilder {
@PerActivity @PerActivity
@ContributesAndroidInjector(modules = [DrawModule::class]) @ContributesAndroidInjector(modules = [DrawModule::class])
abstract fun bindDrawingActivity(): DrawingActivity abstract fun bindDrawingActivity(): DrawingActivity
@PerActivity
@ContributesAndroidInjector(modules = [UserDetailsModule::class])
abstract fun bindUserDetailsActivity(): UserDetailsActivity
} }
...@@ -102,6 +102,18 @@ class DatabaseManager(val context: Application, val serverUrl: String) { ...@@ -102,6 +102,18 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
} }
} }
suspend fun insertOrReplaceRoom(chatRoomEntity: ChatRoomEntity) {
retryDB("insertOrReplace($chatRoomEntity)") {
chatRoomDao().insertOrReplace(chatRoomEntity)
}
}
suspend fun getUser(id: String) = withContext(dbManagerContext) {
retryDB("getUser($id)") {
userDao().getUser(id)
}
}
fun processUsersBatch(users: List<User>) { fun processUsersBatch(users: List<User>) {
launch(dbManagerContext) { launch(dbManagerContext) {
val list = ArrayList<BaseUserEntity>(users.size) val list = ArrayList<BaseUserEntity>(users.size)
......
...@@ -22,7 +22,7 @@ class MembersFragmentModule { ...@@ -22,7 +22,7 @@ class MembersFragmentModule {
@Provides @Provides
@PerFragment @PerFragment
fun provideChatRoomNavigator(activity: ChatDetailsActivity) = MembersNavigator(activity) fun provideMembersNavigator(activity: ChatDetailsActivity) = MembersNavigator(activity)
@Provides @Provides
@PerFragment @PerFragment
......
package chat.rocket.android.members.presentation package chat.rocket.android.members.presentation
import chat.rocket.android.R
import chat.rocket.android.chatdetails.ui.ChatDetailsActivity import chat.rocket.android.chatdetails.ui.ChatDetailsActivity
import chat.rocket.android.userdetails.ui.userDetailsIntent import chat.rocket.android.userdetails.ui.TAG_USER_DETAILS_FRAGMENT
import chat.rocket.android.util.extensions.addFragmentBackStack
class MembersNavigator(internal val activity: ChatDetailsActivity) { class MembersNavigator(internal val activity: ChatDetailsActivity) {
fun toMemberDetails(userId: String) { fun toMemberDetails(userId: String) {
activity.apply { // TODO
startActivity(this.userDetailsIntent(userId, "")) // activity.addFragmentBackStack(TAG_USER_DETAILS_FRAGMENT, R.id.fragment_container) {
} // chat.rocket.android.userdetails.ui.newInstance(userId)
// }
} }
} }
...@@ -37,13 +37,12 @@ internal const val TAG_MENTIONS_FRAGMENT = "MentionsFragment" ...@@ -37,13 +37,12 @@ internal const val TAG_MENTIONS_FRAGMENT = "MentionsFragment"
private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id" private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id"
class MentionsFragment : Fragment(), MentionsView { class MentionsFragment : Fragment(), MentionsView {
private lateinit var chatRoomId: String
private val adapter = ChatRoomAdapter(enableActions = false)
@Inject @Inject
lateinit var presenter: MentionsPresenter lateinit var presenter: MentionsPresenter
@Inject @Inject
lateinit var analyticsManager: AnalyticsManager lateinit var analyticsManager: AnalyticsManager
private lateinit var chatRoomId: String
private val adapter = ChatRoomAdapter(enableActions = false)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
......
package chat.rocket.android.userdetails.di
import androidx.lifecycle.LifecycleOwner
import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.userdetails.presentation.UserDetailsView
import chat.rocket.android.userdetails.ui.UserDetailsFragment
import dagger.Module
import dagger.Provides
@Module
class UserDetailsFragmentModule {
@Provides
@PerFragment
fun provideUserDetailsView(frag: UserDetailsFragment): UserDetailsView = frag
@Provides
@PerFragment
fun provideLifecycleOwner(frag: UserDetailsFragment): LifecycleOwner = frag
}
package chat.rocket.android.userdetails.di
import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.userdetails.ui.UserDetailsFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class UserDetailsFragmentProvider {
@ContributesAndroidInjector(modules = [UserDetailsFragmentModule::class])
@PerFragment
abstract fun provideUserDetailsFragment(): UserDetailsFragment
}
package chat.rocket.android.userdetails.di
import androidx.lifecycle.LifecycleOwner
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerActivity
import chat.rocket.android.userdetails.presentation.UserDetailsView
import chat.rocket.android.userdetails.ui.UserDetailsActivity
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.experimental.Job
@Module
class UserDetailsModule {
@Provides
@PerActivity
fun provideJob() = Job()
@Provides
@PerActivity
fun provideUserDetailsView(activity: UserDetailsActivity): UserDetailsView = activity
@Provides
@PerActivity
fun provideLifecycleOwner(activity: UserDetailsActivity): LifecycleOwner = activity
@Provides
@PerActivity
fun provideCancelStrategy(owner: LifecycleOwner, jobs: Job): CancelStrategy {
return CancelStrategy(owner, jobs)
}
}
package chat.rocket.android.userdetails.presentation package chat.rocket.android.userdetails.presentation
import chat.rocket.android.chatroom.presentation.ChatRoomNavigator
import chat.rocket.android.chatrooms.domain.FetchChatRoomsInteractor import chat.rocket.android.chatrooms.domain.FetchChatRoomsInteractor
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.model.ChatRoomEntity import chat.rocket.android.db.model.ChatRoomEntity
import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.server.domain.GetConnectingServerInteractor import chat.rocket.android.server.domain.GetConnectingServerInteractor
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.util.ifNull
import chat.rocket.common.model.userStatusOf
import chat.rocket.core.internal.rest.createDirectMessage import chat.rocket.core.internal.rest.createDirectMessage
import chat.rocket.core.model.ChatRoom import kotlinx.coroutines.experimental.DefaultDispatcher
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
...@@ -23,141 +23,98 @@ class UserDetailsPresenter @Inject constructor( ...@@ -23,141 +23,98 @@ class UserDetailsPresenter @Inject constructor(
private val view: UserDetailsView, private val view: UserDetailsView,
private val dbManager: DatabaseManager, private val dbManager: DatabaseManager,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val navigator: ChatRoomNavigator,
serverInteractor: GetConnectingServerInteractor, serverInteractor: GetConnectingServerInteractor,
factory: ConnectionManagerFactory factory: ConnectionManagerFactory
) { ) {
private var currentServer = serverInteractor.get()!! private var currentServer = serverInteractor.get()!!
private val manager = factory.create(currentServer) private val manager = factory.create(currentServer)
private val client = manager.client private val client = manager.client
private val interactor = FetchChatRoomsInteractor(client,dbManager) private val interactor = FetchChatRoomsInteractor(client, dbManager)
private lateinit var userEntity: UserEntity
fun loadUserDetails(userId: String) { fun loadUserDetails(userId: String) {
launchUI(strategy) { launchUI(strategy) {
try { try {
val user = withContext(CommonPool) { view.showLoading()
dbManager.userDao().getUser(id = userId) dbManager.getUser(userId)?.let {
} userEntity = it
val avatarUrl =
user?.let { u -> userEntity.username?.let { currentServer.avatarUrl(avatar = it) }
val openedChatRooms = chatRoomByName(name = u.name) val username = userEntity.username
val avatarUrl = u.username?.let { currentServer.avatarUrl(avatar = it) } val name = userEntity.name
val utcOffset =
val chatRoom: ChatRoom? = openedChatRooms.firstOrNull() userEntity.utcOffset // TODO Convert UTC and display like the mockup
view.showUserDetails( if (avatarUrl != null && username != null && name != null && utcOffset != null) {
avatarUrl = avatarUrl, view.showUserDetails(
username = u.username, avatarUrl = avatarUrl,
name = u.name, name = name,
utcOffset = u.utcOffset, username = username,
status = u.status, status = userEntity.status,
chatRoom = chatRoom utcOffset = utcOffset.toString()
) )
} else {
throw Exception()
}
} }
} catch (ex: Exception) { } catch (ex: Exception) {
Timber.e(ex) Timber.e(ex)
ex.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
} finally {
view.hideLoading()
} }
} }
} }
fun createDirectMessage(id: String) = launchUI(strategy) { fun createDirectMessage(username: String) {
try { launchUI(strategy) {
val result = retryIO("createDirectMessage($id") { try {
client.createDirectMessage(username = id) view.showLoading()
}
interactor.refreshChatRooms() withContext(DefaultDispatcher) {
val directMessage = retryIO("createDirectMessage($username") {
client.createDirectMessage(username)
}
val userEntity = withContext(CommonPool) { val chatRoomEntity = ChatRoomEntity(
dbManager.userDao().getUser(id = id) id = directMessage.id,
} name = userEntity.username ?: userEntity.name.orEmpty(),
description = null,
type = RoomType.DIRECT_MESSAGE,
fullname = userEntity.name,
subscriptionId = "",
updatedAt = directMessage.updatedAt
)
if (userEntity != null) { dbManager.insertOrReplaceRoom(chatRoomEntity)
val chatRoom = ChatRoom(
id = result.id,
type = roomTypeOf(RoomType.DIRECT_MESSAGE),
name = userEntity.username ?: userEntity.name.orEmpty(),
fullName = userEntity.name,
favorite = false,
open = false,
alert = false,
status = userStatusOf(userEntity.status),
client = client,
broadcast = false,
archived = false,
default = false,
description = null,
groupMentions = null,
userMentions = null,
lastMessage = null,
lastSeen = null,
topic = null,
announcement = null,
roles = null,
unread = 0,
readonly = false,
muted = null,
subscriptionId = "",
timestamp = null,
updatedAt = result.updatedAt,
user = null
)
withContext(CommonPool + strategy.jobs) { interactor.refreshChatRooms()
dbManager.chatRoomDao().insertOrReplace(chatRoom = ChatRoomEntity(
id = chatRoom.id,
name = chatRoom.name,
description = chatRoom.description,
type = chatRoom.type.toString(),
fullname = chatRoom.fullName,
subscriptionId = chatRoom.subscriptionId,
updatedAt = chatRoom.updatedAt
))
}
view.toDirectMessage(chatRoom = chatRoom) navigator.toChatRoom(
} chatRoomId = chatRoomEntity.id,
} catch (ex: Exception) { chatRoomName = chatRoomEntity.name,
Timber.e(ex) chatRoomType = chatRoomEntity.type,
view.onOpenDirectMessageError() isReadOnly = false,
} chatRoomLastSeen = -1,
} isSubscribed = chatRoomEntity.open,
isCreator = true,
private suspend fun chatRoomByName(name: String? = null): List<ChatRoom> = withContext(CommonPool) { isFavorite = false
return@withContext dbManager.chatRoomDao().getAllSync().filter { )
if (name == null) { }
return@filter true } catch (ex: Exception) {
} Timber.e(ex)
it.chatRoom.name == name || it.chatRoom.fullname == name ex.message?.let {
}.map { view.showMessage(it)
with(it.chatRoom) { }.ifNull {
ChatRoom( view.showGenericErrorMessage()
id = id, }
subscriptionId = subscriptionId, } finally {
type = roomTypeOf(type), view.hideLoading()
unread = unread,
broadcast = broadcast ?: false,
alert = alert,
fullName = fullname,
name = name ?: "",
favorite = favorite ?: false,
default = isDefault ?: false,
readonly = readonly,
open = open,
lastMessage = null,
archived = false,
status = null,
user = null,
userMentions = userMentions,
client = client,
announcement = null,
description = null,
groupMentions = groupMentions,
roles = null,
topic = null,
lastSeen = this.lastSeen,
timestamp = timestamp,
updatedAt = updatedAt
)
} }
} }
} }
......
package chat.rocket.android.userdetails.presentation package chat.rocket.android.userdetails.presentation
import chat.rocket.core.model.ChatRoom import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
interface UserDetailsView { interface UserDetailsView : LoadingView, MessageView {
fun showUserDetails(avatarUrl: String?, username: String?, name: String?, utcOffset: Float?, status: String, chatRoom: ChatRoom?) /**
* Shows user detail.
fun toDirectMessage(chatRoom: ChatRoom) *
* @param avatarUrl The user avatar URL.
fun onOpenDirectMessageError() * @param name The user's name.
* @param username The user's username.
* @param status The user's status.
* @param utcOffset The user's UTC offset.
*/
fun showUserDetails(
avatarUrl: String,
name: String,
username: String,
status: String,
utcOffset: String
)
} }
package chat.rocket.android.userdetails.ui
import android.content.Context
import android.content.Intent
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import blurred
import chat.rocket.android.R
import chat.rocket.android.chatroom.ui.chatRoomIntent
import chat.rocket.android.emoji.internal.GlideApp
import chat.rocket.android.userdetails.presentation.UserDetailsPresenter
import chat.rocket.android.userdetails.presentation.UserDetailsView
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extension.orFalse
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.retryIO
import chat.rocket.common.model.roomTypeOf
import chat.rocket.core.internal.rest.createDirectMessage
import chat.rocket.core.model.ChatRoom
import chat.rocket.core.model.userId
import com.bumptech.glide.Glide
import com.bumptech.glide.Priority
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.CenterInside
import com.bumptech.glide.load.resource.bitmap.FitCenter
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import com.google.android.material.snackbar.Snackbar
import dagger.android.AndroidInjection
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.support.HasSupportFragmentInjector
import kotlinx.android.synthetic.main.activity_user_details.*
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext
import org.threeten.bp.OffsetDateTime
import org.threeten.bp.ZoneId
import org.threeten.bp.ZoneOffset
import org.threeten.bp.ZonedDateTime
import org.threeten.bp.format.DateTimeFormatter
import timber.log.Timber
import javax.inject.Inject
import kotlin.math.roundToLong
fun Context.userDetailsIntent(userId: String, subscriptionId: String): Intent {
return Intent(this, UserDetailsActivity::class.java).apply {
putExtra(EXTRA_USER_ID, userId)
putExtra(EXTRA_SUBSCRIPTION_ID, subscriptionId)
}
}
const val EXTRA_USER_ID = "EXTRA_USER_ID"
const val EXTRA_SUBSCRIPTION_ID = "EXTRA_USERNAME"
class UserDetailsActivity : AppCompatActivity(), UserDetailsView, HasSupportFragmentInjector {
@Inject
lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
@Inject
lateinit var presenter: UserDetailsPresenter
private lateinit var subscriptionId: String
private lateinit var userId: String
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user_details)
setupToolbar()
userId = intent.getStringExtra(EXTRA_USER_ID)
subscriptionId = intent.getStringExtra(EXTRA_SUBSCRIPTION_ID)
showLoadingView(true)
presenter.loadUserDetails(userId = userId)
}
override fun supportFragmentInjector(): AndroidInjector<Fragment> = fragmentDispatchingAndroidInjector
private fun setupToolbar() {
setSupportActionBar(toolbar)
supportActionBar?.setDisplayShowTitleEnabled(false)
toolbar.setNavigationOnClickListener { finish() }
}
override fun showUserDetails(
avatarUrl: String?,
username: String?,
name: String?,
utcOffset: Float?,
status: String,
chatRoom: ChatRoom?
) {
text_view_name.text = name
text_view_username.text = username
text_view_status.text = status.capitalize()
try {
launch(UI) {
val image = withContext(CommonPool) {
try {
val requestOptions = RequestOptions()
.priority(Priority.IMMEDIATE)
.transforms(CenterInside(), FitCenter())
return@withContext GlideApp.with(this@UserDetailsActivity)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.load(avatarUrl)
.apply(requestOptions)
.submit()
.get()
} catch (ex: Exception) {
Timber.e(ex)
return@withContext null
} finally {
showLoadingView(false)
}
}
image?.let {
val blurredBitmap = image.blurred(context = this@UserDetailsActivity,
newWidth = toolbar.measuredWidth, newHeight = toolbar.measuredHeight)
toolbar.background = BitmapDrawable(resources, blurredBitmap)
GlideApp.with(this@UserDetailsActivity)
.asBitmap()
.transforms(RoundedCorners(25), CenterCrop())
.load(image)
.into(image_view_avatar)
}
}
utcOffset?.let {
val offsetLong = it.roundToLong()
val offset = if (it > 0) "+$offsetLong" else offsetLong.toString()
val formatter = DateTimeFormatter.ofPattern("'(GMT$offset)' hh:mm a")
val zoneId = ZoneId.systemDefault()
val timeNow = OffsetDateTime.now(ZoneOffset.UTC).plusHours(offsetLong).toLocalDateTime()
text_view_tz.text = formatter.format(ZonedDateTime.of(timeNow, zoneId))
}
text_view_message.setOnClickListener {
if (chatRoom == null) {
presenter.createDirectMessage(id = userId)
} else {
toDirectMessage(chatRoom)
}
}
image_view_message.setOnClickListener {
if (chatRoom == null) {
presenter.createDirectMessage(id = userId)
} else {
toDirectMessage(chatRoom)
}
}
} catch (ex: Exception) {
Timber.e(ex)
}
}
private fun showLoadingView(show: Boolean) {
runOnUiThread {
group_user_details.isVisible = !show
view_loading.isVisible = show
}
}
override fun onOpenDirectMessageError() {
Snackbar.make(root_layout, R.string.error_opening_dm, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.retry) {
presenter.createDirectMessage(userId)
}.show()
}
override fun toDirectMessage(chatRoom: ChatRoom) {
finish()
if (chatRoom.subscriptionId.isEmpty() || chatRoom.subscriptionId != subscriptionId) {
startActivity(
chatRoomIntent(
chatRoomId = chatRoom.id,
chatRoomName = chatRoom.name,
chatRoomType = chatRoom.type.toString(),
isReadOnly = chatRoom.readonly.orFalse(),
chatRoomLastSeen = chatRoom.lastSeen ?: 0,
isSubscribed = chatRoom.open,
isCreator = false,
isFavorite = chatRoom.favorite
)
)
}
}
}
package chat.rocket.android.userdetails.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.userdetails.presentation.UserDetailsPresenter
import chat.rocket.android.userdetails.presentation.UserDetailsView
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.setLightStatusBar
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import com.bumptech.glide.Glide
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.app_bar_chat_room.*
import kotlinx.android.synthetic.main.fragment_user_details.*
import javax.inject.Inject
fun newInstance(userId: String): Fragment {
return UserDetailsFragment().apply {
arguments = Bundle(1).apply {
putString(BUNDLE_USER_ID, userId)
}
}
}
internal const val TAG_USER_DETAILS_FRAGMENT = "UserDetailsFragment"
private const val BUNDLE_USER_ID = "user_id"
class UserDetailsFragment : Fragment(), UserDetailsView {
@Inject
lateinit var presenter: UserDetailsPresenter
@Inject
lateinit var analyticsManager: AnalyticsManager
private lateinit var userId: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
val bundle = arguments
if (bundle != null) {
userId = bundle.getString(BUNDLE_USER_ID)
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = container?.inflate(R.layout.fragment_user_details)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToolbar()
presenter.loadUserDetails(userId)
analyticsManager.logScreenView(ScreenViewEvent.UserDetails)
}
override fun showUserDetails(
avatarUrl: String,
name: String,
username: String,
status: String,
utcOffset: String
) {
Glide.with(this)
.asBitmap()
.load(avatarUrl)
.into(image_avatar)
text_name.text = name
text_username.text = username
text_description_status.text = status
text_description_timezone.text = utcOffset
// We should also setup the user details listeners.
text_message.setOnClickListener { presenter.createDirectMessage(username) }
}
override fun showLoading() {
group_user_details.isVisible = false
view_loading.isVisible = true
}
override fun hideLoading() {
group_user_details.isVisible = true
view_loading.isVisible = false
}
override fun showMessage(resId: Int) {
ui { showToast(resId) }
}
override fun showMessage(message: String) {
ui { showToast(message) }
}
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
private fun setupToolbar() {
with(activity as ChatRoomActivity) {
view?.let { setLightStatusBar(it) }
toolbar.isVisible = false
}
}
}
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="20" android:viewportWidth="20"
android:viewportHeight="20"> android:viewportHeight="20">
<path <path
android:fillColor="#1d74f5" android:fillColor="#1d74f5"
android:fillType="evenOdd" android:fillType="evenOdd"
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:fitsSystemWindows="true">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
style="@style/Authentication.AVLoadingIndicatorView"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<ImageView
android:id="@+id/image_view_message"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_view_username"
app:srcCompat="@drawable/ic_message_24dp" />
<TextView
android:id="@+id/text_view_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/message"
android:textColor="#1d74f5"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="@+id/image_view_message"
app:layout_constraintStart_toStartOf="@+id/image_view_message"
app:layout_constraintTop_toBottomOf="@+id/image_view_message" />
<TextView
android:id="@+id/text_view_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:fontFamily="sans-serif-medium"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Karem Flusser" />
<TextView
android:id="@+id/text_view_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:textColor="@color/darkGray"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_view_name"
tools:text="karem.flusser" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:text="@string/status"
android:textColor="@color/darkGray"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_view_message" />
<TextView
android:id="@+id/text_view_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:textColor="@android:color/black"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3"
tools:text="Online" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="@string/timezone"
android:textColor="@color/darkGray"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_view_status" />
<TextView
android:id="@+id/text_view_tz"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:textColor="@android:color/black"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
tools:text="(UTC-2) 11:08 AM" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_user_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="text_view_tz,textView,text_view_status,text_view_message,textView3,text_view_name,text_view_username,image_view_message" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
app:elevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="@android:color/white"
app:expandedTitleGravity="top"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="?actionBarSize"
app:elevation="0dp"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:navigationIcon="?android:attr/homeAsUpIndicator"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<ImageView
android:id="@+id/image_view_avatar"
android:layout_width="98dp"
android:layout_height="98dp"
android:layout_gravity="center_horizontal"
android:layout_marginStart="16dp"
android:layout_marginTop="?actionBarSize"
android:layout_marginEnd="16dp"
android:background="@drawable/bg_round_bounds_white"
tools:srcCompat="@tools:sample/avatars[6]" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:padding="@dimen/screen_edge_left_and_right_margins">
<ImageView
android:id="@+id/image_avatar"
android:layout_width="98dp"
android:layout_height="98dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars[6]" />
<TextView
android:id="@+id/text_name"
style="@style/UserDetails.TextView.Name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/image_avatar"
tools:text="Karem Flusser" />
<TextView
android:id="@+id/text_username"
style="@style/UserDetails.TextView.Username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_name"
tools:text="karem.flusser" />
<TextView
android:id="@+id/text_message"
style="@style/UserDetails.TextView.Actions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:drawableTop="@drawable/ic_message_24dp"
android:text="@string/msg_message"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_username" />
<TextView
android:id="@+id/text_title_status"
style="@style/UserDetails.TextView.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/status"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_message" />
<TextView
android:id="@+id/text_description_status"
style="@style/UserDetails.TextView.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_title_status"
tools:text="Online" />
<TextView
android:id="@+id/text_title_timezone"
style="@style/UserDetails.TextView.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/timezone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_description_status" />
<TextView
android:id="@+id/text_description_timezone"
style="@style/UserDetails.TextView.Description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_title_timezone"
tools:text="(UTC-2) 11:08 AM" />
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
style="@style/Authentication.AVLoadingIndicatorView"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_user_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="image_avatar, text_name, text_username, text_message, text_title_status, text_description_status, text_title_timezone, text_description_timezone" />
</androidx.constraintlayout.widget.ConstraintLayout>
...@@ -329,11 +329,9 @@ ...@@ -329,11 +329,9 @@
<string name="read_by">Gelesen von</string> <string name="read_by">Gelesen von</string>
<string name="message_information_title">Nachricht Information</string> <string name="message_information_title">Nachricht Information</string>
<string name="message_room_changed_privacy">Room type changed to: %1$s by %2$s</string> <string name="message_room_changed_privacy">Room type changed to: %1$s by %2$s</string>
<!-- User Details --> <!-- User Details -->
<string name="message">Botschaft</string>
<string name="timezone">Zeitzone</string> <string name="timezone">Zeitzone</string>
<string name="error_opening_dm">Etwas ist schiefgegangen, als wir dieses Gespräch erstellt haben…</string>
<string name="retry">Wiederholen</string>
<!-- Report --> <!-- Report -->
<string name="submit">einreichen</string> <string name="submit">einreichen</string>
......
...@@ -335,10 +335,7 @@ ...@@ -335,10 +335,7 @@
<string name="message_room_changed_privacy">Room type changed to: %1$s by %2$s</string> <!--TODO - Add proper translation--> <string name="message_room_changed_privacy">Room type changed to: %1$s by %2$s</string> <!--TODO - Add proper translation-->
<!-- User Details --> <!-- User Details -->
<string name="message">Message</string> <!-- TODO - Add proper translation -->
<string name="timezone">Timezone</string> <!-- TODO - Add proper translation --> <string name="timezone">Timezone</string> <!-- TODO - Add proper translation -->
<string name="error_opening_dm">Something went wrong while we were creating this conversation…</string> <!-- TODO - Add proper translation -->
<string name="retry">Retry</string> <!-- TODO - Add proper translation -->
<!-- Report --> <!-- Report -->
<string name="submit">Submit</string> <!--TODO - Add proper translation--> <string name="submit">Submit</string> <!--TODO - Add proper translation-->
......
...@@ -338,10 +338,7 @@ ...@@ -338,10 +338,7 @@
<string name="message_room_changed_privacy">Room type changed to: %1$s by %2$s</string> <string name="message_room_changed_privacy">Room type changed to: %1$s by %2$s</string>
<!-- User Details --> <!-- User Details -->
<string name="message">Message</string> <!-- TODO - Add proper translation -->
<string name="timezone">Timezone</string> <!-- TODO - Add proper translation --> <string name="timezone">Timezone</string> <!-- TODO - Add proper translation -->
<string name="error_opening_dm">Something went wrong while we were creating this conversation…</string> <!-- TODO - Add proper translation -->
<string name="retry">Retry</string> <!-- TODO - Add proper translation -->
<!-- Report --> <!-- Report -->
<string name="submit">Submit</string> <!-- TODO - Add proper translation --> <string name="submit">Submit</string> <!-- TODO - Add proper translation -->
......
...@@ -336,10 +336,7 @@ ...@@ -336,10 +336,7 @@
<string name="message_room_changed_privacy">%2$s ने रूम का प्रकार बदलकर %1$s किया </string> <string name="message_room_changed_privacy">%2$s ने रूम का प्रकार बदलकर %1$s किया </string>
<!-- User Details --> <!-- User Details -->
<string name="message">संदेश</string>
<string name="timezone">समय क्षेत्र</string> <string name="timezone">समय क्षेत्र</string>
<string name="error_opening_dm">जब हम इस बातचीत को बना रहे थे तो कुछ गड़बड़ हुई …</string>
<string name="retry">पुन: प्रयास करें</string>
<!-- Report --> <!-- Report -->
<string name="submit">जमा करें</string> <string name="submit">जमा करें</string>
......
...@@ -331,10 +331,7 @@ ...@@ -331,10 +331,7 @@
<string name="message_room_changed_privacy">Il tipo di stanza è cambiato in: %1$s da %2$s</string> <string name="message_room_changed_privacy">Il tipo di stanza è cambiato in: %1$s da %2$s</string>
<!-- User Details --> <!-- User Details -->
<string name="message">Messaggio</string>
<string name="timezone">Fuso Orario</string> <string name="timezone">Fuso Orario</string>
<string name="error_opening_dm">È successo qualcosa di sbagliato durante la creazione di questa conversazione...</string>
<string name="retry">Riprova</string>
<!-- Report --> <!-- Report -->
<string name="submit">Invia</string> <string name="submit">Invia</string>
......
...@@ -339,10 +339,7 @@ ...@@ -339,10 +339,7 @@
<string name="message_room_changed_privacy">ルームタイプを %2$s から %1$s に変更しました</string> <string name="message_room_changed_privacy">ルームタイプを %2$s から %1$s に変更しました</string>
<!-- User Details --> <!-- User Details -->
<string name="message">Message</string> <!--TODO - Add proper translation-->
<string name="timezone">Timezone</string> <!--TODO - Add proper translation--> <string name="timezone">Timezone</string> <!--TODO - Add proper translation-->
<string name="error_opening_dm">Something went wrong while we were creating this conversation…</string> <!-- TODO - Add proper translation -->
<string name="retry">Retry</string> <!-- TODO - Add proper translation -->
<!-- Report --> <!-- Report -->
<string name="submit">Submit</string> <!--TODO - Add proper translation--> <string name="submit">Submit</string> <!--TODO - Add proper translation-->
......
...@@ -336,10 +336,7 @@ ...@@ -336,10 +336,7 @@
<string name="message_room_changed_privacy">O tipo da sala mudou para: %1$s por %2$s</string> <string name="message_room_changed_privacy">O tipo da sala mudou para: %1$s por %2$s</string>
<!-- User Details --> <!-- User Details -->
<string name="message">Mensagem</string>
<string name="timezone">Fuso horário</string> <string name="timezone">Fuso horário</string>
<string name="error_opening_dm">Algo deu errado quando tentamos abrir esta conversa…</string>
<string name="retry">Retentar</string>
<!-- Report --> <!-- Report -->
<string name="submit">Enviar</string> <string name="submit">Enviar</string>
......
...@@ -333,10 +333,7 @@ ...@@ -333,10 +333,7 @@
<string name="message_room_changed_privacy">Тип канала изменен на: %1$s пользователем %2$s</string> <string name="message_room_changed_privacy">Тип канала изменен на: %1$s пользователем %2$s</string>
<!-- User Details --> <!-- User Details -->
<string name="message">Сообщение</string>
<string name="timezone">Часовой поясe</string> <string name="timezone">Часовой поясe</string>
<string name="error_opening_dm">При создании этого диалога что-то пошло не так...</string>
<string name="retry">Повторить</string>
<!-- Report --> <!-- Report -->
<string name="submit">Отправить</string> <string name="submit">Отправить</string>
......
...@@ -337,10 +337,7 @@ ...@@ -337,10 +337,7 @@
<string name="message_room_changed_privacy">Room type changed to: %1$s by %2$s</string> <!--TODO - Add proper translation--> <string name="message_room_changed_privacy">Room type changed to: %1$s by %2$s</string> <!--TODO - Add proper translation-->
<!-- User Details --> <!-- User Details -->
<string name="message">Message</string> <!--TODO - Add proper translation-->
<string name="timezone">Timezone</string> <!--TODO - Add proper translation--> <string name="timezone">Timezone</string> <!--TODO - Add proper translation-->
<string name="error_opening_dm">Something went wrong while we were creating this conversation…</string> <!-- TODO - Add proper translation -->
<string name="retry">Retry</string> <!-- TODO - Add proper translation -->
<!-- Report --> <!-- Report -->
<string name="submit">Submit</string> <!--TODO - Add proper translation--> <string name="submit">Submit</string> <!--TODO - Add proper translation-->
......
...@@ -335,10 +335,7 @@ ...@@ -335,10 +335,7 @@
<string name="message_room_changed_privacy">Room type changed to: %1$s by %2$s</string> <!-- TODO - Add proper translation --> <string name="message_room_changed_privacy">Room type changed to: %1$s by %2$s</string> <!-- TODO - Add proper translation -->
<!-- User Details --> <!-- User Details -->
<string name="message">Message</string>
<string name="timezone">Timezone</string> <string name="timezone">Timezone</string>
<string name="error_opening_dm">Something went wrong while we were creating this conversation…</string> <!-- TODO - Add proper translation -->
<string name="retry">Retry</string> <!-- TODO - Add proper translation -->
<!-- Report --> <!-- Report -->
<string name="submit">Submit</string> <!-- TODO - Add proper translation --> <string name="submit">Submit</string> <!-- TODO - Add proper translation -->
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
<color name="colorTimestampText">#FF9DA2A9</color> <color name="colorTimestampText">#FF9DA2A9</color>
<color name="colorTimestampTextUnread">#FF5699FF</color> <color name="colorTimestampTextUnread">#FF5699FF</color>
<color name="colorLastMessageText">#99000000</color> <color name="colorLastMessageText">#99000000</color>
<color name="colorUserDetailsNameText">#FF0C0D0F</color>
<color name="colorUserDetailsUsernameText">#8B000000</color>
<!-- User status colors --> <!-- User status colors -->
<color name="colorUserStatusOnline">#2FE1A8</color> <color name="colorUserStatusOnline">#2FE1A8</color>
......
...@@ -350,11 +350,8 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin ...@@ -350,11 +350,8 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="foss" translatable="false">(FOSS)</string> <string name="foss" translatable="false">(FOSS)</string>
<!-- User Details --> <!-- User Details -->
<string name="message">Message</string>
<string name="timezone">Timezone</string> <string name="timezone">Timezone</string>
<string name="status" translatable="false">Status</string> <string name="status" translatable="false">Status</string>
<string name="error_opening_dm">Something went wrong while we were creating this conversation…</string>
<string name="retry">Retry</string>
<!-- Report --> <!-- Report -->
<string name="submit">Submit</string> <string name="submit">Submit</string>
......
...@@ -155,6 +155,43 @@ ...@@ -155,6 +155,43 @@
</style> </style>
<!-- End chat list --> <!-- End chat list -->
<!-- User details -->
<style name="UserDetails.TextView.Name" parent="TextAppearance.AppCompat">
<item name="android:textSize">18sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">@color/colorUserDetailsNameText</item>
</style>
<style name="UserDetails.TextView.Username" parent="TextAppearance.AppCompat">
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@color/colorUserDetailsUsernameText</item>
</style>
<style name="UserDetails.TextView.Actions" parent="TextAppearance.AppCompat">
<item name="android:textSize">16sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@color/colorAccent</item>
</style>
<style name="UserDetails.TextView.Title" parent="TextAppearance.AppCompat">
<item name="android:textSize">12sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@color/colorAuthenticationSecondaryText</item>
</style>
<style name="UserDetails.TextView.Description" parent="TextAppearance.AppCompat">
<item name="android:textSize">16sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@color/colorPrimary</item>
</style>
<!-- End user details-->
<style name="EditText.Password" parent="TextAppearance.AppCompat"> <style name="EditText.Password" parent="TextAppearance.AppCompat">
<!-- Hint color and label color in FALSE state --> <!-- Hint color and label color in FALSE state -->
<item name="android:textColorHint">@color/colorPrimaryDark</item> <item name="android:textColorHint">@color/colorPrimaryDark</item>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment