Commit e0ef6159 authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Merge branch 'develop' of github.com:RocketChat/Rocket.Chat.Android into new/video-call-support

Also enables the video conferencing from the UserDetails fragment.
parents 85e5b838 3525893c
...@@ -43,8 +43,8 @@ cd Rocket.Chat.Android/app ...@@ -43,8 +43,8 @@ cd Rocket.Chat.Android/app
## Bug report & Feature request ## Bug report & Feature request
Are you having a technical issue trying to compile the app, or setting up Push Notifications? Please use our Community Support channel for that: https://forums.rocket.chat/c/community-support. The issues are only suppose to be used for bugs, improvements and features in the native Android application. Are you having a technical issue trying to compile the app, or setting up Push Notifications? Please use our Community Support channel for that: https://forums.rocket.chat/c/community-support. The issues are only supposed to be used for bugs, improvements, and features in the native Android application.
## Coding Style ## Coding Style
Please follow the official [Kotlin coding convections](https://kotlinlang.org/docs/reference/coding-conventions.html) when contributing. Please follow the official [Kotlin coding conventions](https://kotlinlang.org/docs/reference/coding-conventions.html) when contributing.
...@@ -99,87 +99,68 @@ android { ...@@ -99,87 +99,68 @@ 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.coroutinesCore implementation libraries.coroutinesCore
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.livedataKtx implementation libraries.livedataKtx
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
kapt libraries.kotshiCompiler kapt libraries.kotshiCompiler
implementation libraries.kotshiApi implementation libraries.kotshiApi
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.frescoImageViewer implementation libraries.frescoImageViewer
implementation libraries.markwon implementation libraries.markwon
implementation libraries.aVLoadingIndicatorView implementation libraries.aVLoadingIndicatorView
implementation libraries.glide implementation libraries.glide
implementation libraries.glideTransformations implementation libraries.glideTransformations
implementation(libraries.jitsi) { transitive = true } implementation(libraries.jitsi) { transitive = true }
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.8@aar') { transitive = true } playImplementation('com.crashlytics.sdk.android:crashlytics:2.9.8@aar') { transitive = true }
playImplementation('com.crashlytics.sdk.android:answers:1.4.6@aar') { transitive = true } playImplementation('com.crashlytics.sdk.android:answers:1.4.6@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/core-2af5921.jar')
implementation files('libs/common-2af5921.jar')
} }
androidExtensions { androidExtensions {
......
...@@ -34,12 +34,16 @@ class AboutFragment : Fragment() { ...@@ -34,12 +34,16 @@ class AboutFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setupToolbar()
setupViews() setupViews()
analyticsManager.logScreenView(ScreenViewEvent.About) analyticsManager.logScreenView(ScreenViewEvent.About)
} }
override fun onResume() {
super.onResume()
setupToolbar()
}
private fun setupViews() { private fun setupViews() {
text_version_name.text = BuildConfig.VERSION_NAME text_version_name.text = BuildConfig.VERSION_NAME
text_build_number.text = getString( text_build_number.text = getString(
......
import android.content.Context import android.content.Context
import chat.rocket.android.R import chat.rocket.android.R
import org.threeten.bp.* import org.threeten.bp.Instant
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime
import org.threeten.bp.LocalTime
import org.threeten.bp.Period
import org.threeten.bp.ZoneId
import org.threeten.bp.format.DateTimeFormatter import org.threeten.bp.format.DateTimeFormatter
import org.threeten.bp.format.FormatStyle import org.threeten.bp.format.FormatStyle
import org.threeten.bp.format.TextStyle import org.threeten.bp.format.TextStyle
...@@ -53,39 +58,39 @@ object DateTimeHelper { ...@@ -53,39 +58,39 @@ object DateTimeHelper {
} }
} }
/** /**
* Returns a time from a [LocalDateTime]. * Returns a time from a [LocalDateTime].
* *
* @param localDateTime The [LocalDateTime]. * @param localDateTime The [LocalDateTime].
* @return The time from a [LocalDateTime]. * @return The time from a [LocalDateTime].
*/ */
fun getTime(localDateTime: LocalDateTime): String { fun getTime(localDateTime: LocalDateTime): String {
val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
return localDateTime.toLocalTime().format(formatter).toString() return localDateTime.toLocalTime().format(formatter).toString()
} }
/** /**
* Returns a date time from a [LocalDateTime]. * Returns a date time from a [LocalDateTime].
* *
* @param localDateTime The [LocalDateTime]. * @param localDateTime The [LocalDateTime].
* @return The time from a [LocalDateTime]. * @return The time from a [LocalDateTime].
*/ */
fun getDateTime(localDateTime: LocalDateTime): String { fun getDateTime(localDateTime: LocalDateTime): String {
return formatLocalDateTime(localDateTime) return formatLocalDateTime(localDateTime)
} }
private fun formatLocalDateTime(localDateTime: LocalDateTime): String { private fun formatLocalDateTime(localDateTime: LocalDateTime): String {
val formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT) val formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
return localDateTime.format(formatter).toString() return localDateTime.format(formatter).toString()
} }
private fun formatLocalDate(localDate: LocalDate): String { private fun formatLocalDate(localDate: LocalDate): String {
val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM) val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
return localDate.format(formatter).toString() return localDate.format(formatter).toString()
} }
private fun formatLocalTime(localTime: LocalTime): String { private fun formatLocalTime(localTime: LocalTime): String {
val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
return localTime.format(formatter).toString() return localTime.format(formatter).toString()
} }
} }
\ No newline at end of file
...@@ -8,7 +8,8 @@ import chat.rocket.android.server.domain.MultiServerTokenRepository ...@@ -8,7 +8,8 @@ import chat.rocket.android.server.domain.MultiServerTokenRepository
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
@PerActivity @PerActivity
class SharedPreferencesMultiServerTokenRepository(private val repository: LocalRepository, class SharedPreferencesMultiServerTokenRepository(
private val repository: LocalRepository,
private val moshi: Moshi private val moshi: Moshi
) : MultiServerTokenRepository { ) : MultiServerTokenRepository {
...@@ -16,11 +17,7 @@ class SharedPreferencesMultiServerTokenRepository(private val repository: LocalR ...@@ -16,11 +17,7 @@ class SharedPreferencesMultiServerTokenRepository(private val repository: LocalR
val token = repository.get("$TOKEN_KEY$server") val token = repository.get("$TOKEN_KEY$server")
val adapter = moshi.adapter<TokenModel>(TokenModel::class.java) val adapter = moshi.adapter<TokenModel>(TokenModel::class.java)
token?.let { return token?.let { adapter.fromJson(it) }
return adapter.fromJson(token)
}
return null
} }
override fun save(server: String, token: TokenModel) { override fun save(server: String, token: TokenModel) {
......
...@@ -39,12 +39,10 @@ internal const val REQUEST_CODE_FOR_SIGN_IN_REQUIRED = 1 ...@@ -39,12 +39,10 @@ internal const val REQUEST_CODE_FOR_SIGN_IN_REQUIRED = 1
internal const val REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION = 2 internal const val REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION = 2
internal const val REQUEST_CODE_FOR_SAVE_RESOLUTION = 3 internal const val REQUEST_CODE_FOR_SAVE_RESOLUTION = 3
fun newInstance(serverName: String): Fragment { fun newInstance(serverName: String): Fragment = LoginFragment().apply {
return LoginFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(SERVER_NAME, serverName) putString(SERVER_NAME, serverName)
} }
}
} }
class LoginFragment : Fragment(), LoginView { class LoginFragment : Fragment(), LoginView {
...@@ -59,9 +57,8 @@ class LoginFragment : Fragment(), LoginView { ...@@ -59,9 +57,8 @@ class LoginFragment : Fragment(), LoginView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { serverName = getString(SERVER_NAME)
serverName = bundle.getString(SERVER_NAME)
} }
} }
...@@ -150,7 +147,7 @@ class LoginFragment : Fragment(), LoginView { ...@@ -150,7 +147,7 @@ class LoginFragment : Fragment(), LoginView {
override fun showGenericErrorMessage() = showMessage(R.string.msg_generic_error) override fun showGenericErrorMessage() = showMessage(R.string.msg_generic_error)
private fun setupOnClickListener() = private fun setupOnClickListener() =
ui { _ -> ui {
button_log_in.setOnClickListener { button_log_in.setOnClickListener {
presenter.authenticateWithUserAndPassword( presenter.authenticateWithUserAndPassword(
text_username_or_email.textContent, text_username_or_email.textContent,
...@@ -160,7 +157,7 @@ class LoginFragment : Fragment(), LoginView { ...@@ -160,7 +157,7 @@ class LoginFragment : Fragment(), LoginView {
} }
override fun showForgotPasswordView() { override fun showForgotPasswordView() {
ui { _ -> ui {
button_forgot_your_password.isVisible = true button_forgot_your_password.isVisible = true
button_forgot_your_password.setOnClickListener { presenter.forgotPassword() } button_forgot_your_password.setOnClickListener { presenter.forgotPassword() }
......
...@@ -88,8 +88,7 @@ fun newInstance( ...@@ -88,8 +88,7 @@ fun newInstance(
isLoginFormEnabled: Boolean, isLoginFormEnabled: Boolean,
isNewAccountCreationEnabled: Boolean, isNewAccountCreationEnabled: Boolean,
deepLinkInfo: LoginDeepLinkInfo? = null deepLinkInfo: LoginDeepLinkInfo? = null
): Fragment { ): Fragment = LoginOptionsFragment().apply {
return LoginOptionsFragment().apply {
arguments = Bundle(23).apply { arguments = Bundle(23).apply {
putString(SERVER_NAME, serverName) putString(SERVER_NAME, serverName)
putString(STATE, state) putString(STATE, state)
...@@ -118,7 +117,6 @@ fun newInstance( ...@@ -118,7 +117,6 @@ fun newInstance(
putBoolean(IS_NEW_ACCOUNT_CREATION_ENABLED, isNewAccountCreationEnabled) putBoolean(IS_NEW_ACCOUNT_CREATION_ENABLED, isNewAccountCreationEnabled)
putParcelable(DEEP_LINK_INFO, deepLinkInfo) putParcelable(DEEP_LINK_INFO, deepLinkInfo)
} }
}
} }
class LoginOptionsFragment : Fragment(), LoginOptionsView { class LoginOptionsFragment : Fragment(), LoginOptionsView {
...@@ -157,34 +155,33 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -157,34 +155,33 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { serverName = getString(SERVER_NAME)
serverName = bundle.getString(SERVER_NAME) state = getString(STATE)
state = bundle.getString(STATE) facebookOauthUrl = getString(FACEBOOK_OAUTH_URL)
facebookOauthUrl = bundle.getString(FACEBOOK_OAUTH_URL) githubOauthUrl = getString(GITHUB_OAUTH_URL)
githubOauthUrl = bundle.getString(GITHUB_OAUTH_URL) googleOauthUrl = getString(GOOGLE_OAUTH_URL)
googleOauthUrl = bundle.getString(GOOGLE_OAUTH_URL) linkedinOauthUrl = getString(LINKEDIN_OAUTH_URL)
linkedinOauthUrl = bundle.getString(LINKEDIN_OAUTH_URL) gitlabOauthUrl = getString(GITLAB_OAUTH_URL)
gitlabOauthUrl = bundle.getString(GITLAB_OAUTH_URL) wordpressOauthUrl = getString(WORDPRESS_OAUTH_URL)
wordpressOauthUrl = bundle.getString(WORDPRESS_OAUTH_URL) casLoginUrl = getString(CAS_LOGIN_URL)
casLoginUrl = bundle.getString(CAS_LOGIN_URL) casToken = getString(CAS_TOKEN)
casToken = bundle.getString(CAS_TOKEN) casServiceName = getString(CAS_SERVICE_NAME)
casServiceName = bundle.getString(CAS_SERVICE_NAME) casServiceNameTextColor = getInt(CAS_SERVICE_NAME_TEXT_COLOR)
casServiceNameTextColor = bundle.getInt(CAS_SERVICE_NAME_TEXT_COLOR) casServiceButtonColor = getInt(CAS_SERVICE_BUTTON_COLOR)
casServiceButtonColor = bundle.getInt(CAS_SERVICE_BUTTON_COLOR) customOauthUrl = getString(CUSTOM_OAUTH_URL)
customOauthUrl = bundle.getString(CUSTOM_OAUTH_URL) customOauthServiceName = getString(CUSTOM_OAUTH_SERVICE_NAME)
customOauthServiceName = bundle.getString(CUSTOM_OAUTH_SERVICE_NAME) customOauthServiceTextColor = getInt(CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR)
customOauthServiceTextColor = bundle.getInt(CUSTOM_OAUTH_SERVICE_NAME_TEXT_COLOR) customOauthServiceButtonColor = getInt(CUSTOM_OAUTH_SERVICE_BUTTON_COLOR)
customOauthServiceButtonColor = bundle.getInt(CUSTOM_OAUTH_SERVICE_BUTTON_COLOR) samlUrl = getString(SAML_URL)
samlUrl = bundle.getString(SAML_URL) samlToken = getString(SAML_TOKEN)
samlToken = bundle.getString(SAML_TOKEN) samlServiceName = getString(SAML_SERVICE_NAME)
samlServiceName = bundle.getString(SAML_SERVICE_NAME) samlServiceTextColor = getInt(SAML_SERVICE_NAME_TEXT_COLOR)
samlServiceTextColor = bundle.getInt(SAML_SERVICE_NAME_TEXT_COLOR) samlServiceButtonColor = getInt(SAML_SERVICE_BUTTON_COLOR)
samlServiceButtonColor = bundle.getInt(SAML_SERVICE_BUTTON_COLOR) totalSocialAccountsEnabled = getInt(TOTAL_SOCIAL_ACCOUNTS)
totalSocialAccountsEnabled = bundle.getInt(TOTAL_SOCIAL_ACCOUNTS) isLoginFormEnabled = getBoolean(IS_LOGIN_FORM_ENABLED)
isLoginFormEnabled = bundle.getBoolean(IS_LOGIN_FORM_ENABLED) isNewAccountCreationEnabled = getBoolean(IS_NEW_ACCOUNT_CREATION_ENABLED)
isNewAccountCreationEnabled = bundle.getBoolean(IS_NEW_ACCOUNT_CREATION_ENABLED) deepLinkInfo = getParcelable(DEEP_LINK_INFO)
deepLinkInfo = bundle.getParcelable(DEEP_LINK_INFO)
} }
} }
...@@ -388,7 +385,7 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -388,7 +385,7 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
} }
override fun setupExpandAccountsView() { override fun setupExpandAccountsView() {
ui { _ -> ui {
expand_more_accounts_container.isVisible = true expand_more_accounts_container.isVisible = true
var isAccountsCollapsed = true var isAccountsCollapsed = true
button_expand_collapse_accounts.setOnClickListener { button_expand_collapse_accounts.setOnClickListener {
...@@ -406,14 +403,14 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -406,14 +403,14 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
} }
override fun showLoginWithEmailButton() { override fun showLoginWithEmailButton() {
ui { _ -> ui {
button_login_with_email.setOnClickListener { presenter.toLoginWithEmail() } button_login_with_email.setOnClickListener { presenter.toLoginWithEmail() }
button_login_with_email.isVisible = true button_login_with_email.isVisible = true
} }
} }
override fun showCreateNewAccountButton() { override fun showCreateNewAccountButton() {
ui { _ -> ui {
button_create_an_account.setOnClickListener { presenter.toCreateAccount() } button_create_an_account.setOnClickListener { presenter.toCreateAccount() }
button_create_an_account.isVisible = true button_create_an_account.isVisible = true
} }
......
...@@ -31,13 +31,11 @@ import javax.inject.Inject ...@@ -31,13 +31,11 @@ import javax.inject.Inject
private const val BUNDLE_USER_ID = "user_id" private const val BUNDLE_USER_ID = "user_id"
private const val BUNDLE_AUTH_TOKEN = "auth_token" private const val BUNDLE_AUTH_TOKEN = "auth_token"
fun newInstance(userId: String, authToken: String): Fragment { fun newInstance(userId: String, authToken: String): Fragment = RegisterUsernameFragment().apply {
return RegisterUsernameFragment().apply {
arguments = Bundle(2).apply { arguments = Bundle(2).apply {
putString(BUNDLE_USER_ID, userId) putString(BUNDLE_USER_ID, userId)
putString(BUNDLE_AUTH_TOKEN, authToken) putString(BUNDLE_AUTH_TOKEN, authToken)
} }
}
} }
class RegisterUsernameFragment : Fragment(), RegisterUsernameView { class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
...@@ -53,13 +51,10 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView { ...@@ -53,13 +51,10 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { userId = getString(BUNDLE_USER_ID, "")
userId = bundle.getString(BUNDLE_USER_ID) authToken = getString(BUNDLE_AUTH_TOKEN, "")
authToken = bundle.getString(BUNDLE_AUTH_TOKEN) } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
} }
override fun onCreateView( override fun onCreateView(
......
...@@ -75,7 +75,7 @@ class SignupFragment : Fragment(), SignupView { ...@@ -75,7 +75,7 @@ class SignupFragment : Fragment(), SignupView {
} }
private fun setupOnClickListener() = private fun setupOnClickListener() =
ui { _ -> ui {
button_register.setOnClickListener { button_register.setOnClickListener {
presenter.signup( presenter.signup(
text_username.textContent, text_username.textContent,
......
...@@ -25,13 +25,11 @@ import io.reactivex.disposables.Disposable ...@@ -25,13 +25,11 @@ import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.fragment_authentication_two_fa.* import kotlinx.android.synthetic.main.fragment_authentication_two_fa.*
import javax.inject.Inject import javax.inject.Inject
fun newInstance(username: String, password: String): Fragment { fun newInstance(username: String, password: String): Fragment = TwoFAFragment().apply {
return TwoFAFragment().apply {
arguments = Bundle(2).apply { arguments = Bundle(2).apply {
putString(BUNDLE_USERNAME, username) putString(BUNDLE_USERNAME, username)
putString(BUNDLE_PASSWORD, password) putString(BUNDLE_PASSWORD, password)
} }
}
} }
private const val BUNDLE_USERNAME = "username" private const val BUNDLE_USERNAME = "username"
...@@ -50,13 +48,10 @@ class TwoFAFragment : Fragment(), TwoFAView { ...@@ -50,13 +48,10 @@ class TwoFAFragment : Fragment(), TwoFAView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { username = getString(BUNDLE_USERNAME, "")
username = bundle.getString(BUNDLE_USERNAME) password = getString(BUNDLE_PASSWORD, "")
password = bundle.getString(BUNDLE_PASSWORD) } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
} }
override fun onCreateView( override fun onCreateView(
......
package chat.rocket.android.chatdetails.adapter package chat.rocket.android.chatdetails.adapter
import android.content.Context import DrawableHelper
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
......
...@@ -11,9 +11,15 @@ import chat.rocket.android.util.extensions.inflate ...@@ -11,9 +11,15 @@ import chat.rocket.android.util.extensions.inflate
class ChatDetailsAdapter: RecyclerView.Adapter<OptionViewHolder>() { class ChatDetailsAdapter: RecyclerView.Adapter<OptionViewHolder>() {
private val options: MutableList<Option> = ArrayList() private val options: MutableList<Option> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OptionViewHolder = OptionViewHolder(parent.inflate(R.layout.item_detail_option)) override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): OptionViewHolder = OptionViewHolder(parent.inflate(R.layout.item_detail_option))
override fun onBindViewHolder(holder: OptionViewHolder, position: Int) = holder.bindViews(OptionItemHolder(options[position])) override fun onBindViewHolder(
holder: OptionViewHolder,
position: Int
) = holder.bindViews(OptionItemHolder(options[position]))
override fun getItemCount(): Int = options.size override fun getItemCount(): Int = options.size
......
...@@ -81,16 +81,13 @@ class ChatDetailsFragment : Fragment(), ChatDetailsView { ...@@ -81,16 +81,13 @@ class ChatDetailsFragment : Fragment(), ChatDetailsView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { chatRoomId = getString(BUNDLE_CHAT_ROOM_ID)
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID) chatRoomType = getString(BUNDLE_CHAT_ROOM_TYPE)
chatRoomType = bundle.getString(BUNDLE_CHAT_ROOM_TYPE) isSubscribed = getBoolean(BUNDLE_IS_SUBSCRIBED)
isSubscribed = bundle.getBoolean(BUNDLE_IS_SUBSCRIBED) isFavorite = getBoolean(BUNDLE_IS_FAVORITE)
isFavorite = bundle.getBoolean(BUNDLE_IS_FAVORITE) disableMenu = getBoolean(BUNDLE_DISABLE_MENU)
disableMenu = bundle.getBoolean(BUNDLE_DISABLE_MENU) } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
setHasOptionsMenu(true) setHasOptionsMenu(true)
} }
......
...@@ -5,9 +5,10 @@ import androidx.lifecycle.ViewModelProvider ...@@ -5,9 +5,10 @@ import androidx.lifecycle.ViewModelProvider
import chat.rocket.android.db.ChatRoomDao import chat.rocket.android.db.ChatRoomDao
import javax.inject.Inject import javax.inject.Inject
class ChatDetailsViewModelFactory @Inject constructor(private val chatRoomDao: ChatRoomDao) : ViewModelProvider.NewInstanceFactory() { class ChatDetailsViewModelFactory @Inject constructor(
private val chatRoomDao: ChatRoomDao
) : ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>) = override fun <T : ViewModel?> create(modelClass: Class<T>) = ChatDetailsViewModel(chatRoomDao) as T
ChatDetailsViewModel(chatRoomDao) as T
} }
\ No newline at end of file
...@@ -12,7 +12,10 @@ import com.facebook.drawee.backends.pipeline.Fresco ...@@ -12,7 +12,10 @@ import com.facebook.drawee.backends.pipeline.Fresco
import kotlinx.android.synthetic.main.item_action_button.view.* import kotlinx.android.synthetic.main.item_action_button.view.*
import timber.log.Timber import timber.log.Timber
class ActionsListAdapter(actions: List<Action>, var actionAttachmentOnClickListener: ActionAttachmentOnClickListener) : RecyclerView.Adapter<ActionsListAdapter.ViewHolder>() { class ActionsListAdapter(
actions: List<Action>,
var actionAttachmentOnClickListener: ActionAttachmentOnClickListener
) : RecyclerView.Adapter<ActionsListAdapter.ViewHolder>() {
var actions: List<Action> = actions var actions: List<Action> = actions
...@@ -62,9 +65,7 @@ class ActionsListAdapter(actions: List<Action>, var actionAttachmentOnClickListe ...@@ -62,9 +65,7 @@ class ActionsListAdapter(actions: List<Action>, var actionAttachmentOnClickListe
return ViewHolder(view) return ViewHolder(view)
} }
override fun getItemCount(): Int { override fun getItemCount(): Int = actions.size
return actions.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val action = actions[position] val action = actions[position]
......
...@@ -73,13 +73,9 @@ class ChatRoomAdapter( ...@@ -73,13 +73,9 @@ class ChatRoomAdapter(
} }
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int = dataSet[position].viewType
return dataSet[position].viewType
}
override fun getItemCount(): Int { override fun getItemCount(): Int = dataSet.size
return dataSet.size
}
override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) { override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
if (holder !is MessageViewHolder) { if (holder !is MessageViewHolder) {
...@@ -171,12 +167,12 @@ class ChatRoomAdapter( ...@@ -171,12 +167,12 @@ class ChatRoomAdapter(
Timber.d("index: $index") Timber.d("index: $index")
if (index > -1) { if (index > -1) {
dataSet[index] = message dataSet[index] = message
dataSet.forEachIndexed { index, viewModel -> dataSet.forEachIndexed { ind, viewModel ->
if (viewModel.messageId == message.messageId) { if (viewModel.messageId == message.messageId) {
if (viewModel.nextDownStreamMessage == null) { if (viewModel.nextDownStreamMessage == null) {
viewModel.reactions = message.reactions viewModel.reactions = message.reactions
} }
notifyItemChanged(index) notifyItemChanged(ind)
} }
} }
// Delete message only if current is a system message update, i.e.: Message Removed // Delete message only if current is a system message update, i.e.: Message Removed
...@@ -255,10 +251,10 @@ class ChatRoomAdapter( ...@@ -255,10 +251,10 @@ class ChatRoomAdapter(
actionSelectListener?.editMessage(roomId, id, message.message) actionSelectListener?.editMessage(roomId, id, message.message)
} }
R.id.action_message_star -> { R.id.action_message_star -> {
actionSelectListener?.toogleStar(id, !item.isChecked) actionSelectListener?.toggleStar(id, !item.isChecked)
} }
R.id.action_message_unpin -> { R.id.action_message_unpin -> {
actionSelectListener?.tooglePin(id, !item.isChecked) actionSelectListener?.togglePin(id, !item.isChecked)
} }
R.id.action_message_delete -> { R.id.action_message_delete -> {
actionSelectListener?.deleteMessage(roomId, id) actionSelectListener?.deleteMessage(roomId, id)
...@@ -295,9 +291,9 @@ class ChatRoomAdapter( ...@@ -295,9 +291,9 @@ class ChatRoomAdapter(
fun editMessage(roomId: String, messageId: String, text: String) fun editMessage(roomId: String, messageId: String, text: String)
fun toogleStar(id: String, star: Boolean) fun toggleStar(id: String, star: Boolean)
fun tooglePin(id: String, pin: Boolean) fun togglePin(id: String, pin: Boolean)
fun deleteMessage(roomId: String, id: String) fun deleteMessage(roomId: String, id: String)
......
...@@ -24,8 +24,8 @@ class RoomSuggestionsAdapter : SuggestionsAdapter<RoomSuggestionsViewHolder>("#" ...@@ -24,8 +24,8 @@ class RoomSuggestionsAdapter : SuggestionsAdapter<RoomSuggestionsViewHolder>("#"
override fun bind(item: SuggestionModel, itemClickListener: SuggestionsAdapter.ItemClickListener?) { override fun bind(item: SuggestionModel, itemClickListener: SuggestionsAdapter.ItemClickListener?) {
item as ChatRoomSuggestionUiModel item as ChatRoomSuggestionUiModel
with(itemView) { with(itemView) {
val fullname = itemView.findViewById<TextView>(R.id.text_fullname) val fullname = findViewById<TextView>(R.id.text_fullname)
val name = itemView.findViewById<TextView>(R.id.text_name) val name = findViewById<TextView>(R.id.text_name)
name.text = item.name name.text = item.name
fullname.text = item.fullName fullname.text = item.fullName
setOnClickListener { setOnClickListener {
......
...@@ -15,9 +15,7 @@ class UrlPreviewViewHolder( ...@@ -15,9 +15,7 @@ class UrlPreviewViewHolder(
) : BaseViewHolder<UrlPreviewUiModel>(itemView, listener, reactionListener) { ) : BaseViewHolder<UrlPreviewUiModel>(itemView, listener, reactionListener) {
init { init {
with(itemView) { setupActionMenu(itemView.url_preview_layout)
setupActionMenu(url_preview_layout)
}
} }
override fun bindViews(data: UrlPreviewUiModel) { override fun bindViews(data: UrlPreviewUiModel) {
......
...@@ -180,8 +180,8 @@ class ChatRoomPresenter @Inject constructor( ...@@ -180,8 +180,8 @@ class ChatRoomPresenter @Inject constructor(
chatRoomId?.let { chatRoomId?.let {
manager.addRoomChannel(it, roomChangesChannel) manager.addRoomChannel(it, roomChangesChannel)
for (room in roomChangesChannel) { for (room in roomChangesChannel) {
dbManager.getRoom(room.id)?.let { dbManager.getRoom(room.id)?.let { chatRoom ->
view.onRoomUpdated(roomMapper.map(chatRoom = it, showLastMessage = true)) view.onRoomUpdated(roomMapper.map(chatRoom = chatRoom, showLastMessage = true))
} }
} }
} }
...@@ -314,16 +314,18 @@ class ChatRoomPresenter @Inject constructor( ...@@ -314,16 +314,18 @@ class ChatRoomPresenter @Inject constructor(
fun sendMessage(chatRoomId: String, text: String, messageId: String?) { fun sendMessage(chatRoomId: String, text: String, messageId: String?) {
launchUI(strategy) { launchUI(strategy) {
try { try {
view.disableSendMessageButton()
// ignore message for now, will receive it on the stream // ignore message for now, will receive it on the stream
if (messageId == null) { if (messageId == null) {
val id = UUID.randomUUID().toString() val id = UUID.randomUUID().toString()
val username = userHelper.username() val username = userHelper.username()
val user = userHelper.user()
val newMessage = Message( val newMessage = Message(
id = id, id = id,
roomId = chatRoomId, roomId = chatRoomId,
message = text, message = text,
timestamp = Instant.now().toEpochMilli(), timestamp = Instant.now().toEpochMilli(),
sender = SimpleUser(null, username, username), sender = SimpleUser(user?.id, user?.username ?: username, user?.name),
attachments = null, attachments = null,
avatar = currentServer.avatarUrl(username ?: ""), avatar = currentServer.avatarUrl(username ?: ""),
channels = null, channels = null,
...@@ -1052,7 +1054,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -1052,7 +1054,7 @@ class ChatRoomPresenter @Inject constructor(
launchUI(strategy) { launchUI(strategy) {
try { try {
messagesRepository.getById(messageId)?.let { message -> messagesRepository.getById(messageId)?.let { message ->
getChatRoomAsync(message.roomId)?.let { chatRoom -> getChatRoomAsync(message.roomId)?.let {
val models = mapper.map(message) val models = mapper.map(message)
models.firstOrNull()?.permalink?.let { models.firstOrNull()?.permalink?.let {
view.copyToClipboard(it) view.copyToClipboard(it)
...@@ -1273,10 +1275,8 @@ class ChatRoomPresenter @Inject constructor( ...@@ -1273,10 +1275,8 @@ class ChatRoomPresenter @Inject constructor(
* @param unfinishedMessage The unfinished message to save. * @param unfinishedMessage The unfinished message to save.
*/ */
fun saveDraftMessage(unfinishedMessage: String) { fun saveDraftMessage(unfinishedMessage: String) {
if (unfinishedMessage.isNotBlank()) {
localRepository.save(draftKey, unfinishedMessage) localRepository.save(draftKey, unfinishedMessage)
} }
}
fun clearDraftMessage() { fun clearDraftMessage() {
localRepository.clear(draftKey) localRepository.clear(draftKey)
......
...@@ -30,8 +30,7 @@ fun Context.chatRoomIntent( ...@@ -30,8 +30,7 @@ fun Context.chatRoomIntent(
isCreator: Boolean = false, isCreator: Boolean = false,
isFavorite: Boolean = false, isFavorite: Boolean = false,
chatRoomMessage: String? = null chatRoomMessage: String? = null
): Intent { ): Intent = Intent(this, ChatRoomActivity::class.java).apply {
return Intent(this, ChatRoomActivity::class.java).apply {
putExtra(INTENT_CHAT_ROOM_ID, chatRoomId) putExtra(INTENT_CHAT_ROOM_ID, chatRoomId)
putExtra(INTENT_CHAT_ROOM_NAME, chatRoomName) putExtra(INTENT_CHAT_ROOM_NAME, chatRoomName)
putExtra(INTENT_CHAT_ROOM_TYPE, chatRoomType) putExtra(INTENT_CHAT_ROOM_TYPE, chatRoomType)
...@@ -41,7 +40,6 @@ fun Context.chatRoomIntent( ...@@ -41,7 +40,6 @@ fun Context.chatRoomIntent(
putExtra(INTENT_CHAT_ROOM_IS_CREATOR, isCreator) putExtra(INTENT_CHAT_ROOM_IS_CREATOR, isCreator)
putExtra(INTENT_CHAT_ROOM_IS_FAVORITE, isFavorite) putExtra(INTENT_CHAT_ROOM_IS_FAVORITE, isFavorite)
putExtra(INTENT_CHAT_ROOM_MESSAGE, chatRoomMessage) putExtra(INTENT_CHAT_ROOM_MESSAGE, chatRoomMessage)
}
} }
private const val INTENT_CHAT_ROOM_ID = "chat_room_id" private const val INTENT_CHAT_ROOM_ID = "chat_room_id"
...@@ -79,26 +77,27 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector { ...@@ -79,26 +77,27 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
return return
} }
val chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID) with(intent) {
val chatRoomId = getStringExtra(INTENT_CHAT_ROOM_ID)
requireNotNull(chatRoomId) { "no chat_room_id provided in Intent extras" } requireNotNull(chatRoomId) { "no chat_room_id provided in Intent extras" }
val chatRoomName = intent.getStringExtra(INTENT_CHAT_ROOM_NAME) val chatRoomName = getStringExtra(INTENT_CHAT_ROOM_NAME)
requireNotNull(chatRoomName) { "no chat_room_name provided in Intent extras" } requireNotNull(chatRoomName) { "no chat_room_name provided in Intent extras" }
val chatRoomType = intent.getStringExtra(INTENT_CHAT_ROOM_TYPE) val chatRoomType = getStringExtra(INTENT_CHAT_ROOM_TYPE)
requireNotNull(chatRoomType) { "no chat_room_type provided in Intent extras" } requireNotNull(chatRoomType) { "no chat_room_type provided in Intent extras" }
val isReadOnly = intent.getBooleanExtra(INTENT_CHAT_ROOM_IS_READ_ONLY, true) val isReadOnly = getBooleanExtra(INTENT_CHAT_ROOM_IS_READ_ONLY, true)
val isCreator = intent.getBooleanExtra(INTENT_CHAT_ROOM_IS_CREATOR, false) val isCreator = getBooleanExtra(INTENT_CHAT_ROOM_IS_CREATOR, false)
val isFavorite = intent.getBooleanExtra(INTENT_CHAT_ROOM_IS_FAVORITE, false) val isFavorite = getBooleanExtra(INTENT_CHAT_ROOM_IS_FAVORITE, false)
val chatRoomLastSeen = intent.getLongExtra(INTENT_CHAT_ROOM_LAST_SEEN, -1) val chatRoomLastSeen = getLongExtra(INTENT_CHAT_ROOM_LAST_SEEN, -1)
val isSubscribed = intent.getBooleanExtra(INTENT_CHAT_IS_SUBSCRIBED, true) val isSubscribed = getBooleanExtra(INTENT_CHAT_IS_SUBSCRIBED, true)
val chatRoomMessage = intent.getStringExtra(INTENT_CHAT_ROOM_MESSAGE) val chatRoomMessage = getStringExtra(INTENT_CHAT_ROOM_MESSAGE)
setupToolbar() setupToolbar()
...@@ -118,6 +117,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector { ...@@ -118,6 +117,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
} }
} }
} }
}
override fun onBackPressed() { override fun onBackPressed() {
finishActivity() finishActivity()
......
...@@ -416,21 +416,19 @@ class UiModelMapper @Inject constructor( ...@@ -416,21 +416,19 @@ class UiModelMapper @Inject constructor(
return fullUrl return fullUrl
} }
private fun attachmentText(text: String?, attachment: Attachment?, context: Context): String? { private fun attachmentText(text: String?, attachment: Attachment?, context: Context): String? = attachment?.run {
return if (attachment != null) { with(context) {
when { when {
attachment.imageUrl.isNotNullNorEmpty() -> context.getString(R.string.msg_preview_photo) imageUrl.isNotNullNorEmpty() -> getString(R.string.msg_preview_photo)
attachment.videoUrl.isNotNullNorEmpty() -> context.getString(R.string.msg_preview_video) videoUrl.isNotNullNorEmpty() -> getString(R.string.msg_preview_video)
attachment.audioUrl.isNotNullNorEmpty() -> context.getString(R.string.msg_preview_audio) audioUrl.isNotNullNorEmpty() -> getString(R.string.msg_preview_audio)
attachment.titleLink.isNotNullNorEmpty() && titleLink.isNotNullNorEmpty() &&
attachment.type?.contentEquals("file") == true -> type?.contentEquals("file") == true ->
context.getString(R.string.msg_preview_file) getString(R.string.msg_preview_file)
else -> text else -> text
} }
} else {
text
}
} }
} ?: text
private fun attachmentDescription(attachment: Attachment): String? { private fun attachmentDescription(attachment: Attachment): String? {
return attachment.description return attachment.description
...@@ -464,12 +462,10 @@ class UiModelMapper @Inject constructor( ...@@ -464,12 +462,10 @@ class UiModelMapper @Inject constructor(
subscriptionId = chatRoom.subscriptionId) subscriptionId = chatRoom.subscriptionId)
} }
private fun mapMessagePreview(message: Message): Message { private fun mapMessagePreview(message: Message): Message = when (message.isSystemMessage()) {
return when (message.isSystemMessage()) {
false -> stripMessageQuotes(message) false -> stripMessageQuotes(message)
true -> message.copy(message = getSystemMessage(message).toString()) true -> message.copy(message = getSystemMessage(message).toString())
} }
}
private fun getReactions(message: Message): List<ReactionUiModel> { private fun getReactions(message: Message): List<ReactionUiModel> {
val reactions = message.reactions?.let { val reactions = message.reactions?.let {
...@@ -535,75 +531,36 @@ class UiModelMapper @Inject constructor( ...@@ -535,75 +531,36 @@ class UiModelMapper @Inject constructor(
private fun getTime(timestamp: Long) = DateTimeHelper.getTime(DateTimeHelper.getLocalDateTime(timestamp)) private fun getTime(timestamp: Long) = DateTimeHelper.getTime(DateTimeHelper.getLocalDateTime(timestamp))
private fun getContent(message: Message): CharSequence { private fun getContent(message: Message): CharSequence = when (message.isSystemMessage()) {
return when (message.isSystemMessage()) {
true -> getSystemMessage(message) true -> getSystemMessage(message)
false -> parser.render(message, currentUsername) false -> parser.render(message, currentUsername)
} }
}
private fun getSystemMessage(message: Message): CharSequence { private fun getSystemMessage(message: Message): CharSequence {
val content = when (message.type) { val content = with(context) {
when (message.type) {
//TODO: Add implementation for Welcome type. //TODO: Add implementation for Welcome type.
is MessageType.MessageRemoved -> context.getString(R.string.message_removed) is MessageType.MessageRemoved -> getString(R.string.message_removed)
is MessageType.UserJoined -> context.getString(R.string.message_user_joined_channel) is MessageType.UserJoined -> getString(R.string.message_user_joined_channel)
is MessageType.UserLeft -> context.getString(R.string.message_user_left) is MessageType.UserLeft -> getString(R.string.message_user_left)
is MessageType.UserAdded -> context.getString( is MessageType.UserAdded -> getString(R.string.message_user_added_by, message.message, message.sender?.username)
R.string.message_user_added_by, is MessageType.RoomNameChanged -> getString(R.string.message_room_name_changed, message.message, message.sender?.username)
message.message, is MessageType.UserRemoved -> getString(R.string.message_user_removed_by, message.message, message.sender?.username)
message.sender?.username is MessageType.MessagePinned -> getString(R.string.message_pinned)
) is MessageType.UserMuted -> getString(R.string.message_muted, message.message, message.sender?.username)
is MessageType.RoomNameChanged -> context.getString( is MessageType.UserUnMuted -> getString(R.string.message_unmuted, message.message, message.sender?.username)
R.string.message_room_name_changed, message.message, message.sender?.username is MessageType.SubscriptionRoleAdded -> getString(R.string.message_role_add, message.message, message.role, message.sender?.username)
) is MessageType.SubscriptionRoleRemoved -> getString(R.string.message_role_removed, message.message, message.role, message.sender?.username)
is MessageType.UserRemoved -> context.getString( is MessageType.RoomChangedPrivacy -> getString(R.string.message_room_changed_privacy, message.message, message.sender?.username)
R.string.message_user_removed_by,
message.message,
message.sender?.username
)
is MessageType.MessagePinned -> context.getString(R.string.message_pinned)
is MessageType.UserMuted -> context.getString(
R.string.message_muted,
message.message,
message.sender?.username
)
is MessageType.UserUnMuted -> context.getString(
R.string.message_unmuted,
message.message,
message.sender?.username
)
is MessageType.SubscriptionRoleAdded -> context.getString(
R.string.message_role_add,
message.message,
message.role,
message.sender?.username
)
is MessageType.SubscriptionRoleRemoved -> context.getString(
R.string.message_role_removed,
message.message,
message.role,
message.sender?.username
)
is MessageType.RoomChangedPrivacy -> context.getString(
R.string.message_room_changed_privacy,
message.message,
message.sender?.username
)
is MessageType.JitsiCallStarted -> context.getString( is MessageType.JitsiCallStarted -> context.getString(
R.string.message_video_call_started, message.sender?.username R.string.message_video_call_started, message.sender?.username
) )
else -> { else -> throw InvalidParameterException("Invalid message type: ${message.type}")
throw InvalidParameterException("Invalid message type: ${message.type}")
} }
} }
val spannableMsg = SpannableStringBuilder(content) val spannableMsg = SpannableStringBuilder(content)
spannableMsg.setSpan( spannableMsg.setSpan(StyleSpan(Typeface.ITALIC), 0, spannableMsg.length, 0)
StyleSpan(Typeface.ITALIC), 0, spannableMsg.length, 0 spannableMsg.setSpan(ForegroundColorSpan(Color.GRAY), 0, spannableMsg.length, 0)
)
spannableMsg.setSpan(
ForegroundColorSpan(Color.GRAY), 0, spannableMsg.length, 0
)
return spannableMsg return spannableMsg
} }
} }
\ No newline at end of file
...@@ -36,15 +36,30 @@ class RoomUiModelMapper( ...@@ -36,15 +36,30 @@ class RoomUiModelMapper(
grouped: Boolean = false, grouped: Boolean = false,
showLastMessage: Boolean = true showLastMessage: Boolean = true
): List<ItemHolder<*>> { ): List<ItemHolder<*>> {
val list = ArrayList<ItemHolder<*>>(rooms.size + 4) val list = ArrayList<ItemHolder<*>>(rooms.size + 5)
var lastType: String? = null var lastType: String? = null
rooms.forEach { room -> if (grouped) {
if (grouped && lastType != room.chatRoom.type) { val favRooms = rooms.filter { it.chatRoom.favorite == true }
val unfavRooms = rooms.filterNot { it.chatRoom.favorite == true }
if (favRooms.isNotEmpty()) {
list.add(HeaderItemHolder(context.resources.getString(R.string.header_favorite)))
}
favRooms.forEach { room ->
list.add(RoomItemHolder(map(room, showLastMessage)))
}
unfavRooms.forEach { room ->
if (lastType != room.chatRoom.type) {
list.add(HeaderItemHolder(roomType(room.chatRoom.type))) list.add(HeaderItemHolder(roomType(room.chatRoom.type)))
} }
list.add(RoomItemHolder(map(room, showLastMessage))) list.add(RoomItemHolder(map(room, showLastMessage)))
lastType = room.chatRoom.type lastType = room.chatRoom.type
} }
} else {
rooms.forEach { room ->
list.add(RoomItemHolder(map(room, showLastMessage)))
}
}
return list return list
} }
...@@ -62,8 +77,7 @@ class RoomUiModelMapper( ...@@ -62,8 +77,7 @@ class RoomUiModelMapper(
return list return list
} }
private fun mapUser(user: User): RoomUiModel { private fun mapUser(user: User): RoomUiModel = with(user) {
return with(user) {
val name = mapName(user.username!!, user.name) val name = mapName(user.username!!, user.name)
val status = user.status val status = user.status
val avatar = serverUrl.avatarUrl(user.username!!) val avatar = serverUrl.avatarUrl(user.username!!)
...@@ -78,10 +92,8 @@ class RoomUiModelMapper( ...@@ -78,10 +92,8 @@ class RoomUiModelMapper(
username = username username = username
) )
} }
}
private fun mapRoom(room: Room, showLastMessage: Boolean = true): RoomUiModel { private fun mapRoom(room: Room, showLastMessage: Boolean = true): RoomUiModel = with(room) {
return with(room) {
RoomUiModel( RoomUiModel(
id = id, id = id,
name = name!!, name = name!!,
...@@ -100,14 +112,13 @@ class RoomUiModelMapper( ...@@ -100,14 +112,13 @@ class RoomUiModelMapper(
writable = isChannelWritable(muted) writable = isChannelWritable(muted)
) )
} }
}
fun map(chatRoom: ChatRoom, showLastMessage: Boolean = true): RoomUiModel { fun map(chatRoom: ChatRoom, showLastMessage: Boolean = true): RoomUiModel = with(chatRoom.chatRoom) {
return with(chatRoom.chatRoom) {
val isUnread = alert || unread > 0 val isUnread = alert || unread > 0
val type = roomTypeOf(type) val type = roomTypeOf(type)
val status = chatRoom.status?.let { userStatusOf(it) } val status = chatRoom.status?.let { userStatusOf(it) }
val roomName = mapName(name, fullname) val roomName = mapName(name, fullname)
val favorite = favorite
val timestamp = mapDate(lastMessageTimestamp ?: updatedAt) val timestamp = mapDate(lastMessageTimestamp ?: updatedAt)
val avatar = if (type is RoomType.DirectMessage) { val avatar = if (type is RoomType.DirectMessage) {
serverUrl.avatarUrl(name) serverUrl.avatarUrl(name)
...@@ -128,8 +139,7 @@ class RoomUiModelMapper( ...@@ -128,8 +139,7 @@ class RoomUiModelMapper(
} }
val hasMentions = mapMentions(userMentions, groupMentions) val hasMentions = mapMentions(userMentions, groupMentions)
val open = open val open = open
val lastMessageMarkdown = val lastMessageMarkdown = lastMessage?.let { Markwon.markdown(context, it.toString()).toString() }
lastMessage?.let { Markwon.markdown(context, it.toString()).toString() }
RoomUiModel( RoomUiModel(
id = id, id = id,
...@@ -140,6 +150,7 @@ class RoomUiModelMapper( ...@@ -140,6 +150,7 @@ class RoomUiModelMapper(
date = timestamp, date = timestamp,
unread = unread, unread = unread,
mentions = hasMentions, mentions = hasMentions,
favorite = favorite,
alert = isUnread, alert = isUnread,
lastMessage = lastMessageMarkdown, lastMessage = lastMessageMarkdown,
status = status, status = status,
...@@ -148,21 +159,19 @@ class RoomUiModelMapper( ...@@ -148,21 +159,19 @@ class RoomUiModelMapper(
writable = isChannelWritable(muted) writable = isChannelWritable(muted)
) )
} }
}
private fun isChannelWritable(muted: List<String>?): Boolean { private fun isChannelWritable(muted: List<String>?): Boolean {
val canWriteToReadOnlyChannels = permissions.canPostToReadOnlyChannels() val canWriteToReadOnlyChannels = permissions.canPostToReadOnlyChannels()
return canWriteToReadOnlyChannels || !muted.orEmpty().contains(currentUser?.username) return canWriteToReadOnlyChannels || !muted.orEmpty().contains(currentUser?.username)
} }
private fun roomType(type: String): String { private fun roomType(type: String): String = with(context.resources) {
val resources = context.resources when (type) {
return when (type) { RoomType.CHANNEL -> getString(R.string.header_channel)
RoomType.CHANNEL -> resources.getString(R.string.header_channel) RoomType.PRIVATE_GROUP -> getString(R.string.header_private_groups)
RoomType.PRIVATE_GROUP -> resources.getString(R.string.header_private_groups) RoomType.DIRECT_MESSAGE -> getString(R.string.header_direct_messages)
RoomType.DIRECT_MESSAGE -> resources.getString(R.string.header_direct_messages) RoomType.LIVECHAT -> getString(R.string.header_live_chats)
RoomType.LIVECHAT -> resources.getString(R.string.header_live_chats) else -> getString(R.string.header_unknown)
else -> resources.getString(R.string.header_unknown)
} }
} }
...@@ -195,14 +204,12 @@ class RoomUiModelMapper( ...@@ -195,14 +204,12 @@ class RoomUiModelMapper(
} }
} }
private fun mapUnread(unread: Long): String? { private fun mapUnread(unread: Long): String? = when (unread) {
return when (unread) {
0L -> null 0L -> null
in 1..99 -> unread.toString() in 1..99 -> unread.toString()
else -> context.getString(R.string.msg_more_than_ninety_nine_unread_messages) else -> context.getString(R.string.msg_more_than_ninety_nine_unread_messages)
} }
}
private fun mapMentions(userMentions: Long?, groupMentions: Long?): Boolean { private fun mapMentions(userMentions: Long?, groupMentions: Long?): Boolean {
if (userMentions != null && groupMentions != null) { if (userMentions != null && groupMentions != null) {
......
...@@ -8,6 +8,7 @@ import androidx.core.view.isInvisible ...@@ -8,6 +8,7 @@ import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatrooms.adapter.model.RoomUiModel import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.util.extension.setTextViewAppearance
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
import kotlinx.android.synthetic.main.item_chat.view.* import kotlinx.android.synthetic.main.item_chat.view.*
...@@ -16,12 +17,12 @@ import kotlinx.android.synthetic.main.unread_messages_badge.view.* ...@@ -16,12 +17,12 @@ import kotlinx.android.synthetic.main.unread_messages_badge.view.*
class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit) : class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit) :
ViewHolder<RoomItemHolder>(itemView) { ViewHolder<RoomItemHolder>(itemView) {
private val resources: Resources = itemView.resources private val resources: Resources = itemView.resources
private val channelIcon: Drawable = resources.getDrawable(R.drawable.ic_hashtag_12dp) private val channelIcon: Drawable = resources.getDrawable(R.drawable.ic_hashtag_12dp, null)
private val groupIcon: Drawable = resources.getDrawable(R.drawable.ic_lock_12_dp) private val groupIcon: Drawable = resources.getDrawable(R.drawable.ic_lock_12_dp, null)
private val onlineIcon: Drawable = resources.getDrawable(R.drawable.ic_status_online_12dp) private val onlineIcon: Drawable = resources.getDrawable(R.drawable.ic_status_online_12dp, null)
private val awayIcon: Drawable = resources.getDrawable(R.drawable.ic_status_away_12dp) private val awayIcon: Drawable = resources.getDrawable(R.drawable.ic_status_away_12dp, null)
private val busyIcon: Drawable = resources.getDrawable(R.drawable.ic_status_busy_12dp) private val busyIcon: Drawable = resources.getDrawable(R.drawable.ic_status_busy_12dp, null)
private val offlineIcon: Drawable = resources.getDrawable(R.drawable.ic_status_invisible_12dp) private val offlineIcon: Drawable = resources.getDrawable(R.drawable.ic_status_invisible_12dp, null)
override fun bindViews(data: RoomItemHolder) { override fun bindViews(data: RoomItemHolder) {
val room = data.data val room = data.data
...@@ -53,14 +54,14 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit ...@@ -53,14 +54,14 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit
if (room.unread == null) text_total_unread_messages.text = "!" if (room.unread == null) text_total_unread_messages.text = "!"
if (room.unread != null) text_total_unread_messages.text = room.unread if (room.unread != null) text_total_unread_messages.text = room.unread
if (room.mentions) text_total_unread_messages.text = "@${room.unread}" if (room.mentions) text_total_unread_messages.text = "@${room.unread}"
text_chat_name.setTextAppearance(context, R.style.ChatList_ChatName_Unread_TextView) text_chat_name.setTextViewAppearance(context, R.style.ChatList_ChatName_Unread_TextView)
text_timestamp.setTextAppearance(context, R.style.ChatList_Timestamp_Unread_TextView) text_timestamp.setTextViewAppearance(context, R.style.ChatList_Timestamp_Unread_TextView)
text_last_message.setTextAppearance(context, R.style.ChatList_LastMessage_Unread_TextView) text_last_message.setTextViewAppearance(context, R.style.ChatList_LastMessage_Unread_TextView)
text_total_unread_messages.isVisible = true text_total_unread_messages.isVisible = true
} else { } else {
text_chat_name.setTextAppearance(context, R.style.ChatList_ChatName_TextView) text_chat_name.setTextViewAppearance(context, R.style.ChatList_ChatName_TextView)
text_timestamp.setTextAppearance(context, R.style.ChatList_Timestamp_TextView) text_timestamp.setTextViewAppearance(context, R.style.ChatList_Timestamp_TextView)
text_last_message.setTextAppearance(context, R.style.ChatList_LastMessage_TextView) text_last_message.setTextViewAppearance(context, R.style.ChatList_LastMessage_TextView)
text_total_unread_messages.isInvisible = true text_total_unread_messages.isInvisible = true
} }
...@@ -68,20 +69,16 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit ...@@ -68,20 +69,16 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit
} }
} }
private fun getRoomDrawable(type: RoomType): Drawable? { private fun getRoomDrawable(type: RoomType): Drawable? = when (type) {
return when (type) {
is RoomType.Channel -> channelIcon is RoomType.Channel -> channelIcon
is RoomType.PrivateGroup -> groupIcon is RoomType.PrivateGroup -> groupIcon
else -> null else -> null
} }
}
private fun getStatusDrawable(status: UserStatus): Drawable { private fun getStatusDrawable(status: UserStatus): Drawable = when (status) {
return when (status) {
is UserStatus.Online -> onlineIcon is UserStatus.Online -> onlineIcon
is UserStatus.Away -> awayIcon is UserStatus.Away -> awayIcon
is UserStatus.Busy -> busyIcon is UserStatus.Busy -> busyIcon
else -> offlineIcon else -> offlineIcon
} }
}
} }
\ No newline at end of file
...@@ -19,8 +19,7 @@ class RoomsAdapter(private val listener: (RoomUiModel) -> Unit) : ...@@ -19,8 +19,7 @@ class RoomsAdapter(private val listener: (RoomUiModel) -> Unit) :
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder<*> { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder<*> = when (viewType) {
return when (viewType) {
VIEW_TYPE_ROOM -> { VIEW_TYPE_ROOM -> {
val view = parent.inflate(R.layout.item_chat) val view = parent.inflate(R.layout.item_chat)
RoomViewHolder(view, listener) RoomViewHolder(view, listener)
...@@ -35,7 +34,6 @@ class RoomsAdapter(private val listener: (RoomUiModel) -> Unit) : ...@@ -35,7 +34,6 @@ class RoomsAdapter(private val listener: (RoomUiModel) -> Unit) :
} }
else -> throw IllegalStateException("View type must be either Room, Header or Loading") else -> throw IllegalStateException("View type must be either Room, Header or Loading")
} }
}
override fun getItemCount() = values.size override fun getItemCount() = values.size
...@@ -49,14 +47,12 @@ class RoomsAdapter(private val listener: (RoomUiModel) -> Unit) : ...@@ -49,14 +47,12 @@ class RoomsAdapter(private val listener: (RoomUiModel) -> Unit) :
} }
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int = when (values[position]) {
return when (values[position]) {
is RoomItemHolder -> VIEW_TYPE_ROOM is RoomItemHolder -> VIEW_TYPE_ROOM
is HeaderItemHolder -> VIEW_TYPE_HEADER is HeaderItemHolder -> VIEW_TYPE_HEADER
is LoadingItemHolder -> VIEW_TYPE_LOADING is LoadingItemHolder -> VIEW_TYPE_LOADING
else -> throw IllegalStateException("View type must be either Room, Header or Loading") else -> throw IllegalStateException("View type must be either Room, Header or Loading")
} }
}
override fun onBindViewHolder(holder: ViewHolder<*>, position: Int) { override fun onBindViewHolder(holder: ViewHolder<*>, position: Int) {
if (holder is RoomViewHolder) { if (holder is RoomViewHolder) {
......
...@@ -12,6 +12,7 @@ data class RoomUiModel( ...@@ -12,6 +12,7 @@ data class RoomUiModel(
val date: CharSequence? = null, val date: CharSequence? = null,
val unread: String? = null, val unread: String? = null,
val alert: Boolean = false, val alert: Boolean = false,
val favorite: Boolean? = false,
val mentions: Boolean = false, val mentions: Boolean = false,
val lastMessage: CharSequence? = null, val lastMessage: CharSequence? = null,
val status: UserStatus? = null, val status: UserStatus? = null,
......
...@@ -2,6 +2,7 @@ package chat.rocket.android.chatrooms.presentation ...@@ -2,6 +2,7 @@ package chat.rocket.android.chatrooms.presentation
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatrooms.adapter.model.RoomUiModel import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
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
...@@ -117,6 +118,7 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -117,6 +118,7 @@ class ChatRoomsPresenter @Inject constructor(
retryIO("createDirectMessage($name)") { retryIO("createDirectMessage($name)") {
withTimeout(10000) { withTimeout(10000) {
createDirectMessage(name) createDirectMessage(name)
FetchChatRoomsInteractor(client, dbManager).refreshChatRooms()
} }
} }
val fromTo = mutableListOf(myself.id, id).apply { val fromTo = mutableListOf(myself.id, id).apply {
......
...@@ -36,7 +36,6 @@ import chat.rocket.android.helper.SharedPreferenceHelper ...@@ -36,7 +36,6 @@ import chat.rocket.android.helper.SharedPreferenceHelper
import chat.rocket.android.util.extension.onQueryTextListener import chat.rocket.android.util.extension.onQueryTextListener
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.ifNotNullNorEmpty
import chat.rocket.android.util.extensions.ifNotNullNotEmpty import chat.rocket.android.util.extensions.ifNotNullNotEmpty
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
...@@ -69,22 +68,19 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -69,22 +68,19 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
private var progressDialog: ProgressDialog? = null private var progressDialog: ProgressDialog? = null
companion object { companion object {
fun newInstance(chatRoomId: String? = null): ChatRoomsFragment { fun newInstance(chatRoomId: String? = null): ChatRoomsFragment = ChatRoomsFragment().apply {
return ChatRoomsFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(BUNDLE_CHAT_ROOM_ID, chatRoomId) putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
} }
} }
} }
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
setHasOptionsMenu(true) setHasOptionsMenu(true)
val bundle = arguments arguments?.run {
if (bundle != null) { chatRoomId = getString(BUNDLE_CHAT_ROOM_ID)
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID)
chatRoomId.ifNotNullNotEmpty { roomId -> chatRoomId.ifNotNullNotEmpty { roomId ->
presenter.loadChatRoom(roomId) presenter.loadChatRoom(roomId)
chatRoomId = null chatRoomId = null
...@@ -129,12 +125,14 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -129,12 +125,14 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
) )
) )
recycler_view.itemAnimator = DefaultItemAnimator() recycler_view.itemAnimator = DefaultItemAnimator()
recycler_view.adapter = adapter
viewModel.getChatRooms().observe(viewLifecycleOwner, Observer { rooms -> viewModel.getChatRooms().observe(viewLifecycleOwner, Observer { rooms ->
rooms?.let { rooms?.let {
Timber.d("Got items: $it") Timber.d("Got items: $it")
adapter.values = it adapter.values = it
if (recycler_view.adapter != adapter) {
recycler_view.adapter = adapter
}
if (rooms.isNotEmpty()) { if (rooms.isNotEmpty()) {
text_no_data_to_display.isVisible = false text_no_data_to_display.isVisible = false
} }
...@@ -320,21 +318,20 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -320,21 +318,20 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
ui { ui {
text_connection_status.fadeIn() text_connection_status.fadeIn()
handler.removeCallbacks(dismissStatus) handler.removeCallbacks(dismissStatus)
when (state) { text_connection_status.text = when (state) {
is State.Connected -> { is State.Connected -> {
text_connection_status.text = getString(R.string.status_connected)
handler.postDelayed(dismissStatus, 2000) handler.postDelayed(dismissStatus, 2000)
getString(R.string.status_connected)
}
is State.Disconnected -> getString(R.string.status_disconnected)
is State.Connecting -> getString(R.string.status_connecting)
is State.Authenticating -> getString(R.string.status_authenticating)
is State.Disconnecting -> getString(R.string.status_disconnecting)
is State.Waiting -> getString(R.string.status_waiting, state.seconds)
else -> {
handler.postDelayed(dismissStatus, 500)
""
} }
is State.Disconnected -> text_connection_status.text =
getString(R.string.status_disconnected)
is State.Connecting -> text_connection_status.text =
getString(R.string.status_connecting)
is State.Authenticating -> text_connection_status.text =
getString(R.string.status_authenticating)
is State.Disconnecting -> text_connection_status.text =
getString(R.string.status_disconnecting)
is State.Waiting -> text_connection_status.text =
getString(R.string.status_waiting, state.seconds)
} }
} }
} }
......
...@@ -45,9 +45,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback ...@@ -45,9 +45,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
lateinit var analyticsManager: AnalyticsManager lateinit var analyticsManager: AnalyticsManager
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
private val adapter: MembersAdapter = MembersAdapter { private val adapter: MembersAdapter = MembersAdapter {
if (it.username != null) { it.username?.run { processSelectedMember(this) }
processSelectedMember(it.username)
}
} }
private val compositeDisposable = CompositeDisposable() private val compositeDisposable = CompositeDisposable()
private var channelType: String = RoomType.CHANNEL private var channelType: String = RoomType.CHANNEL
...@@ -294,8 +292,8 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback ...@@ -294,8 +292,8 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
private fun addChip(chipText: String) { private fun addChip(chipText: String) {
val chip = Chip(context) val chip = Chip(context)
chip.chipText = chipText chip.text = chipText
chip.isCloseIconEnabled = true chip.isCloseIconVisible = true
chip.setChipBackgroundColorResource(R.color.icon_grey) chip.setChipBackgroundColorResource(R.color.icon_grey)
setupChipOnCloseIconClickListener(chip) setupChipOnCloseIconClickListener(chip)
chip_group_member.addView(chip) chip_group_member.addView(chip)
...@@ -304,7 +302,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback ...@@ -304,7 +302,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
private fun setupChipOnCloseIconClickListener(chip: Chip) { private fun setupChipOnCloseIconClickListener(chip: Chip) {
chip.setOnCloseIconClickListener { chip.setOnCloseIconClickListener {
removeChip(it) removeChip(it)
removeMember((it as Chip).chipText.toString()) removeMember((it as Chip).text.toString())
// whenever we remove a chip we should process the chip group visibility. // whenever we remove a chip we should process the chip group visibility.
processChipGroupVisibility() processChipGroupVisibility()
} }
......
...@@ -115,7 +115,7 @@ fun Attachment.asEntity(msgId: String, context: Context): List<BaseMessageEntity ...@@ -115,7 +115,7 @@ fun Attachment.asEntity(msgId: String, context: Context): List<BaseMessageEntity
val text = mapAttachmentText(text, attachments?.firstOrNull(), context) val text = mapAttachmentText(text, attachments?.firstOrNull(), context)
val entity = AttachmentEntity( list.add(AttachmentEntity(
_id = attachmentId, _id = attachmentId,
messageId = msgId, messageId = msgId,
title = title, title = title,
...@@ -144,16 +144,14 @@ fun Attachment.asEntity(msgId: String, context: Context): List<BaseMessageEntity ...@@ -144,16 +144,14 @@ fun Attachment.asEntity(msgId: String, context: Context): List<BaseMessageEntity
buttonAlignment = buttonAlignment, buttonAlignment = buttonAlignment,
hasActions = actions?.isNotEmpty() == true, hasActions = actions?.isNotEmpty() == true,
hasFields = fields?.isNotEmpty() == true hasFields = fields?.isNotEmpty() == true
) ))
list.add(entity)
fields?.forEach { field -> fields?.forEach { field ->
val entity = AttachmentFieldEntity( list.add(AttachmentFieldEntity(
attachmentId = attachmentId, attachmentId = attachmentId,
title = field.title, title = field.title,
value = field.value value = field.value
) ))
list.add(entity)
} }
actions?.forEach { action -> actions?.forEach { action ->
...@@ -175,18 +173,14 @@ fun Attachment.asEntity(msgId: String, context: Context): List<BaseMessageEntity ...@@ -175,18 +173,14 @@ fun Attachment.asEntity(msgId: String, context: Context): List<BaseMessageEntity
return list return list
} }
fun mapAttachmentText(text: String?, attachment: Attachment?, context: Context): String? { fun mapAttachmentText(text: String?, attachment: Attachment?, context: Context): String? = attachment?.run {
return if (attachment != null) {
when { when {
attachment.imageUrl.isNotNullNorEmpty() -> context.getString(R.string.msg_preview_photo) imageUrl.isNotNullNorEmpty() -> context.getString(R.string.msg_preview_photo)
attachment.videoUrl.isNotNullNorEmpty() -> context.getString(R.string.msg_preview_video) videoUrl.isNotNullNorEmpty() -> context.getString(R.string.msg_preview_video)
attachment.audioUrl.isNotNullNorEmpty() -> context.getString(R.string.msg_preview_audio) audioUrl.isNotNullNorEmpty() -> context.getString(R.string.msg_preview_audio)
attachment.titleLink.isNotNullNorEmpty() && titleLink.isNotNullNorEmpty() &&
attachment.type?.contentEquals("file") == true -> type?.contentEquals("file") == true ->
context.getString(R.string.msg_preview_file) context.getString(R.string.msg_preview_file)
else -> text else -> text
} }
} else { } ?: text
text \ No newline at end of file
}
}
...@@ -36,8 +36,7 @@ class FavoriteMessagesPresenter @Inject constructor( ...@@ -36,8 +36,7 @@ class FavoriteMessagesPresenter @Inject constructor(
try { try {
view.showLoading() view.showLoading()
dbManager.getRoom(roomId)?.let { dbManager.getRoom(roomId)?.let {
val favoriteMessages = val favoriteMessages = client.getFavoriteMessages(roomId, roomTypeOf(it.chatRoom.type), offset)
client.getFavoriteMessages(roomId, roomTypeOf(it.chatRoom.type), offset)
val messageList = mapper.map(favoriteMessages.result, asNotReversed = true) val messageList = mapper.map(favoriteMessages.result, asNotReversed = true)
view.showFavoriteMessages(messageList) view.showFavoriteMessages(messageList)
offset += 1 * 30 offset += 1 * 30
......
...@@ -25,12 +25,10 @@ import dagger.android.support.AndroidSupportInjection ...@@ -25,12 +25,10 @@ import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_favorite_messages.* import kotlinx.android.synthetic.main.fragment_favorite_messages.*
import javax.inject.Inject import javax.inject.Inject
fun newInstance(chatRoomId: String): Fragment { fun newInstance(chatRoomId: String): Fragment = FavoriteMessagesFragment().apply {
return FavoriteMessagesFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(INTENT_CHAT_ROOM_ID, chatRoomId) putString(INTENT_CHAT_ROOM_ID, chatRoomId)
} }
}
} }
internal const val TAG_FAVORITE_MESSAGES_FRAGMENT = "FavoriteMessagesFragment" internal const val TAG_FAVORITE_MESSAGES_FRAGMENT = "FavoriteMessagesFragment"
...@@ -48,12 +46,9 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView { ...@@ -48,12 +46,9 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { chatRoomId = getString(INTENT_CHAT_ROOM_ID, "")
chatRoomId = bundle.getString(INTENT_CHAT_ROOM_ID) } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
} }
override fun onCreateView( override fun onCreateView(
......
...@@ -30,12 +30,10 @@ import dagger.android.support.AndroidSupportInjection ...@@ -30,12 +30,10 @@ import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_files.* import kotlinx.android.synthetic.main.fragment_files.*
import javax.inject.Inject import javax.inject.Inject
fun newInstance(chatRoomId: String): Fragment { fun newInstance(chatRoomId: String): Fragment = FilesFragment().apply {
return FilesFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(BUNDLE_CHAT_ROOM_ID, chatRoomId) putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
} }
}
} }
internal const val TAG_FILES_FRAGMENT = "FilesFragment" internal const val TAG_FILES_FRAGMENT = "FilesFragment"
...@@ -55,12 +53,9 @@ class FilesFragment : Fragment(), FilesView { ...@@ -55,12 +53,9 @@ class FilesFragment : Fragment(), FilesView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { chatRoomId = getString(BUNDLE_CHAT_ROOM_ID, "")
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID) } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
} }
override fun onCreateView( override fun onCreateView(
......
...@@ -53,8 +53,8 @@ object ImageHelper { ...@@ -53,8 +53,8 @@ object ImageHelper {
) )
val toolbar = Toolbar(context).also { val toolbar = Toolbar(context).also {
it.inflateMenu(R.menu.image_actions) it.inflateMenu(R.menu.image_actions)
it.setOnMenuItemClickListener { it.setOnMenuItemClickListener { view ->
return@setOnMenuItemClickListener when (it.itemId) { return@setOnMenuItemClickListener when (view.itemId) {
R.id.action_save_image -> saveImage(context) R.id.action_save_image -> saveImage(context)
else -> true else -> true
} }
...@@ -62,20 +62,24 @@ object ImageHelper { ...@@ -62,20 +62,24 @@ object ImageHelper {
val titleSize = context.resources val titleSize = context.resources
.getDimensionPixelSize(R.dimen.viewer_toolbar_title) .getDimensionPixelSize(R.dimen.viewer_toolbar_title)
val titleTextView = TextView(context).also { val titleTextView = TextView(context).also { tv ->
it.text = imageName with(tv) {
it.setTextColor(Color.WHITE) text = imageName
it.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleSize.toFloat()) setTextColor(Color.WHITE)
it.ellipsize = TextUtils.TruncateAt.END setTextSize(TypedValue.COMPLEX_UNIT_PX, titleSize.toFloat())
it.setSingleLine() ellipsize = TextUtils.TruncateAt.END
it.typeface = Typeface.DEFAULT_BOLD setSingleLine()
it.setPadding(pad) typeface = Typeface.DEFAULT_BOLD
setPadding(pad)
}
} }
val backArrowView = ImageView(context).also { val backArrowView = ImageView(context).also { imgView ->
it.setImageResource(R.drawable.ic_arrow_back_white_24dp) with(imgView) {
it.setOnClickListener { imageViewer?.onDismiss() } setImageResource(R.drawable.ic_arrow_back_white_24dp)
it.setPadding(0, pad, pad, pad) setOnClickListener { imageViewer?.onDismiss() }
setPadding(0, pad, pad, pad)
}
} }
val layoutParams = AppBarLayout.LayoutParams( val layoutParams = AppBarLayout.LayoutParams(
...@@ -88,15 +92,17 @@ object ImageHelper { ...@@ -88,15 +92,17 @@ object ImageHelper {
} }
val appBarLayout = AppBarLayout(context).also { val appBarLayout = AppBarLayout(context).also {
it.layoutParams = lparams with(it) {
it.setBackgroundColor(Color.BLACK) layoutParams = lparams
it.addView( setBackgroundColor(Color.BLACK)
addView(
toolbar, AppBarLayout.LayoutParams( toolbar, AppBarLayout.LayoutParams(
AppBarLayout.LayoutParams.MATCH_PARENT, AppBarLayout.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
) )
) )
} }
}
val builder = ImageViewer.createPipelineDraweeControllerBuilder() val builder = ImageViewer.createPipelineDraweeControllerBuilder()
.setImageRequest(request) .setImageRequest(request)
......
...@@ -38,6 +38,9 @@ import kotlinx.android.synthetic.main.activity_main.* ...@@ -38,6 +38,9 @@ import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.app_bar.* import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.nav_header.view.* import kotlinx.android.synthetic.main.nav_header.view.*
import javax.inject.Inject import javax.inject.Inject
import android.app.NotificationManager
import android.content.Context
private const val CURRENT_STATE = "current_state" private const val CURRENT_STATE = "current_state"
...@@ -90,6 +93,9 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -90,6 +93,9 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
presenter.toChatList(chatRoomId) presenter.toChatList(chatRoomId)
isFragmentAdded = true isFragmentAdded = true
} }
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE)
as NotificationManager
notificationManager.cancelAll()
} }
override fun onDestroy() { override fun onDestroy() {
......
...@@ -10,8 +10,9 @@ import chat.rocket.android.util.extensions.inflate ...@@ -10,8 +10,9 @@ import chat.rocket.android.util.extensions.inflate
import kotlinx.android.synthetic.main.avatar.view.* import kotlinx.android.synthetic.main.avatar.view.*
import kotlinx.android.synthetic.main.item_member.view.* import kotlinx.android.synthetic.main.item_member.view.*
class MembersAdapter(private val listener: (MemberUiModel) -> Unit) : class MembersAdapter(
RecyclerView.Adapter<MembersAdapter.ViewHolder>() { private val listener: (MemberUiModel) -> Unit
) : RecyclerView.Adapter<MembersAdapter.ViewHolder>() {
private var dataSet: List<MemberUiModel> = ArrayList() private var dataSet: List<MemberUiModel> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MembersAdapter.ViewHolder = override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MembersAdapter.ViewHolder =
...@@ -43,7 +44,8 @@ class MembersAdapter(private val listener: (MemberUiModel) -> Unit) : ...@@ -43,7 +44,8 @@ class MembersAdapter(private val listener: (MemberUiModel) -> Unit) :
fun bind(memberUiModel: MemberUiModel, listener: (MemberUiModel) -> Unit) = with(itemView) { fun bind(memberUiModel: MemberUiModel, listener: (MemberUiModel) -> Unit) = with(itemView) {
image_avatar.setImageURI(memberUiModel.avatarUri) image_avatar.setImageURI(memberUiModel.avatarUri)
text_member.content = memberUiModel.displayName text_member.content = memberUiModel.displayName
text_member.setCompoundDrawablesRelativeWithIntrinsicBounds(DrawableHelper.getUserStatusDrawable(memberUiModel.status, context), null, null, null) text_member.setCompoundDrawablesRelativeWithIntrinsicBounds(
DrawableHelper.getUserStatusDrawable(memberUiModel.status, context), null, null, null)
setOnClickListener { listener(memberUiModel) } setOnClickListener { listener(memberUiModel) }
} }
} }
......
...@@ -3,6 +3,7 @@ package chat.rocket.android.members.presentation ...@@ -3,6 +3,7 @@ package chat.rocket.android.members.presentation
import chat.rocket.android.chatroom.presentation.ChatRoomNavigator import chat.rocket.android.chatroom.presentation.ChatRoomNavigator
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.helper.UserHelper
import chat.rocket.android.members.uimodel.MemberUiModel import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.members.uimodel.MemberUiModelMapper import chat.rocket.android.members.uimodel.MemberUiModelMapper
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
...@@ -23,7 +24,8 @@ class MembersPresenter @Inject constructor( ...@@ -23,7 +24,8 @@ class MembersPresenter @Inject constructor(
@Named("currentServer") private val currentServer: String, @Named("currentServer") private val currentServer: String,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val mapper: MemberUiModelMapper, private val mapper: MemberUiModelMapper,
val factory: RocketChatClientFactory val factory: RocketChatClientFactory,
private val userHelper: UserHelper
) { ) {
private val client: RocketChatClient = factory.create(currentServer) private val client: RocketChatClient = factory.create(currentServer)
private var offset: Long = 0 private var offset: Long = 0
...@@ -59,6 +61,10 @@ class MembersPresenter @Inject constructor( ...@@ -59,6 +61,10 @@ class MembersPresenter @Inject constructor(
} }
fun toMemberDetails(memberUiModel: MemberUiModel) { fun toMemberDetails(memberUiModel: MemberUiModel) {
navigator.toMemberDetails(memberUiModel.userId) with(memberUiModel) {
if (userId != userHelper.user()?.id) {
navigator.toMemberDetails(userId)
}
}
} }
} }
...@@ -27,12 +27,10 @@ import kotlinx.android.synthetic.main.app_bar_chat_room.* ...@@ -27,12 +27,10 @@ import kotlinx.android.synthetic.main.app_bar_chat_room.*
import kotlinx.android.synthetic.main.fragment_members.* import kotlinx.android.synthetic.main.fragment_members.*
import javax.inject.Inject import javax.inject.Inject
fun newInstance(chatRoomId: String): Fragment { fun newInstance(chatRoomId: String): Fragment = MembersFragment().apply {
return MembersFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(BUNDLE_CHAT_ROOM_ID, chatRoomId) putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
} }
}
} }
internal const val TAG_MEMBERS_FRAGMENT = "MembersFragment" internal const val TAG_MEMBERS_FRAGMENT = "MembersFragment"
...@@ -52,12 +50,9 @@ class MembersFragment : Fragment(), MembersView { ...@@ -52,12 +50,9 @@ class MembersFragment : Fragment(), MembersView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { chatRoomId = getString(BUNDLE_CHAT_ROOM_ID, "")
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID) } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
} }
override fun onCreateView( override fun onCreateView(
...@@ -80,7 +75,7 @@ class MembersFragment : Fragment(), MembersView { ...@@ -80,7 +75,7 @@ class MembersFragment : Fragment(), MembersView {
setupToolbar(total) setupToolbar(total)
if (adapter.itemCount == 0) { if (adapter.itemCount == 0) {
adapter.prependData(dataSet) adapter.prependData(dataSet)
if (dataSet.size >= 59) { // TODO Check why the API retorns the specified count -1 if (dataSet.size >= 59) { // TODO Check why the API returns the specified count -1
recycler_view.addOnScrollListener(object : recycler_view.addOnScrollListener(object :
EndlessRecyclerViewScrollListener(linearLayoutManager) { EndlessRecyclerViewScrollListener(linearLayoutManager) {
override fun onLoadMore( override fun onLoadMore(
......
...@@ -25,12 +25,10 @@ import dagger.android.support.AndroidSupportInjection ...@@ -25,12 +25,10 @@ import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_mentions.* import kotlinx.android.synthetic.main.fragment_mentions.*
import javax.inject.Inject import javax.inject.Inject
fun newInstance(chatRoomId: String): Fragment { fun newInstance(chatRoomId: String): Fragment = MentionsFragment().apply {
return MentionsFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(BUNDLE_CHAT_ROOM_ID, chatRoomId) putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
} }
}
} }
internal const val TAG_MENTIONS_FRAGMENT = "MentionsFragment" internal const val TAG_MENTIONS_FRAGMENT = "MentionsFragment"
...@@ -48,12 +46,9 @@ class MentionsFragment : Fragment(), MentionsView { ...@@ -48,12 +46,9 @@ class MentionsFragment : Fragment(), MentionsView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { chatRoomId = getString(BUNDLE_CHAT_ROOM_ID, "")
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID) } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
} }
override fun onCreateView( override fun onCreateView(
......
...@@ -25,12 +25,10 @@ import dagger.android.support.AndroidSupportInjection ...@@ -25,12 +25,10 @@ import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_pinned_messages.* import kotlinx.android.synthetic.main.fragment_pinned_messages.*
import javax.inject.Inject import javax.inject.Inject
fun newInstance(chatRoomId: String): Fragment { fun newInstance(chatRoomId: String): Fragment = PinnedMessagesFragment().apply {
return PinnedMessagesFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(BUNDLE_CHAT_ROOM_ID, chatRoomId) putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
} }
}
} }
internal const val TAG_PINNED_MESSAGES_FRAGMENT = "PinnedMessagesFragment" internal const val TAG_PINNED_MESSAGES_FRAGMENT = "PinnedMessagesFragment"
...@@ -48,12 +46,9 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView { ...@@ -48,12 +46,9 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { chatRoomId = getString(BUNDLE_CHAT_ROOM_ID, "")
chatRoomId = bundle.getString(BUNDLE_CHAT_ROOM_ID) } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
} }
override fun onCreateView( override fun onCreateView(
......
...@@ -38,13 +38,17 @@ class PreferencesFragment : Fragment(), PreferencesView { ...@@ -38,13 +38,17 @@ class PreferencesFragment : Fragment(), PreferencesView {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setupToolbar()
setupListeners() setupListeners()
presenter.loadAnalyticsTrackingInformation() presenter.loadAnalyticsTrackingInformation()
analyticsManager.logScreenView(ScreenViewEvent.Preferences) analyticsManager.logScreenView(ScreenViewEvent.Preferences)
} }
override fun onResume() {
setupToolbar()
super.onResume()
}
override fun setupAnalyticsTrackingView(isAnalyticsTrackingEnabled: Boolean) { override fun setupAnalyticsTrackingView(isAnalyticsTrackingEnabled: Boolean) {
if (BuildConfig.FLAVOR == "foss") { if (BuildConfig.FLAVOR == "foss") {
switch_analytics_tracking.isChecked = false switch_analytics_tracking.isChecked = false
......
...@@ -82,7 +82,7 @@ class ProfilePresenter @Inject constructor( ...@@ -82,7 +82,7 @@ class ProfilePresenter @Inject constructor(
view.showLoading() view.showLoading()
try { try {
user?.id?.let { id -> user?.id?.let { id ->
retryIO { client.updateProfile(id, email, name, username) } retryIO { client.updateProfile(userId = id, email = email, name = name, username = username) }
view.showProfileUpdateSuccessfullyMessage() view.showProfileUpdateSuccessfullyMessage()
view.showProfile( view.showProfile(
serverUrl.avatarUrl(user.username ?: ""), serverUrl.avatarUrl(user.username ?: ""),
...@@ -115,7 +115,7 @@ class ProfilePresenter @Inject constructor( ...@@ -115,7 +115,7 @@ class ProfilePresenter @Inject constructor(
uriInteractor.getInputStream(uri) uriInteractor.getInputStream(uri)
} }
} }
user?.username?.let { view.reloadUserAvatar(it) } user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) }
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
exception.message?.let { exception.message?.let {
view.showMessage(it) view.showMessage(it)
...@@ -143,7 +143,7 @@ class ProfilePresenter @Inject constructor( ...@@ -143,7 +143,7 @@ class ProfilePresenter @Inject constructor(
} }
} }
user?.username?.let { view.reloadUserAvatar(it) } user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) }
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
exception.message?.let { exception.message?.let {
view.showMessage(it) view.showMessage(it)
...@@ -163,7 +163,7 @@ class ProfilePresenter @Inject constructor( ...@@ -163,7 +163,7 @@ class ProfilePresenter @Inject constructor(
user?.id?.let { id -> user?.id?.let { id ->
retryIO { client.resetAvatar(id) } retryIO { client.resetAvatar(id) }
} }
user?.username?.let { view.reloadUserAvatar(it) } user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) }
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
exception.message?.let { exception.message?.let {
view.showMessage(it) view.showMessage(it)
......
...@@ -94,11 +94,13 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -94,11 +94,13 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (resultData != null && resultCode == Activity.RESULT_OK) { resultData?.run {
if (resultCode == Activity.RESULT_OK) {
if (requestCode == REQUEST_CODE_FOR_PERFORM_SAF) { if (requestCode == REQUEST_CODE_FOR_PERFORM_SAF) {
presenter.updateAvatar(resultData.data) data?.let { presenter.updateAvatar(it) }
} else if (requestCode == REQUEST_CODE_FOR_PERFORM_CAMERA) { } else if (requestCode == REQUEST_CODE_FOR_PERFORM_CAMERA) {
presenter.preparePhotoAndUpdateAvatar(resultData.extras["data"] as Bitmap) extras?.get("data")?.let { presenter.preparePhotoAndUpdateAvatar(it as Bitmap) }
}
} }
} }
} }
...@@ -203,8 +205,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -203,8 +205,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} }
private fun setupToolbar() { private fun setupToolbar() {
(activity as AppCompatActivity?)?.supportActionBar?.title = (activity as AppCompatActivity?)?.supportActionBar?.title = getString(R.string.title_profile)
getString(R.string.title_profile)
} }
private fun setupListeners() { private fun setupListeners() {
...@@ -293,19 +294,14 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -293,19 +294,14 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} }
fun showDeleteAccountDialog() { fun showDeleteAccountDialog() {
val passwordEditText = EditText(context)
passwordEditText.hint = getString(R.string.msg_password)
context?.let { context?.let {
val builder = AlertDialog.Builder(it) val passwordEText = EditText(context);
builder.setTitle(R.string.title_are_you_sure) val mDialogView = LayoutInflater.from(it).inflate(R.layout.item_account_delete, null)
.setView(passwordEditText) val mBuilder = AlertDialog.Builder(it)
.setPositiveButton(R.string.action_delete_account) { _, _ ->
presenter.deleteAccount(passwordEditText.text.toString()) mBuilder.setView(mDialogView).setPositiveButton(R.string.action_delete_account) { _, _ ->
} presenter.deleteAccount(passwordEText.text.toString())
.setNegativeButton(android.R.string.no) { dialog, _ -> dialog.cancel() } }.setNegativeButton(android.R.string.no) { dialog, _ -> dialog.cancel() }.create().show()
.create()
.show()
} }
} }
} }
...@@ -12,13 +12,14 @@ import android.os.Build ...@@ -12,13 +12,14 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import android.text.Html
import android.text.Spanned
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.RemoteInput import androidx.core.app.RemoteInput
import android.text.Html
import android.text.Spanned
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.server.domain.GetAccountInteractor import chat.rocket.android.server.domain.GetAccountInteractor
...@@ -303,7 +304,11 @@ class PushManager @Inject constructor( ...@@ -303,7 +304,11 @@ class PushManager @Inject constructor(
// CharSequence extensions // CharSequence extensions
private fun CharSequence.fromHtml(): Spanned { private fun CharSequence.fromHtml(): Spanned {
return Html.fromHtml(this as String) return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(this as String, FROM_HTML_MODE_LEGACY, null, null)
} else {
Html.fromHtml(this as String)
}
} }
// NotificationCompat.Builder extensions // NotificationCompat.Builder extensions
...@@ -383,12 +388,12 @@ data class PushMessage( ...@@ -383,12 +388,12 @@ data class PushMessage(
) : Parcelable { ) : Parcelable {
constructor(parcel: Parcel) : this( constructor(parcel: Parcel) : this(
parcel.readString().orEmpty(),
parcel.readString().orEmpty(),
parcel.readParcelable(PushMessage::class.java.classLoader) ?: PushInfo.EMPTY,
parcel.readString(), parcel.readString(),
parcel.readString(), parcel.readString(),
parcel.readParcelable(PushMessage::class.java.classLoader), parcel.readString().orEmpty(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(), parcel.readString(),
parcel.readString()) parcel.readString())
...@@ -433,9 +438,9 @@ data class PushInfo @KotshiConstructor constructor( ...@@ -433,9 +438,9 @@ data class PushInfo @KotshiConstructor constructor(
} }
constructor(parcel: Parcel) : this( constructor(parcel: Parcel) : this(
parcel.readString(), parcel.readString().orEmpty(),
parcel.readString(), parcel.readString().orEmpty(),
roomTypeOf(parcel.readString()), roomTypeOf(parcel.readString().orEmpty()),
parcel.readString(), parcel.readString(),
parcel.readParcelable(PushInfo::class.java.classLoader)) parcel.readParcelable(PushInfo::class.java.classLoader))
...@@ -481,7 +486,7 @@ data class PushSender @KotshiConstructor constructor( ...@@ -481,7 +486,7 @@ data class PushSender @KotshiConstructor constructor(
val name: String? val name: String?
) : Parcelable { ) : Parcelable {
constructor(parcel: Parcel) : this( constructor(parcel: Parcel) : this(
parcel.readString(), parcel.readString().orEmpty(),
parcel.readString(), parcel.readString(),
parcel.readString()) parcel.readString())
......
...@@ -106,6 +106,7 @@ class ConnectionManager( ...@@ -106,6 +106,7 @@ class ConnectionManager(
resubscribeRooms() resubscribeRooms()
temporaryStatus?.let { client.setTemporaryStatus(it) } temporaryStatus?.let { client.setTemporaryStatus(it) }
} }
is State.Waiting -> Timber.d("Connection in: ${status.seconds}") is State.Waiting -> Timber.d("Connection in: ${status.seconds}")
} }
...@@ -236,7 +237,7 @@ class ConnectionManager( ...@@ -236,7 +237,7 @@ class ConnectionManager(
} }
private fun resubscribeRooms() { private fun resubscribeRooms() {
roomMessagesChannels.toList().map { (roomId, channel) -> roomMessagesChannels.toList().map { (roomId, _) ->
client.subscribeRoomMessages(roomId) { _, id -> client.subscribeRoomMessages(roomId) { _, id ->
Timber.d("Subscribed to $roomId: $id") Timber.d("Subscribed to $roomId: $id")
subscriptionIdMap[roomId] = id subscriptionIdMap[roomId] = id
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infraestructure
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.model.AttachmentActionEntity import chat.rocket.android.db.model.*
import chat.rocket.android.db.model.AttachmentEntity
import chat.rocket.android.db.model.FullMessage
import chat.rocket.android.db.model.ReactionEntity
import chat.rocket.android.db.model.UrlEntity
import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.util.retryDB import chat.rocket.android.util.retryDB
import chat.rocket.common.model.SimpleRoom import chat.rocket.common.model.SimpleRoom
import chat.rocket.common.model.SimpleUser import chat.rocket.common.model.SimpleUser
...@@ -159,8 +154,8 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) { ...@@ -159,8 +154,8 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
} else { } else {
null null
} }
list.add(
val attachment = Attachment( Attachment(
title = title, title = title,
type = type, type = type,
description = description, description = description,
...@@ -190,7 +185,7 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) { ...@@ -190,7 +185,7 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
?: "vertical" else null, ?: "vertical" else null,
actions = actions actions = actions
) )
list.add(attachment) )
} }
} }
return list return list
......
...@@ -47,8 +47,8 @@ class DatabaseMessagesRepository( ...@@ -47,8 +47,8 @@ class DatabaseMessagesRepository(
dbManager.processMessagesBatch(listOf(message)).join() dbManager.processMessagesBatch(listOf(message)).join()
} }
override suspend fun saveAll(messages: List<Message>) { override suspend fun saveAll(newMessages: List<Message>) {
dbManager.processMessagesBatch(messages).join() dbManager.processMessagesBatch(newMessages).join()
} }
override suspend fun removeById(id: String) { override suspend fun removeById(id: String) {
...@@ -79,7 +79,7 @@ class DatabaseMessagesRepository( ...@@ -79,7 +79,7 @@ class DatabaseMessagesRepository(
override suspend fun getLastSyncDate(roomId: String): Long? = withContext(Dispatchers.IO) { override suspend fun getLastSyncDate(roomId: String): Long? = withContext(Dispatchers.IO) {
retryDB("getLastSync($roomId)") { retryDB("getLastSync($roomId)") {
dbManager.messageDao().getLastSync(roomId)?.let { it.timestamp } dbManager.messageDao().getLastSync(roomId)?.timestamp
} }
} }
} }
\ No newline at end of file
...@@ -14,13 +14,8 @@ class SharedPreferencesAccountsRepository( ...@@ -14,13 +14,8 @@ class SharedPreferencesAccountsRepository(
private val moshi: Moshi private val moshi: Moshi
) : AccountsRepository { ) : AccountsRepository {
override fun save(newAccount: Account) { override fun save(account: Account) {
val accounts = load() save(load().filter { item -> item.serverUrl != item.serverUrl }.toMutableList().apply { add(0, account) })
val newList = accounts.filter { account -> newAccount.serverUrl != account.serverUrl }
.toMutableList()
newList.add(0, newAccount)
save(newList)
} }
override fun load(): List<Account> { override fun load(): List<Account> {
...@@ -28,15 +23,11 @@ class SharedPreferencesAccountsRepository( ...@@ -28,15 +23,11 @@ class SharedPreferencesAccountsRepository(
val type = Types.newParameterizedType(List::class.java, Account::class.java) val type = Types.newParameterizedType(List::class.java, Account::class.java)
val adapter = moshi.adapter<List<Account>>(type) val adapter = moshi.adapter<List<Account>>(type)
return adapter.fromJson(json) ?: emptyList() return json?.let { adapter.fromJson(it) ?: emptyList() } ?: emptyList()
} }
override fun remove(serverUrl: String) { override fun remove(serverUrl: String) {
val accounts = load() save(load().filter { account -> serverUrl != account.serverUrl }.toMutableList())
val newList = accounts.filter { account -> serverUrl != account.serverUrl }
.toMutableList()
save(newList)
} }
private fun save(accounts: List<Account>) { private fun save(accounts: List<Account>) {
......
...@@ -15,8 +15,7 @@ class SharedPrefsBasicAuthRepository( ...@@ -15,8 +15,7 @@ class SharedPrefsBasicAuthRepository(
) : BasicAuthRepository { ) : BasicAuthRepository {
override fun save(basicAuth: BasicAuth) { override fun save(basicAuth: BasicAuth) {
val newList = load().filter { basicAuth -> basicAuth.host != basicAuth.host } val newList = load().filter { auth -> auth.host != auth.host }.toMutableList()
.toMutableList()
newList.add(0, basicAuth) newList.add(0, basicAuth)
save(newList) save(newList)
} }
...@@ -26,7 +25,7 @@ class SharedPrefsBasicAuthRepository( ...@@ -26,7 +25,7 @@ class SharedPrefsBasicAuthRepository(
val type = Types.newParameterizedType(List::class.java, BasicAuth::class.java) val type = Types.newParameterizedType(List::class.java, BasicAuth::class.java)
val adapter = moshi.adapter<List<BasicAuth>>(type) val adapter = moshi.adapter<List<BasicAuth>>(type)
return adapter.fromJson(json) ?: emptyList() return json?.let { adapter.fromJson(it) ?: emptyList() } ?: emptyList()
} }
private fun save(basicAuths: List<BasicAuth>) { private fun save(basicAuths: List<BasicAuth>) {
......
...@@ -106,8 +106,7 @@ class PasswordFragment : Fragment(), PasswordView, ActionMode.Callback { ...@@ -106,8 +106,7 @@ class PasswordFragment : Fragment(), PasswordView, ActionMode.Callback {
private fun finishActionMode() = actionMode?.finish() private fun finishActionMode() = actionMode?.finish()
private fun listenToChanges(): Disposable { private fun listenToChanges(): Disposable = Observables.combineLatest(
return Observables.combineLatest(
text_new_password.asObservable(), text_new_password.asObservable(),
text_confirm_password.asObservable() text_confirm_password.asObservable()
).subscribe { ).subscribe {
...@@ -119,7 +118,6 @@ class PasswordFragment : Fragment(), PasswordView, ActionMode.Callback { ...@@ -119,7 +118,6 @@ class PasswordFragment : Fragment(), PasswordView, ActionMode.Callback {
finishActionMode() finishActionMode()
} }
} }
}
private fun startActionMode() { private fun startActionMode() {
if (actionMode == null) { if (actionMode == null) {
......
...@@ -2,6 +2,7 @@ package chat.rocket.android.settings.ui ...@@ -2,6 +2,7 @@ package chat.rocket.android.settings.ui
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
...@@ -114,8 +115,7 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen ...@@ -114,8 +115,7 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen
} }
private fun setupToolbar() { private fun setupToolbar() {
(activity as AppCompatActivity?)?.supportActionBar?.title = (activity as AppCompatActivity?)?.supportActionBar?.title = getString(R.string.title_settings)
getString(R.string.title_settings)
} }
private fun shareApp() { private fun shareApp() {
...@@ -128,11 +128,12 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen ...@@ -128,11 +128,12 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen
} }
private fun contactSupport() { private fun contactSupport() {
with(Intent(Intent.ACTION_SEND)) { val uriText = "mailto:${"support@rocket.chat"}" +
type = "message/rfc822" "?subject=" + Uri.encode(getString(R.string.msg_android_app_support)) +
putExtra(Intent.EXTRA_EMAIL, arrayOf("support@rocket.chat")) "&body=" + Uri.encode(getDeviceAndAppInformation())
putExtra(Intent.EXTRA_SUBJECT, getString(R.string.msg_android_app_support))
putExtra(Intent.EXTRA_TEXT, getDeviceAndAppInformation()) with(Intent(Intent.ACTION_SENDTO)) {
data = uriText.toUri()
try { try {
startActivity(Intent.createChooser(this, getString(R.string.msg_send_email))) startActivity(Intent.createChooser(this, getString(R.string.msg_send_email)))
} catch (ex: ActivityNotFoundException) { } catch (ex: ActivityNotFoundException) {
......
...@@ -44,7 +44,7 @@ class UserDetailsPresenter @Inject constructor( ...@@ -44,7 +44,7 @@ class UserDetailsPresenter @Inject constructor(
dbManager.getUser(userId)?.let { dbManager.getUser(userId)?.let {
userEntity = it userEntity = it
val avatarUrl = val avatarUrl =
userEntity.username?.let { currentServer.avatarUrl(avatar = it) } userEntity.username?.let { username -> currentServer.avatarUrl(avatar = username) }
val username = userEntity.username val username = userEntity.username
val name = userEntity.name val name = userEntity.name
val utcOffset = val utcOffset =
...@@ -124,6 +124,24 @@ class UserDetailsPresenter @Inject constructor( ...@@ -124,6 +124,24 @@ class UserDetailsPresenter @Inject constructor(
} }
} }
// TODO fun toVideoConferencing(username: String) {
fun startVideoCall() {} launchUI(strategy) {
try {
withContext(Dispatchers.Default) {
val directMessage = retryIO("createDirectMessage($username") {
client.createDirectMessage(username)
}
navigator.toVideoConferencing(directMessage.id)
}
} catch (ex: Exception) {
Timber.e(ex)
ex.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
}
}
}
} }
...@@ -29,12 +29,10 @@ import kotlinx.android.synthetic.main.app_bar_chat_room.* ...@@ -29,12 +29,10 @@ import kotlinx.android.synthetic.main.app_bar_chat_room.*
import kotlinx.android.synthetic.main.fragment_user_details.* import kotlinx.android.synthetic.main.fragment_user_details.*
import javax.inject.Inject import javax.inject.Inject
fun newInstance(userId: String): Fragment { fun newInstance(userId: String): Fragment = UserDetailsFragment().apply {
return UserDetailsFragment().apply {
arguments = Bundle(1).apply { arguments = Bundle(1).apply {
putString(BUNDLE_USER_ID, userId) putString(BUNDLE_USER_ID, userId)
} }
}
} }
internal const val TAG_USER_DETAILS_FRAGMENT = "UserDetailsFragment" internal const val TAG_USER_DETAILS_FRAGMENT = "UserDetailsFragment"
...@@ -52,12 +50,10 @@ class UserDetailsFragment : Fragment(), UserDetailsView { ...@@ -52,12 +50,10 @@ class UserDetailsFragment : Fragment(), UserDetailsView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { userId = getString(BUNDLE_USER_ID, "")
userId = bundle.getString(BUNDLE_USER_ID)
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
} }
?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} }
override fun onCreateView( override fun onCreateView(
...@@ -108,7 +104,7 @@ class UserDetailsFragment : Fragment(), UserDetailsView { ...@@ -108,7 +104,7 @@ class UserDetailsFragment : Fragment(), UserDetailsView {
if (isVideoCallAllowed) { if (isVideoCallAllowed) {
text_video_call.isVisible = true text_video_call.isVisible = true
text_video_call.setOnClickListener { presenter.startVideoCall() } text_video_call.setOnClickListener { presenter.toVideoConferencing(username) }
} else { } else {
text_video_call.isVisible = false text_video_call.isVisible = false
} }
......
...@@ -191,7 +191,7 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept ...@@ -191,7 +191,7 @@ class HttpLoggingInterceptor constructor(private val logger: Logger) : Intercept
val responseBody = response.body() val responseBody = response.body()
val contentLength = responseBody!!.contentLength() val contentLength = responseBody!!.contentLength()
val bodySize = if (contentLength != -1L) contentLength.toString() + "-byte" else "unknown-length" val bodySize = if (contentLength != -1L) "$contentLength-byte" else "unknown-length"
val responseStr = if (response.message().isEmpty()) "" else " ${response.message()}" val responseStr = if (response.message().isEmpty()) "" else " ${response.message()}"
logger.log("<-- ${response.code()}$responseStr ${response.request().url()}" logger.log("<-- ${response.code()}$responseStr ${response.request().url()}"
+ " (" + tookMs + "ms" + (if (!logHeaders) ", $bodySize body" else "") + ')'.toString()) + " (" + tookMs + "ms" + (if (!logHeaders) ", $bodySize body" else "") + ')'.toString())
......
...@@ -69,11 +69,8 @@ fun String.userId(userId: String?): String? { ...@@ -69,11 +69,8 @@ fun String.userId(userId: String?): String? {
return userId?.let { this.replace(it, "") } return userId?.let { this.replace(it, "") }
} }
fun String.lowercaseUrl(): String? { fun String.lowercaseUrl(): String? = HttpUrl.parse(this)?.run {
val httpUrl = HttpUrl.parse(this) newBuilder().scheme(scheme().toLowerCase()).build().toString()
val newScheme = httpUrl?.scheme()?.toLowerCase()
return httpUrl?.newBuilder()?.scheme(newScheme)?.build()?.toString()
} }
fun String?.isNotNullNorEmpty(): Boolean = this != null && this.isNotEmpty() fun String?.isNotNullNorEmpty(): Boolean = this != null && this.isNotEmpty()
......
...@@ -80,12 +80,10 @@ fun AppCompatActivity.toPreviousView() { ...@@ -80,12 +80,10 @@ fun AppCompatActivity.toPreviousView() {
} }
fun Activity.hideKeyboard() { fun Activity.hideKeyboard() {
if (currentFocus != null) { currentFocus?.run {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager (getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).also {
imm.hideSoftInputFromWindow( it.hideSoftInputFromWindow(windowToken, InputMethodManager.RESULT_UNCHANGED_SHOWN)
currentFocus.windowToken, }
InputMethodManager.RESULT_UNCHANGED_SHOWN
)
} }
} }
......
...@@ -51,7 +51,7 @@ fun Uri.getFileSize(context: Context): Int { ...@@ -51,7 +51,7 @@ fun Uri.getFileSize(context: Context): Int {
fun Uri.getMimeType(context: Context): String { fun Uri.getMimeType(context: Context): String {
return if (scheme == ContentResolver.SCHEME_CONTENT) { return if (scheme == ContentResolver.SCHEME_CONTENT) {
context.contentResolver.getType(this) context.contentResolver?.getType(this) ?: ""
} else { } else {
val fileExtension = MimeTypeMap.getFileExtensionFromUrl(toString()) val fileExtension = MimeTypeMap.getFileExtensionFromUrl(toString())
if (fileExtension != null) { if (fileExtension != null) {
......
...@@ -3,7 +3,6 @@ package chat.rocket.android.videoconferencing.presenter ...@@ -3,7 +3,6 @@ package chat.rocket.android.videoconferencing.presenter
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.JitsiHelper import chat.rocket.android.helper.JitsiHelper
import chat.rocket.android.server.domain.* import chat.rocket.android.server.domain.*
import chat.rocket.android.server.infraestructure.ConnectionManager
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.core.RocketChatClient import chat.rocket.core.RocketChatClient
...@@ -22,8 +21,6 @@ class VideoConferencingPresenter @Inject constructor( ...@@ -22,8 +21,6 @@ class VideoConferencingPresenter @Inject constructor(
private val connectionManagerFactory: ConnectionManagerFactory, private val connectionManagerFactory: ConnectionManagerFactory,
private val settings: GetSettingsInteractor private val settings: GetSettingsInteractor
) { ) {
private lateinit var currentServerUrl: String
private lateinit var connectionManager: ConnectionManager
private lateinit var client: RocketChatClient private lateinit var client: RocketChatClient
private lateinit var publicSettings: PublicSettings private lateinit var publicSettings: PublicSettings
private lateinit var chatRoomId: String private lateinit var chatRoomId: String
...@@ -31,9 +28,7 @@ class VideoConferencingPresenter @Inject constructor( ...@@ -31,9 +28,7 @@ class VideoConferencingPresenter @Inject constructor(
fun setup(chatRoomId: String) { fun setup(chatRoomId: String) {
currentServerRepository.get()?.let { currentServerRepository.get()?.let {
currentServerUrl = it client = connectionManagerFactory.create(it).client
connectionManager = connectionManagerFactory.create(it)
client = connectionManager.client
publicSettings = settings.get(it) publicSettings = settings.get(it)
} }
this.chatRoomId = chatRoomId this.chatRoomId = chatRoomId
......
...@@ -27,13 +27,10 @@ class AdminPanelWebViewFragment : DaggerFragment() { ...@@ -27,13 +27,10 @@ class AdminPanelWebViewFragment : DaggerFragment() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val bundle = arguments arguments?.run {
if (bundle != null) { webPageUrl = getString(BUNDLE_WEB_PAGE_URL, "")
webPageUrl = bundle.getString(BUNDLE_WEB_PAGE_URL) userToken = getString(BUNDLE_USER_TOKEN, "")
userToken = bundle.getString(BUNDLE_USER_TOKEN) } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
} }
override fun onCreateView( override fun onCreateView(
...@@ -65,7 +62,7 @@ class AdminPanelWebViewFragment : DaggerFragment() { ...@@ -65,7 +62,7 @@ class AdminPanelWebViewFragment : DaggerFragment() {
web_view.webViewClient = object : WebViewClient() { web_view.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) { override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url) super.onPageFinished(view, url)
ui { _ -> ui {
view_loading.hide() view_loading.hide()
web_view.evaluateJavascript("Meteor.loginWithToken('$userToken', function() { })") {} web_view.evaluateJavascript("Meteor.loginWithToken('$userToken', function() { })") {}
} }
......
...@@ -8,13 +8,14 @@ import android.view.View ...@@ -8,13 +8,14 @@ import android.view.View
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.chatrooms.adapter.RoomsAdapter
/** /**
* Adds a default or custom divider to specific item views from the adapter's data set. * Adds a default or custom divider to specific item views from the adapter's data set.
* @see RecyclerView.ItemDecoration * @see RecyclerView.ItemDecoration
*/ */
class DividerItemDecoration() : RecyclerView.ItemDecoration() { class DividerItemDecoration() : RecyclerView.ItemDecoration() {
private lateinit var divider: Drawable private var divider: Drawable? = null
private var boundStart = 0 private var boundStart = 0
private var boundEnd = 0 private var boundEnd = 0
...@@ -39,10 +40,7 @@ class DividerItemDecoration() : RecyclerView.ItemDecoration() { ...@@ -39,10 +40,7 @@ class DividerItemDecoration() : RecyclerView.ItemDecoration() {
// Custom divider will be used. // Custom divider will be used.
constructor(context: Context, @DrawableRes drawableResId: Int) : this() { constructor(context: Context, @DrawableRes drawableResId: Int) : this() {
val customDrawable = ContextCompat.getDrawable(context, drawableResId) divider = ContextCompat.getDrawable(context, drawableResId)
if (customDrawable != null) {
divider = customDrawable
}
} }
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
...@@ -53,16 +51,16 @@ class DividerItemDecoration() : RecyclerView.ItemDecoration() { ...@@ -53,16 +51,16 @@ class DividerItemDecoration() : RecyclerView.ItemDecoration() {
for (i in 0 until childCount) { for (i in 0 until childCount) {
val child = parent.getChildAt(i) val child = parent.getChildAt(i)
if (isLastView(child, parent)) if (isLastView(child, parent) || isViewTypeHeader(child, parent))
continue continue
val params = child.layoutParams as RecyclerView.LayoutParams val params = child.layoutParams as RecyclerView.LayoutParams
val top = child.bottom + params.bottomMargin val bottom = child.bottom + params.bottomMargin
val bottom = top + divider.intrinsicHeight val top = bottom - (divider?.intrinsicHeight ?: 0)
divider.setBounds(left, top, right, bottom) divider?.setBounds(left, top, right, bottom)
divider.draw(c) divider?.draw(c)
} }
} }
...@@ -70,4 +68,9 @@ class DividerItemDecoration() : RecyclerView.ItemDecoration() { ...@@ -70,4 +68,9 @@ class DividerItemDecoration() : RecyclerView.ItemDecoration() {
val position = parent.getChildAdapterPosition(view) val position = parent.getChildAdapterPosition(view)
return position == parent.adapter?.itemCount?.minus(1) ?: false return position == parent.adapter?.itemCount?.minus(1) ?: false
} }
private fun isViewTypeHeader(view: View, parent: RecyclerView): Boolean {
val position = parent.getChildViewHolder(view).itemViewType
return position == RoomsAdapter.VIEW_TYPE_HEADER
}
} }
<vector android:height="24dp" android:viewportHeight="100"
android:viewportWidth="100" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ededed" android:pathData="M50,100q-24.66,0 -49.32,0c-0.57,0 -0.68,-0.11 -0.68,-0.68Q0,50 0,0.68C0,0.11 0.11,0 0.68,0Q50,0 99.32,0c0.57,0 0.68,0.11 0.68,0.68q0,49.32 0,98.64c0,0.57 -0.11,0.68 -0.68,0.68Q74.66,100 50,100Z"/>
<path android:fillColor="#afafae" android:pathData="M49.42,90C41.72,90 34,90 26.34,90a13.82,13.82 0,0 1,-8.55 -2.75A11.18,11.18 0,0 1,13.22 79a46.76,46.76 0,0 1,3 -21.44,17.06 17.06,0 0,1 6.56,-8.48 15.67,15.67 0,0 1,7.3 -2.28,4.52 4.52,0 0,1 2.84,1c1.62,1 3.18,2.14 4.86,3.05a23.24,23.24 0,0 0,20.34 1.5A25.39,25.39 0,0 0,65 48.51c2.81,-2.26 5.65,-1.76 8.61,-0.71 3.73,1.32 6.24,4 8.11,7.39A35.18,35.18 0,0 1,85.31 67,54.2 54.2,0 0,1 86,77.31a12.47,12.47 0,0 1,-4 9.28,12.65 12.65,0 0,1 -7.33,3.22c-3.9,0.4 -7.82,0.13 -11.73,0.17C58.41,90 53.92,90 49.42,90Z"/>
<path android:fillColor="#afafae" android:pathData="M69.35,30.28c0.4,10.36 -8.74,20 -19.89,19.93s-19.92,-9.58 -19.89,-20 8.81,-19.93 20,-19.88C60.64,10.35 69.77,19.87 69.35,30.28Z"/>
</vector>
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
android:layout_width="120dp" android:layout_width="120dp"
android:layout_height="120dp" android:layout_height="120dp"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:background="@drawable/bg_empty_user_avatar"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
......
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="chat.rocket.android.about.ui.AboutFragment"> tools:context="chat.rocket.android.about.ui.AboutFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="50dp"
android:layout_gravity="center">
<ImageView <ImageView
android:id="@+id/image_app_name" android:id="@+id/image_app_name"
android:layout_width="wrap_content" android:layout_width="wrap_content"
...@@ -18,13 +25,14 @@ ...@@ -18,13 +25,14 @@
<ImageView <ImageView
android:layout_width="160dp" android:layout_width="160dp"
android:layout_height="160dp" android:layout_height="160dp"
android:src="@drawable/ic_launcher_foreground"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/image_app_name"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:scaleX="1.5" android:scaleX="1.5"
android:scaleY="1.5" /> android:scaleY="1.5"
android:src="@drawable/ic_launcher_foreground"
app:layout_constraintBottom_toTopOf="@id/image_app_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView <TextView
android:id="@+id/text_version_name" android:id="@+id/text_version_name"
...@@ -49,4 +57,6 @@ ...@@ -49,4 +57,6 @@
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:textColor="@color/colorSecondaryText" /> android:textColor="@color/colorSecondaryText" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
\ No newline at end of file
<?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:padding="@dimen/screen_edge_left_and_right_margins">
<TextView
android:id="@+id/text_reset_password"
style="@style/Authentication.TextView.Headline"
android:text="@string/title_are_you_sure"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/text_delete_account_password"
style="@style/Authentication.EditText.Border"
android:layout_marginTop="16dp"
android:drawableStart="@drawable/ic_key_black_20dp"
android:hint="@string/msg_password"
android:imeOptions="actionDone"
android:inputType="textPassword"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_reset_password" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -4,24 +4,14 @@ ...@@ -4,24 +4,14 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<!--<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/darkGray" />-->
<TextView <TextView
android:id="@+id/text_chatroom_header" android:id="@+id/text_chatroom_header"
style="@style/ChatRooms.Header" style="@style/ChatRooms.Header"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="8dp" android:padding="16dp"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding" android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingStart="@dimen/screen_edge_left_and_right_padding" android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:text="@string/chatroom_header" /> android:text="@string/chatroom_header" />
<View </LinearLayout>
android:layout_width="match_parent" \ No newline at end of file
android:layout_height="1dp"
android:background="@color/quoteBar" />
</LinearLayout>
\ No newline at end of file
...@@ -34,8 +34,8 @@ ...@@ -34,8 +34,8 @@
android:id="@+id/day" android:id="@+id/day"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="16dp" android:layout_marginStart="16dp"
android:layout_marginRight="16dp" android:layout_marginEnd="16dp"
android:textAppearance="@style/Message.DayMarker" android:textAppearance="@style/Message.DayMarker"
tools:text="Wednesday" /> tools:text="Wednesday" />
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
layout="@layout/avatar" layout="@layout/avatar"
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="40dp" android:layout_height="40dp"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/message_header" /> app:layout_constraintTop_toTopOf="@+id/message_header" />
<LinearLayout <LinearLayout
...@@ -95,17 +95,16 @@ ...@@ -95,17 +95,16 @@
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toRightOf="@+id/layout_avatar"
app:layout_constraintStart_toEndOf="@+id/layout_avatar" app:layout_constraintStart_toEndOf="@+id/layout_avatar"
app:layout_constraintTop_toBottomOf="@+id/day_marker_layout"> app:layout_constraintTop_toBottomOf="@+id/day_marker_layout">
<TextView <TextView
android:id="@+id/text_sender" android:id="@+id/text_sender"
style="@style/Sender.Name.TextView" style="@style/Sender.Name.TextView"
android:layout_width="0dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_weight="1" android:maxLength="22"
tools:text="User Name with long name" /> tools:text="User Name with long name" />
<TextView <TextView
...@@ -123,7 +122,7 @@ ...@@ -123,7 +122,7 @@
android:layout_marginStart="4dp" android:layout_marginStart="4dp"
android:text="@string/msg_edited" android:text="@string/msg_edited"
android:textStyle="italic" android:textStyle="italic"
android:visibility="gone" android:visibility="invisible"
tools:visibility="visible" /> tools:visibility="visible" />
<ImageView <ImageView
...@@ -133,7 +132,7 @@ ...@@ -133,7 +132,7 @@
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_marginStart="4dp" android:layout_marginStart="4dp"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:visibility="gone" android:visibility="invisible"
app:srcCompat="@drawable/ic_action_message_star_24dp" app:srcCompat="@drawable/ic_action_message_star_24dp"
tools:visibility="visible" /> tools:visibility="visible" />
...@@ -141,7 +140,7 @@ ...@@ -141,7 +140,7 @@
android:id="@+id/read_receipt_view" android:id="@+id/read_receipt_view"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:visibility="gone" android:visibility="invisible"
app:srcCompat="@drawable/ic_check_unread_24dp" app:srcCompat="@drawable/ic_check_unread_24dp"
tools:visibility="visible" /> tools:visibility="visible" />
</LinearLayout> </LinearLayout>
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
android:id="@+id/image_avatar" android:id="@+id/image_avatar"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="60dp" android:layout_height="60dp"
android:background="@drawable/bg_empty_user_avatar"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
......
...@@ -325,6 +325,7 @@ ...@@ -325,6 +325,7 @@
<string name="chatroom_header">Kopf</string> <string name="chatroom_header">Kopf</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favorites</string><!-- TODO - Add proper translation -->
<string name="header_channel">Räume</string> <string name="header_channel">Räume</string>
<string name="header_private_groups">Private Räume</string> <string name="header_private_groups">Private Räume</string>
<string name="header_direct_messages">Direkt Nachrichten</string> <string name="header_direct_messages">Direkt Nachrichten</string>
......
...@@ -316,6 +316,7 @@ ...@@ -316,6 +316,7 @@
<string name="chatroom_header">Cabezazo</string> <string name="chatroom_header">Cabezazo</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favorites</string><!-- TODO - Add proper translation -->
<string name="header_channel">Canales</string> <string name="header_channel">Canales</string>
<string name="header_private_groups">Grupos privados</string> <string name="header_private_groups">Grupos privados</string>
<string name="header_direct_messages">Mensajes directos</string> <string name="header_direct_messages">Mensajes directos</string>
......
...@@ -319,6 +319,7 @@ ...@@ -319,6 +319,7 @@
<string name="chatroom_header">سرپیام</string> <string name="chatroom_header">سرپیام</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favorites</string><!-- TODO - Add proper translation -->
<string name="header_channel">کانال‌ها</string> <string name="header_channel">کانال‌ها</string>
<string name="header_private_groups">گروه‌های خصوصی</string> <string name="header_private_groups">گروه‌های خصوصی</string>
<string name="header_direct_messages">پیام‌های خصوصی</string> <string name="header_direct_messages">پیام‌های خصوصی</string>
......
This diff is collapsed.
...@@ -125,7 +125,7 @@ ...@@ -125,7 +125,7 @@
<string name="msg_preview_file">फ़ाइल</string> <string name="msg_preview_file">फ़ाइल</string>
<string name="msg_unread_messages">अपठित संदेश</string> <string name="msg_unread_messages">अपठित संदेश</string>
<string name="msg_no_messages_yet">अभी तक कोई पोस्ट नहीं</string> <string name="msg_no_messages_yet">अभी तक कोई पोस्ट नहीं</string>
<string name="msg_build">Build %1$d - %2$s - %3$s</string> <!-- TODO Add translation --> <string name="msg_build">निर्माण %1$d - %2$s - %3$s</string>
<string name="msg_update_app_version_in_order_to_continue">पुराना सर्वर वर्शन। जारी रखने के लिए सर्वर वर्शन को अद्यतन करने के लिए कृपया सर्वर व्यवस्थापक से संपर्क करें।</string> <string name="msg_update_app_version_in_order_to_continue">पुराना सर्वर वर्शन। जारी रखने के लिए सर्वर वर्शन को अद्यतन करने के लिए कृपया सर्वर व्यवस्थापक से संपर्क करें।</string>
<string name="msg_ver_not_recommended"> <string name="msg_ver_not_recommended">
ऐसा लगता है कि आपका सर्वर संस्करण अनुशंसित संस्करण %1$s के नीचे है।\nआप अभी भी लॉगिन कर सकते हैं लेकिन आप अप्रत्याशित व्यवहार का अनुभव कर सकते हैं ऐसा लगता है कि आपका सर्वर संस्करण अनुशंसित संस्करण %1$s के नीचे है।\nआप अभी भी लॉगिन कर सकते हैं लेकिन आप अप्रत्याशित व्यवहार का अनुभव कर सकते हैं
...@@ -320,6 +320,7 @@ ...@@ -320,6 +320,7 @@
<string name="chatroom_header">हैडर</string> <string name="chatroom_header">हैडर</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">पसंदीदा</string>
<string name="header_channel">चैनलों</string> <string name="header_channel">चैनलों</string>
<string name="header_private_groups">निजी समूहों</string> <string name="header_private_groups">निजी समूहों</string>
<string name="header_direct_messages">प्रत्यक्ष संदेश</string> <string name="header_direct_messages">प्रत्यक्ष संदेश</string>
......
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
<string-array name="settings_actions"> <string-array name="settings_actions">
<item name="item_preferences">Preferenze</item> <item name="item_preferences">Preferenze</item>
<item name="item_password">Cambia password</item> <item name="item_password">Cambia password</item>
<item name="change_language">Change language</item><!-- TODO Add translation --> <item name="change_language">Cambia lingua</item>
<item name="item_share_app">Condividi app</item> <item name="item_share_app">Condividi app</item>
<item name="item_rate_us">Votaci</item> <item name="item_rate_us">Votaci</item>
<item name="item_contact_us">Contattaci</item> <item name="item_contact_us">Contattaci</item>
...@@ -127,7 +127,7 @@ ...@@ -127,7 +127,7 @@
<string name="msg_preview_photo">Foto</string> <string name="msg_preview_photo">Foto</string>
<string name="msg_preview_file">Documento</string> <string name="msg_preview_file">Documento</string>
<string name="msg_no_messages_yet">Nessun nuovo messaggio</string> <string name="msg_no_messages_yet">Nessun nuovo messaggio</string>
<string name="msg_build">Build %1$d - %2$s - %3$s</string> <!-- TODO Add translation --> <string name="msg_build">Versione %1$d - %2$s - %3$s</string>
<string name="msg_update_app_version_in_order_to_continue">Versione server non aggiornata. Si prega di contattare l\'amministratore del server per aggiornare la versione del server per continuare.</string> <string name="msg_update_app_version_in_order_to_continue">Versione server non aggiornata. Si prega di contattare l\'amministratore del server per aggiornare la versione del server per continuare.</string>
<string name="msg_ver_not_recommended">Sembra che la versione del tuo server sia inferiore alla versione consigliata %1$s.\nÈ ancora possibile accedere ma è possibile che si verifichino comportamenti imprevisti.</string> <string name="msg_ver_not_recommended">Sembra che la versione del tuo server sia inferiore alla versione consigliata %1$s.\nÈ ancora possibile accedere ma è possibile che si verifichino comportamenti imprevisti.</string>
<string name="msg_ver_not_minimum">Sembra che la versione del tuo server sia inferiore alla versione minima richiesta %1$s.\nSi prega di aggiornare il server per accedere!</string> <string name="msg_ver_not_minimum">Sembra che la versione del tuo server sia inferiore alla versione minima richiesta %1$s.\nSi prega di aggiornare il server per accedere!</string>
...@@ -316,6 +316,7 @@ ...@@ -316,6 +316,7 @@
<string name="chatroom_header">Intestazione</string> <string name="chatroom_header">Intestazione</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favorites</string><!-- TODO - Add proper translation -->
<string name="header_channel">Canali</string> <string name="header_channel">Canali</string>
<string name="header_private_groups">Gruppi Privati</string> <string name="header_private_groups">Gruppi Privati</string>
<string name="header_direct_messages">Messaggi Diretti</string> <string name="header_direct_messages">Messaggi Diretti</string>
......
...@@ -320,6 +320,7 @@ ...@@ -320,6 +320,7 @@
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favorites</string><!-- TODO - Add proper translation -->
<string name="header_channel">チャンネル</string> <string name="header_channel">チャンネル</string>
<string name="header_private_groups">プライベートグループ</string> <string name="header_private_groups">プライベートグループ</string>
<string name="header_direct_messages">ダイレクトメッセージ</string> <string name="header_direct_messages">ダイレクトメッセージ</string>
......
...@@ -318,6 +318,7 @@ ...@@ -318,6 +318,7 @@
<string name="chatroom_header">Cabeçalho</string> <string name="chatroom_header">Cabeçalho</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favoritos</string>
<string name="header_channel">Canais</string> <string name="header_channel">Canais</string>
<string name="header_private_groups">Grupos Privados</string> <string name="header_private_groups">Grupos Privados</string>
<string name="header_direct_messages">Mensagens diretas</string> <string name="header_direct_messages">Mensagens diretas</string>
......
This diff is collapsed.
...@@ -316,6 +316,7 @@ ...@@ -316,6 +316,7 @@
<string name="chatroom_header">Заголовок</string> <string name="chatroom_header">Заголовок</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favorites</string><!-- TODO - Add proper translation -->
<string name="header_channel">Каналы</string> <string name="header_channel">Каналы</string>
<string name="header_private_groups">Приватные каналы</string> <string name="header_private_groups">Приватные каналы</string>
<string name="header_direct_messages">Личная переписка</string> <string name="header_direct_messages">Личная переписка</string>
...@@ -333,7 +334,7 @@ ...@@ -333,7 +334,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="timezone">Часовой поясe</string> <string name="timezone">Часовой пояс</string>
<!-- Report --> <!-- Report -->
<string name="submit">Отправить</string> <string name="submit">Отправить</string>
......
...@@ -321,6 +321,7 @@ ...@@ -321,6 +321,7 @@
<string name="chatroom_header">Başlık</string> <string name="chatroom_header">Başlık</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favorites</string><!-- TODO - Add proper translation -->
<string name="header_channel">Kanallar</string> <string name="header_channel">Kanallar</string>
<string name="header_private_groups">Gizli Gruplar</string> <string name="header_private_groups">Gizli Gruplar</string>
<string name="header_direct_messages">Direkt Mesajlar</string> <string name="header_direct_messages">Direkt Mesajlar</string>
......
...@@ -317,6 +317,7 @@ ...@@ -317,6 +317,7 @@
<string name="chatroom_header">Заголовок</string> <string name="chatroom_header">Заголовок</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favorites</string><!-- TODO - Add proper translation -->
<string name="header_channel">Канали</string> <string name="header_channel">Канали</string>
<string name="header_private_groups">Приватні канали</string> <string name="header_private_groups">Приватні канали</string>
<string name="header_direct_messages">Особисті повідомлення</string> <string name="header_direct_messages">Особисті повідомлення</string>
......
...@@ -316,6 +316,7 @@ ...@@ -316,6 +316,7 @@
<string name="chatroom_header">头部</string> <string name="chatroom_header">头部</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favorites</string><!-- TODO - Add proper translation -->
<string name="header_channel">频道</string> <string name="header_channel">频道</string>
<string name="header_private_groups">私人组</string> <string name="header_private_groups">私人组</string>
<string name="header_direct_messages">直接对话</string> <string name="header_direct_messages">直接对话</string>
......
...@@ -332,6 +332,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin ...@@ -332,6 +332,7 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="chatroom_header">Header</string> <string name="chatroom_header">Header</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favorites</string>
<string name="header_channel">Channels</string> <string name="header_channel">Channels</string>
<string name="header_private_groups">Private Groups</string> <string name="header_private_groups">Private Groups</string>
<string name="header_direct_messages">Direct Messages</string> <string name="header_direct_messages">Direct Messages</string>
......
...@@ -53,8 +53,15 @@ class DrawingActivity : DaggerAppCompatActivity(), DrawView { ...@@ -53,8 +53,15 @@ class DrawingActivity : DaggerAppCompatActivity(), DrawView {
} }
private fun setupDrawTools() { private fun setupDrawTools() {
image_draw_eraser.setOnClickListener { image_draw_eraser.setOnLongClickListener{
custom_draw_view.clearCanvas() custom_draw_view.clearCanvas()
return@setOnLongClickListener true
}
image_draw_eraser.setOnClickListener {
custom_draw_view.setColor(
ResourcesCompat.getColor(resources, R.color.color_white, null)
)
toggleDrawTools(draw_tools, false) toggleDrawTools(draw_tools, false)
} }
...@@ -111,6 +118,13 @@ class DrawingActivity : DaggerAppCompatActivity(), DrawView { ...@@ -111,6 +118,13 @@ class DrawingActivity : DaggerAppCompatActivity(), DrawView {
} }
private fun colorSelector() { private fun colorSelector() {
image_color_black.setOnClickListener {
custom_draw_view.setColor(
ResourcesCompat.getColor(resources, R.color.color_black, null)
)
scaleColorView(image_color_black)
}
image_color_red.setOnClickListener { image_color_red.setOnClickListener {
custom_draw_view.setColor( custom_draw_view.setColor(
ResourcesCompat.getColor(resources, R.color.color_red, null) ResourcesCompat.getColor(resources, R.color.color_red, null)
......
...@@ -42,7 +42,6 @@ class CustomDrawView(context: Context, attrs: AttributeSet) : View(context, attr ...@@ -42,7 +42,6 @@ class CustomDrawView(context: Context, attrs: AttributeSet) : View(context, attr
fun undo() { fun undo() {
if (mPaths.isEmpty() && mLastPaths.isNotEmpty()) { if (mPaths.isEmpty() && mLastPaths.isNotEmpty()) {
mPaths = mLastPaths.clone() as LinkedHashMap<MyPath, PaintOptions> mPaths = mLastPaths.clone() as LinkedHashMap<MyPath, PaintOptions>
mLastPaths.clear()
invalidate() invalidate()
return return
} }
......
package chat.rocket.android.util.extension package chat.rocket.android.util.extension
import android.content.Context
import android.os.Build
import android.widget.TextView
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
fun SearchView.onQueryTextListener(queryListener: (String) -> Unit) { fun SearchView.onQueryTextListener(queryListener: (String) -> Unit) {
...@@ -15,3 +18,11 @@ fun SearchView.onQueryTextListener(queryListener: (String) -> Unit) { ...@@ -15,3 +18,11 @@ fun SearchView.onQueryTextListener(queryListener: (String) -> Unit) {
} }
}) })
} }
fun TextView.setTextViewAppearance(context: Context, style: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setTextAppearance(style)
} else {
setTextAppearance(context, style)
}
}
\ No newline at end of file
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