Unverified Commit c09f75ff authored by Rafael Kellermann Streit's avatar Rafael Kellermann Streit Committed by GitHub

Merge branch 'develop-2.x' into empty-pin-msg

parents e9c2fc4a 29dcfdae
...@@ -19,18 +19,12 @@ Since both the versions use `kotlin` for some or all of their classes, following ...@@ -19,18 +19,12 @@ Since both the versions use `kotlin` for some or all of their classes, following
- After checking out to `develop` branch as mentioned above, simply import the project in Android Studio. - After checking out to `develop` branch as mentioned above, simply import the project in Android Studio.
#### v2+ #### v2+
- This version requires the [Kotlin SDK](https://github.com/RocketChat/Rocket.Chat.Kotlin.SDK) for Rocket.Chat. Clone the Kotlin SDK in the **same directory** as the android repository by running `git clone https://github.com/RocketChat/Rocket.Chat.Kotlin.SDK.git`. Make sure that the android repository and the kotlin sdk have the same immediate parent directory. - This version requires the [Kotlin SDK](https://github.com/RocketChat/Rocket.Chat.Kotlin.SDK) for Rocket.Chat. Clone the Kotlin SDK in by running `git clone https://github.com/RocketChat/Rocket.Chat.Kotlin.SDK.git`.
- First, a build is required for the SDK. Change your directory to the SDK directory by running `cd Rocket.Chat.Kotlin.SDK/` in your terminal. Any of the following approaches can be followed to successfully build the SDK. - First, a build is required for the SDK, so that required jar files are generated. Make sure that the android repository and the kotlin sdk have the same immediate parent directory. Change the current directory to `Rocket.Chat.Android/app` and run the `build-sdk.sh` which will result in creating of the required jar file `core*.jar` and `common*.jar` in `Rocket.Chat.Android/app/libs`,by the following steps in your terminal window:
- **Command Line** - (Within the kotlin SDK directory) Run `./gradlew clean && ./gradlew assemble` to successfully build the project.
- **Android Studio** - Import the project in Android Studio. Go to `Build > Make Project` to build the SDK successfully.
After following the above methods, follow the following steps in your terminal window:
``` ```
cd .. cd Rocket.Chat.Android/app
cd Rocket.Chat.Android/app/libs ./build-sdk.sh
ls
``` ```
Two `jar` files will be found in this directory (the `common` and `core` jar files), this indicates that the SDK was built correctly.
- After the SDK has been built successfully, import the project in Android Studio and build it by following `Build > Make Project`.
## How to run ## How to run
### Command Line ### Command Line
......
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:networkSecurityConfig="@xml/network_security_config">
android:supportsRtl="true"> android:supportsRtl="true">
<activity <activity
android:name=".authentication.ui.AuthenticationActivity" android:name=".authentication.ui.AuthenticationActivity"
android:configChanges="orientation" android:configChanges="orientation"
...@@ -109,4 +111,4 @@ ...@@ -109,4 +111,4 @@
android:theme="@style/AppTheme"/> android:theme="@style/AppTheme"/>
</application> </application>
</manifest> </manifest>
\ No newline at end of file
...@@ -86,31 +86,39 @@ class LoginFragment : Fragment(), LoginView { ...@@ -86,31 +86,39 @@ class LoginFragment : Fragment(), LoginView {
} }
private fun tintEditTextDrawableStart() { private fun tintEditTextDrawableStart() {
activity?.apply { ui {
val personDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_assignment_ind_black_24dp, this) val personDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_assignment_ind_black_24dp, it)
val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_lock_black_24dp, this) val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_lock_black_24dp, it)
val drawables = arrayOf(personDrawable, lockDrawable) val drawables = arrayOf(personDrawable, lockDrawable)
DrawableHelper.wrapDrawables(drawables) DrawableHelper.wrapDrawables(drawables)
DrawableHelper.tintDrawables(drawables, this, R.color.colorDrawableTintGrey) DrawableHelper.tintDrawables(drawables, it, R.color.colorDrawableTintGrey)
DrawableHelper.compoundDrawables(arrayOf(text_username_or_email, text_password), drawables) DrawableHelper.compoundDrawables(arrayOf(text_username_or_email, text_password), drawables)
} }
} }
override fun showLoading() { override fun showLoading() {
view_loading.setVisible(true) ui {
view_loading.setVisible(true)
}
} }
override fun hideLoading() { override fun hideLoading() {
view_loading.setVisible(false) ui {
view_loading.setVisible(false)
}
} }
override fun showMessage(resId: Int) { override fun showMessage(resId: Int) {
showToast(resId) ui {
showToast(resId)
}
} }
override fun showMessage(message: String) { override fun showMessage(message: String) {
showToast(message) ui {
showToast(message)
}
} }
override fun showGenericErrorMessage() { override fun showGenericErrorMessage() {
...@@ -118,152 +126,208 @@ class LoginFragment : Fragment(), LoginView { ...@@ -118,152 +126,208 @@ class LoginFragment : Fragment(), LoginView {
} }
override fun showFormView() { override fun showFormView() {
text_username_or_email.setVisible(true) ui {
text_password.setVisible(true) text_username_or_email.setVisible(true)
text_password.setVisible(true)
}
} }
override fun hideFormView() { override fun hideFormView() {
text_username_or_email.setVisible(false) ui {
text_password.setVisible(false) text_username_or_email.setVisible(false)
text_password.setVisible(false)
}
} }
override fun setupLoginButtonListener() { override fun setupLoginButtonListener() {
button_log_in.setOnClickListener { ui {
presenter.authenticateWithUserAndPassword(text_username_or_email.textContent, text_password.textContent) button_log_in.setOnClickListener {
presenter.authenticateWithUserAndPassword(text_username_or_email.textContent,
text_password.textContent)
}
} }
} }
override fun enableUserInput() { override fun enableUserInput() {
button_log_in.isEnabled = true ui {
text_username_or_email.isEnabled = true button_log_in.isEnabled = true
text_password.isEnabled = true text_username_or_email.isEnabled = true
text_password.isEnabled = true
}
} }
override fun disableUserInput() { override fun disableUserInput() {
button_log_in.isEnabled = false ui {
text_username_or_email.isEnabled = false button_log_in.isEnabled = false
text_password.isEnabled = false text_username_or_email.isEnabled = false
text_password.isEnabled = false
}
} }
override fun showCasButton() { override fun showCasButton() {
button_cas.setVisible(true) ui {
button_cas.setVisible(true)
}
} }
override fun hideCasButton() { override fun hideCasButton() {
button_cas.setVisible(false) ui {
button_cas.setVisible(false)
}
} }
override fun setupCasButtonListener(casUrl: String, casToken: String) { override fun setupCasButtonListener(casUrl: String, casToken: String) {
button_cas.setOnClickListener { ui { activity ->
startActivityForResult(context?.casWebViewIntent(casUrl, casToken), REQUEST_CODE_FOR_CAS) button_cas.setOnClickListener {
activity?.overridePendingTransition(R.anim.slide_up, R.anim.hold) startActivityForResult(activity.casWebViewIntent(casUrl, casToken),
REQUEST_CODE_FOR_CAS)
activity.overridePendingTransition(R.anim.slide_up, R.anim.hold)
}
} }
} }
override fun showSignUpView() { override fun showSignUpView() {
text_new_to_rocket_chat.setVisible(true) ui {
text_new_to_rocket_chat.setVisible(true)
}
} }
override fun setupSignUpView() { override fun setupSignUpView() {
val signUp = getString(R.string.title_sign_up) ui {
val newToRocketChat = String.format(getString(R.string.msg_new_user), signUp) val signUp = getString(R.string.title_sign_up)
val newToRocketChat = String.format(getString(R.string.msg_new_user), signUp)
text_new_to_rocket_chat.text = newToRocketChat text_new_to_rocket_chat.text = newToRocketChat
val signUpListener = object : ClickableSpan() { val signUpListener = object : ClickableSpan() {
override fun onClick(view: View) = presenter.signup() override fun onClick(view: View) = presenter.signup()
} }
TextHelper.addLink(text_new_to_rocket_chat, arrayOf(signUp), arrayOf(signUpListener)) TextHelper.addLink(text_new_to_rocket_chat, arrayOf(signUp), arrayOf(signUpListener))
}
} }
override fun hideSignUpView() { override fun hideSignUpView() {
text_new_to_rocket_chat.setVisible(false) ui {
text_new_to_rocket_chat.setVisible(false)
}
} }
override fun enableOauthView() { override fun enableOauthView() {
isOauthViewEnable = true ui {
showThreeSocialAccountsMethods() isOauthViewEnable = true
social_accounts_container.setVisible(true) showThreeSocialAccountsMethods()
social_accounts_container.setVisible(true)
}
} }
override fun disableOauthView() { override fun disableOauthView() {
isOauthViewEnable = false ui {
social_accounts_container.setVisible(false) isOauthViewEnable = false
social_accounts_container.setVisible(false)
}
} }
override fun showLoginButton() { override fun showLoginButton() {
button_log_in.setVisible(true) ui {
button_log_in.setVisible(true)
}
} }
override fun hideLoginButton() { override fun hideLoginButton() {
button_log_in.setVisible(false) ui {
button_log_in.setVisible(false)
}
} }
override fun enableLoginByFacebook() { override fun enableLoginByFacebook() {
button_facebook.isClickable = true ui {
button_facebook.isClickable = true
}
} }
override fun enableLoginByGithub() { override fun enableLoginByGithub() {
button_github.isClickable = true ui {
button_github.isClickable = true
}
} }
override fun setupGithubButtonListener(githubUrl: String, state: String) { override fun setupGithubButtonListener(githubUrl: String, state: String) {
button_github.setOnClickListener { ui { activity ->
startActivityForResult(context?.oauthWebViewIntent(githubUrl, state), REQUEST_CODE_FOR_OAUTH) button_github.setOnClickListener {
activity?.overridePendingTransition(R.anim.slide_up, R.anim.hold) startActivityForResult(activity.oauthWebViewIntent(githubUrl, state), REQUEST_CODE_FOR_OAUTH)
activity.overridePendingTransition(R.anim.slide_up, R.anim.hold)
}
} }
} }
override fun enableLoginByGoogle() { override fun enableLoginByGoogle() {
button_google.isClickable = true ui {
button_google.isClickable = true
}
} }
// TODO: Use custom tabs instead of web view. See https://github.com/RocketChat/Rocket.Chat.Android/issues/968 // TODO: Use custom tabs instead of web view. See https://github.com/RocketChat/Rocket.Chat.Android/issues/968
override fun setupGoogleButtonListener(googleUrl: String, state: String) { override fun setupGoogleButtonListener(googleUrl: String, state: String) {
button_google.setOnClickListener { ui { activity ->
startActivityForResult(context?.oauthWebViewIntent(googleUrl, state), REQUEST_CODE_FOR_OAUTH) button_google.setOnClickListener {
activity?.overridePendingTransition(R.anim.slide_up, R.anim.hold) startActivityForResult(activity.oauthWebViewIntent(googleUrl, state), REQUEST_CODE_FOR_OAUTH)
activity.overridePendingTransition(R.anim.slide_up, R.anim.hold)
}
} }
} }
override fun enableLoginByLinkedin() { override fun enableLoginByLinkedin() {
button_linkedin.isClickable = true ui {
button_linkedin.isClickable = true
}
} }
override fun setupLinkedinButtonListener(linkedinUrl: String, state: String) { override fun setupLinkedinButtonListener(linkedinUrl: String, state: String) {
button_linkedin.setOnClickListener { ui { activity ->
startActivityForResult(context?.oauthWebViewIntent(linkedinUrl, state), REQUEST_CODE_FOR_OAUTH) button_linkedin.setOnClickListener {
activity?.overridePendingTransition(R.anim.slide_up, R.anim.hold) startActivityForResult(activity.oauthWebViewIntent(linkedinUrl, state), REQUEST_CODE_FOR_OAUTH)
activity.overridePendingTransition(R.anim.slide_up, R.anim.hold)
}
} }
} }
override fun enableLoginByMeteor() { override fun enableLoginByMeteor() {
button_meteor.isClickable = true ui {
button_meteor.isClickable = true
}
} }
override fun enableLoginByTwitter() { override fun enableLoginByTwitter() {
button_twitter.isClickable = true ui {
button_twitter.isClickable = true
}
} }
override fun enableLoginByGitlab() { override fun enableLoginByGitlab() {
button_gitlab.isClickable = true ui {
button_gitlab.isClickable = true
}
} }
override fun setupGitlabButtonListener(gitlabUrl: String, state: String) { override fun setupGitlabButtonListener(gitlabUrl: String, state: String) {
button_gitlab.setOnClickListener { ui { activity ->
startActivityForResult(context?.oauthWebViewIntent(gitlabUrl, state), REQUEST_CODE_FOR_OAUTH) button_gitlab.setOnClickListener {
activity?.overridePendingTransition(R.anim.slide_up, R.anim.hold) startActivityForResult(activity.oauthWebViewIntent(gitlabUrl, state), REQUEST_CODE_FOR_OAUTH)
activity.overridePendingTransition(R.anim.slide_up, R.anim.hold)
}
} }
} }
override fun setupFabListener() { override fun setupFabListener() {
button_fab.setVisible(true) ui {
button_fab.setOnClickListener({ button_fab.setVisible(true)
button_fab.hide() button_fab.setOnClickListener({
showRemainingSocialAccountsView() button_fab.hide()
scrollToBottom() showRemainingSocialAccountsView()
}) scrollToBottom()
})
}
} }
override fun setupGlobalListener() { override fun setupGlobalListener() {
...@@ -276,19 +340,23 @@ class LoginFragment : Fragment(), LoginView { ...@@ -276,19 +340,23 @@ class LoginFragment : Fragment(), LoginView {
} }
override fun alertWrongUsernameOrEmail() { override fun alertWrongUsernameOrEmail() {
vibrateSmartPhone() ui {
text_username_or_email.shake() vibrateSmartPhone()
text_username_or_email.requestFocus() text_username_or_email.shake()
text_username_or_email.requestFocus()
}
} }
override fun alertWrongPassword() { override fun alertWrongPassword() {
vibrateSmartPhone() ui {
text_password.shake() vibrateSmartPhone()
text_password.requestFocus() text_password.shake()
text_password.requestFocus()
}
} }
override fun alertNotRecommendedVersion() { override fun alertNotRecommendedVersion() {
context?.let { ui {
AlertDialog.Builder(it) AlertDialog.Builder(it)
.setMessage(getString(R.string.msg_ver_not_recommended, BuildConfig.RECOMMENDED_SERVER_VERSION)) .setMessage(getString(R.string.msg_ver_not_recommended, BuildConfig.RECOMMENDED_SERVER_VERSION))
.setPositiveButton(R.string.msg_ok, null) .setPositiveButton(R.string.msg_ok, null)
...@@ -298,7 +366,7 @@ class LoginFragment : Fragment(), LoginView { ...@@ -298,7 +366,7 @@ class LoginFragment : Fragment(), LoginView {
} }
override fun blockAndAlertNotRequiredVersion() { override fun blockAndAlertNotRequiredVersion() {
context?.let { ui {
AlertDialog.Builder(it) AlertDialog.Builder(it)
.setMessage(getString(R.string.msg_ver_not_minimum, BuildConfig.REQUIRED_SERVER_VERSION)) .setMessage(getString(R.string.msg_ver_not_minimum, BuildConfig.REQUIRED_SERVER_VERSION))
.setOnDismissListener { activity?.onBackPressed() } .setOnDismissListener { activity?.onBackPressed() }
...@@ -313,14 +381,14 @@ class LoginFragment : Fragment(), LoginView { ...@@ -313,14 +381,14 @@ class LoginFragment : Fragment(), LoginView {
(0..social_accounts_container.childCount) (0..social_accounts_container.childCount)
.mapNotNull { social_accounts_container.getChildAt(it) as? ImageButton } .mapNotNull { social_accounts_container.getChildAt(it) as? ImageButton }
.filter { it.isClickable } .filter { it.isClickable }
.forEach { it.setVisible(true)} .forEach { ui { it.setVisible(true) }}
}, 1000) }, 1000)
} }
// Scrolling to the bottom of the screen. // Scrolling to the bottom of the screen.
private fun scrollToBottom() { private fun scrollToBottom() {
scroll_view.postDelayed({ scroll_view.postDelayed({
scroll_view.fullScroll(ScrollView.FOCUS_DOWN) ui { scroll_view.fullScroll(ScrollView.FOCUS_DOWN) }
}, 1250) }, 1250)
} }
...@@ -350,13 +418,13 @@ class LoginFragment : Fragment(), LoginView { ...@@ -350,13 +418,13 @@ class LoginFragment : Fragment(), LoginView {
.forEach { it.setVisible(true) } .forEach { it.setVisible(true) }
} }
fun showOauthView() { private fun showOauthView() {
if (isOauthViewEnable) { if (isOauthViewEnable) {
social_accounts_container.setVisible(true) social_accounts_container.setVisible(true)
} }
} }
fun hideOauthView() { private fun hideOauthView() {
if (isOauthViewEnable) { if (isOauthViewEnable) {
social_accounts_container.setVisible(false) social_accounts_container.setVisible(false)
button_fab.setVisible(false) button_fab.setVisible(false)
......
...@@ -59,26 +59,36 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView { ...@@ -59,26 +59,36 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
} }
override fun alertBlankUsername() { override fun alertBlankUsername() {
vibrateSmartPhone() ui {
text_username.shake() vibrateSmartPhone()
text_username.shake()
}
} }
override fun showLoading() { override fun showLoading() {
disableUserInput() ui {
view_loading.setVisible(true) disableUserInput()
view_loading.setVisible(true)
}
} }
override fun hideLoading() { override fun hideLoading() {
view_loading.setVisible(false) ui {
enableUserInput() view_loading.setVisible(false)
enableUserInput()
}
} }
override fun showMessage(resId: Int) { override fun showMessage(resId: Int) {
showToast(resId) ui {
showToast(resId)
}
} }
override fun showMessage(message: String) { override fun showMessage(message: String) {
showToast(message) ui {
showToast(message)
}
} }
override fun showGenericErrorMessage() { override fun showGenericErrorMessage() {
...@@ -86,10 +96,10 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView { ...@@ -86,10 +96,10 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
} }
private fun tintEditTextDrawableStart() { private fun tintEditTextDrawableStart() {
activity?.apply { ui {
val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_24dp, this) val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_24dp, it)
DrawableHelper.wrapDrawable(atDrawable) DrawableHelper.wrapDrawable(atDrawable)
DrawableHelper.tintDrawable(atDrawable, this, R.color.colorDrawableTintGrey) DrawableHelper.tintDrawable(atDrawable, it, R.color.colorDrawableTintGrey)
DrawableHelper.compoundDrawable(text_username, atDrawable) DrawableHelper.compoundDrawable(text_username, atDrawable)
} }
} }
......
...@@ -47,21 +47,29 @@ class ServerFragment : Fragment(), ServerView { ...@@ -47,21 +47,29 @@ class ServerFragment : Fragment(), ServerView {
override fun showInvalidServerUrlMessage() = showMessage(getString(R.string.msg_invalid_server_url)) override fun showInvalidServerUrlMessage() = showMessage(getString(R.string.msg_invalid_server_url))
override fun showLoading() { override fun showLoading() {
enableUserInput(false) ui {
view_loading.setVisible(true) enableUserInput(false)
view_loading.setVisible(true)
}
} }
override fun hideLoading() { override fun hideLoading() {
view_loading.setVisible(false) ui {
enableUserInput(true) view_loading.setVisible(false)
enableUserInput(true)
}
} }
override fun showMessage(resId: Int){ override fun showMessage(resId: Int){
showToast(resId) ui {
showToast(resId)
}
} }
override fun showMessage(message: String) { override fun showMessage(message: String) {
showToast(message) ui {
showToast(message)
}
} }
override fun showGenericErrorMessage() { override fun showGenericErrorMessage() {
......
...@@ -25,7 +25,7 @@ class SignupFragment : Fragment(), SignupView { ...@@ -25,7 +25,7 @@ class SignupFragment : Fragment(), SignupView {
} else { } else {
bottom_container.apply { bottom_container.apply {
postDelayed({ postDelayed({
setVisible(true) ui { setVisible(true) }
}, 3) }, 3)
} }
} }
...@@ -64,45 +64,61 @@ class SignupFragment : Fragment(), SignupView { ...@@ -64,45 +64,61 @@ class SignupFragment : Fragment(), SignupView {
} }
override fun alertBlankName() { override fun alertBlankName() {
vibrateSmartPhone() ui {
text_name.shake() vibrateSmartPhone()
text_name.requestFocus() text_name.shake()
text_name.requestFocus()
}
} }
override fun alertBlankUsername() { override fun alertBlankUsername() {
vibrateSmartPhone() ui {
text_username.shake() vibrateSmartPhone()
text_username.requestFocus() text_username.shake()
text_username.requestFocus()
}
} }
override fun alertEmptyPassword() { override fun alertEmptyPassword() {
vibrateSmartPhone() ui {
text_password.shake() vibrateSmartPhone()
text_password.requestFocus() text_password.shake()
text_password.requestFocus()
}
} }
override fun alertBlankEmail() { override fun alertBlankEmail() {
vibrateSmartPhone() ui {
text_email.shake() vibrateSmartPhone()
text_email.requestFocus() text_email.shake()
text_email.requestFocus()
}
} }
override fun showLoading() { override fun showLoading() {
enableUserInput(false) ui {
view_loading.setVisible(true) enableUserInput(false)
view_loading.setVisible(true)
}
} }
override fun hideLoading() { override fun hideLoading() {
view_loading.setVisible(false) ui {
enableUserInput(true) view_loading.setVisible(false)
enableUserInput(true)
}
} }
override fun showMessage(resId: Int) { override fun showMessage(resId: Int) {
showToast(resId) ui {
showToast(resId)
}
} }
override fun showMessage(message: String) { override fun showMessage(message: String) {
showToast(message) ui {
showToast(message)
}
} }
override fun showGenericErrorMessage() { override fun showGenericErrorMessage() {
...@@ -110,15 +126,15 @@ class SignupFragment : Fragment(), SignupView { ...@@ -110,15 +126,15 @@ class SignupFragment : Fragment(), SignupView {
} }
private fun tintEditTextDrawableStart() { private fun tintEditTextDrawableStart() {
activity?.apply { ui {
val personDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_person_black_24dp, this) val personDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_person_black_24dp, it)
val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_24dp, this) val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_24dp, it)
val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_lock_black_24dp, this) val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_lock_black_24dp, it)
val emailDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_email_black_24dp, this) val emailDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_email_black_24dp, it)
val drawables = arrayOf(personDrawable, atDrawable, lockDrawable, emailDrawable) val drawables = arrayOf(personDrawable, atDrawable, lockDrawable, emailDrawable)
DrawableHelper.wrapDrawables(drawables) DrawableHelper.wrapDrawables(drawables)
DrawableHelper.tintDrawables(drawables, this, R.color.colorDrawableTintGrey) DrawableHelper.tintDrawables(drawables, it, R.color.colorDrawableTintGrey)
DrawableHelper.compoundDrawables(arrayOf(text_name, text_username, text_password, text_email), drawables) DrawableHelper.compoundDrawables(arrayOf(text_name, text_username, text_password, text_email), drawables)
} }
} }
......
...@@ -63,8 +63,10 @@ class TwoFAFragment : Fragment(), TwoFAView { ...@@ -63,8 +63,10 @@ class TwoFAFragment : Fragment(), TwoFAView {
} }
override fun alertBlankTwoFactorAuthenticationCode() { override fun alertBlankTwoFactorAuthenticationCode() {
vibrateSmartPhone() ui {
text_two_factor_auth.shake() vibrateSmartPhone()
text_two_factor_auth.shake()
}
} }
override fun alertInvalidTwoFactorAuthenticationCode() { override fun alertInvalidTwoFactorAuthenticationCode() {
...@@ -72,30 +74,38 @@ class TwoFAFragment : Fragment(), TwoFAView { ...@@ -72,30 +74,38 @@ class TwoFAFragment : Fragment(), TwoFAView {
} }
override fun showLoading() { override fun showLoading() {
enableUserInput(false) ui {
view_loading.setVisible(true) enableUserInput(false)
view_loading.setVisible(true)
}
} }
override fun hideLoading() { override fun hideLoading() {
view_loading.setVisible(false) ui {
enableUserInput(true) view_loading.setVisible(false)
enableUserInput(true)
}
} }
override fun showMessage(resId: Int) { override fun showMessage(resId: Int) {
showToast(resId) ui {
showToast(resId)
}
} }
override fun showMessage(message: String) { override fun showMessage(message: String) {
showToast(message) ui {
showToast(message)
}
} }
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error)) override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
private fun tintEditTextDrawableStart() { private fun tintEditTextDrawableStart() {
activity?.apply { ui {
val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_vpn_key_black_24dp, this) val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_vpn_key_black_24dp, it)
DrawableHelper.wrapDrawable(lockDrawable) DrawableHelper.wrapDrawable(lockDrawable)
DrawableHelper.tintDrawable(lockDrawable, this, R.color.colorDrawableTintGrey) DrawableHelper.tintDrawable(lockDrawable, it, R.color.colorDrawableTintGrey)
DrawableHelper.compoundDrawable(text_two_factor_auth, lockDrawable) DrawableHelper.compoundDrawable(text_two_factor_auth, lockDrawable)
} }
} }
......
...@@ -18,6 +18,7 @@ import android.support.v7.widget.DefaultItemAnimator ...@@ -18,6 +18,7 @@ import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.view.* import android.view.*
import androidx.core.content.systemService
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.* import chat.rocket.android.chatroom.adapter.*
import chat.rocket.android.chatroom.presentation.ChatRoomPresenter import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
...@@ -183,28 +184,28 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -183,28 +184,28 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
override fun showMessages(dataSet: List<BaseViewModel<*>>) { override fun showMessages(dataSet: List<BaseViewModel<*>>) {
// track the message sent immediately after the current message ui {
var prevMessageViewModel: MessageViewModel? = null // track the message sent immediately after the current message
var prevMessageViewModel: MessageViewModel? = null
// Loop over received messages to determine first unread
for (i in dataSet.indices) { // Loop over received messages to determine first unread
val msgModel = dataSet[i] for (i in dataSet.indices) {
val msgModel = dataSet[i]
if (msgModel is MessageViewModel) {
val msg = msgModel.rawData if (msgModel is MessageViewModel) {
if (msg.timestamp < chatRoomLastSeen) { val msg = msgModel.rawData
// This message was sent before the last seen of the room. Hence, it was seen. if (msg.timestamp < chatRoomLastSeen) {
// if there is a message after (below) this, mark it firstUnread. // This message was sent before the last seen of the room. Hence, it was seen.
if (prevMessageViewModel != null) { // if there is a message after (below) this, mark it firstUnread.
prevMessageViewModel.isFirstUnread = true if (prevMessageViewModel != null) {
prevMessageViewModel.isFirstUnread = true
}
break
} }
break prevMessageViewModel = msgModel
} }
prevMessageViewModel = msgModel
} }
}
activity?.apply {
if (recycler_view.adapter == null) { if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(chatRoomType, chatRoomName, presenter, adapter = ChatRoomAdapter(chatRoomType, chatRoomName, presenter,
reactionListener = this@ChatRoomFragment) reactionListener = this@ChatRoomFragment)
...@@ -282,11 +283,13 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -282,11 +283,13 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
override fun sendMessage(text: String) { override fun sendMessage(text: String) {
if (!text.isBlank()) { ui {
if (!text.startsWith("/")) { if (!text.isBlank()) {
presenter.sendMessage(chatRoomId, text, editingMessageId) if (!text.startsWith("/")) {
} else { presenter.sendMessage(chatRoomId, text, editingMessageId)
presenter.runCommand(text, chatRoomId) } else {
presenter.runCommand(text, chatRoomId)
}
} }
} }
} }
...@@ -301,43 +304,55 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -301,43 +304,55 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
override fun showNewMessage(message: List<BaseViewModel<*>>) { override fun showNewMessage(message: List<BaseViewModel<*>>) {
adapter.prependData(message) ui {
recycler_view.scrollToPosition(0) adapter.prependData(message)
verticalScrollOffset.set(0) recycler_view.scrollToPosition(0)
verticalScrollOffset.set(0)
}
} }
override fun disableSendMessageButton() { override fun disableSendMessageButton() {
button_send.isEnabled = false ui {
button_send.isEnabled = false
}
} }
override fun enableSendMessageButton(sendFailed: Boolean) { override fun enableSendMessageButton(sendFailed: Boolean) {
button_send.isEnabled = true ui {
text_message.isEnabled = true button_send.isEnabled = true
if (!sendFailed) { text_message.isEnabled = true
clearMessageComposition() if (!sendFailed) {
clearMessageComposition()
}
} }
} }
override fun clearMessageComposition() { override fun clearMessageComposition() {
citation = null ui {
editingMessageId = null citation = null
text_message.textContent = "" editingMessageId = null
actionSnackbar.dismiss() text_message.textContent = ""
actionSnackbar.dismiss()
}
} }
override fun dispatchUpdateMessage(index: Int, message: List<BaseViewModel<*>>) { override fun dispatchUpdateMessage(index: Int, message: List<BaseViewModel<*>>) {
adapter.updateItem(message.last()) ui {
if (message.size > 1) { adapter.updateItem(message.last())
adapter.prependData(listOf(message.first())) if (message.size > 1) {
adapter.prependData(listOf(message.first()))
}
} }
} }
override fun dispatchDeleteMessage(msgId: String) { override fun dispatchDeleteMessage(msgId: String) {
adapter.removeItem(msgId) ui {
adapter.removeItem(msgId)
}
} }
override fun showReplyingAction(username: String, replyMarkdown: String, quotedMessage: String) { override fun showReplyingAction(username: String, replyMarkdown: String, quotedMessage: String) {
activity?.apply { ui {
citation = replyMarkdown citation = replyMarkdown
actionSnackbar.title = username actionSnackbar.title = username
actionSnackbar.text = quotedMessage actionSnackbar.text = quotedMessage
...@@ -352,41 +367,55 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -352,41 +367,55 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
override fun showLoading() = view_loading.setVisible(true) override fun showLoading() {
ui { view_loading.setVisible(true) }
}
override fun hideLoading() = view_loading.setVisible(false) override fun hideLoading() {
ui { view_loading.setVisible(false) }
}
override fun showMessage(message: String) { override fun showMessage(message: String) {
showToast(message) ui {
showToast(message)
}
} }
override fun showMessage(resId: Int) { override fun showMessage(resId: Int) {
showToast(resId) ui {
showToast(resId)
}
} }
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error)) override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
override fun populatePeopleSuggestions(members: List<PeopleSuggestionViewModel>) { override fun populatePeopleSuggestions(members: List<PeopleSuggestionViewModel>) {
suggestions_view.addItems("@", members) ui {
suggestions_view.addItems("@", members)
}
} }
override fun populateRoomSuggestions(chatRooms: List<ChatRoomSuggestionViewModel>) { override fun populateRoomSuggestions(chatRooms: List<ChatRoomSuggestionViewModel>) {
suggestions_view.addItems("#", chatRooms) ui {
suggestions_view.addItems("#", chatRooms)
}
} }
override fun populateCommandSuggestions(commands: List<CommandSuggestionViewModel>) { override fun populateCommandSuggestions(commands: List<CommandSuggestionViewModel>) {
suggestions_view.addItems("/", commands) ui {
suggestions_view.addItems("/", commands)
}
} }
override fun copyToClipboard(message: String) { override fun copyToClipboard(message: String) {
activity?.apply { ui {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clipboard: ClipboardManager = it.systemService()
clipboard.primaryClip = ClipData.newPlainText("", message) clipboard.primaryClip = ClipData.newPlainText("", message)
} }
} }
override fun showEditingAction(roomId: String, messageId: String, text: String) { override fun showEditingAction(roomId: String, messageId: String, text: String) {
activity?.apply { ui {
actionSnackbar.title = getString(R.string.action_title_editing) actionSnackbar.title = getString(R.string.action_title_editing)
actionSnackbar.text = text actionSnackbar.text = text
actionSnackbar.show() actionSnackbar.show()
...@@ -422,7 +451,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -422,7 +451,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
override fun showReactionsPopup(messageId: String) { override fun showReactionsPopup(messageId: String) {
context?.let { ui {
val emojiPickerPopup = EmojiPickerPopup(it) val emojiPickerPopup = EmojiPickerPopup(it)
emojiPickerPopup.listener = object : EmojiListenerAdapter() { emojiPickerPopup.listener = object : EmojiListenerAdapter() {
override fun onEmojiAdded(emoji: Emoji) { override fun onEmojiAdded(emoji: Emoji) {
...@@ -435,11 +464,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -435,11 +464,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private fun setReactionButtonIcon(@DrawableRes drawableId: Int) { private fun setReactionButtonIcon(@DrawableRes drawableId: Int) {
button_add_reaction.setImageResource(drawableId) button_add_reaction.setImageResource(drawableId)
button_add_reaction.setTag(drawableId) button_add_reaction.tag = drawableId
} }
override fun showFileSelection(filter: Array<String>) { override fun showFileSelection(filter: Array<String>) {
activity?.let { ui {
if (ContextCompat.checkSelfPermission(it, Manifest.permission.READ_EXTERNAL_STORAGE) if (ContextCompat.checkSelfPermission(it, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) { != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(it, ActivityCompat.requestPermissions(it,
...@@ -459,7 +488,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -459,7 +488,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
1 -> { 1 -> {
if (!(grantResults.isNotEmpty() && grantResults.first() == PackageManager.PERMISSION_GRANTED)) { if (!(grantResults.isNotEmpty() && grantResults.first() == PackageManager.PERMISSION_GRANTED)) {
handler.postDelayed({ handler.postDelayed({
hideAttachmentOptions() ui { hideAttachmentOptions() }
}, 400) }, 400)
} }
} }
...@@ -471,7 +500,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -471,7 +500,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
override fun showConnectionState(state: State) { override fun showConnectionState(state: State) {
activity?.apply { ui {
connection_status_text.fadeIn() connection_status_text.fadeIn()
handler.removeCallbacks(dismissStatus) handler.removeCallbacks(dismissStatus)
when (state) { when (state) {
...@@ -489,10 +518,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -489,10 +518,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
override fun onJoined() { override fun onJoined() {
input_container.setVisible(true) ui {
button_join_chat.setVisible(false) input_container.setVisible(true)
isSubscribed = true button_join_chat.setVisible(false)
setupMessageComposer() isSubscribed = true
setupMessageComposer()
}
} }
private val dismissStatus = { private val dismissStatus = {
......
...@@ -16,6 +16,7 @@ import chat.rocket.android.chatroom.viewmodel.BaseViewModel ...@@ -16,6 +16,7 @@ import chat.rocket.android.chatroom.viewmodel.BaseViewModel
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.util.extensions.setVisible import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import dagger.android.support.AndroidSupportInjection 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
...@@ -62,22 +63,30 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView { ...@@ -62,22 +63,30 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
presenter.loadPinnedMessages(chatRoomId) presenter.loadPinnedMessages(chatRoomId)
} }
override fun showLoading() = view_loading.setVisible(true) override fun showLoading() {
ui { view_loading.setVisible(true) }
}
override fun hideLoading() = view_loading.setVisible(false) override fun hideLoading() {
ui { view_loading.setVisible(false) }
}
override fun showMessage(resId: Int) { override fun showMessage(resId: Int) {
showToast(resId) ui {
showToast(resId)
}
} }
override fun showMessage(message: String) { override fun showMessage(message: String) {
showToast(message) ui {
showToast(message)
}
} }
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error)) override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
override fun showPinnedMessages(pinnedMessages: List<BaseViewModel<*>>) { override fun showPinnedMessages(pinnedMessages: List<BaseViewModel<*>>) {
activity?.apply { ui {
if (recycler_view_pinned.adapter == null) { if (recycler_view_pinned.adapter == null) {
// TODO - add a better constructor for this case... // TODO - add a better constructor for this case...
adapter = ChatRoomAdapter(chatRoomType, chatRoomName, null, false) adapter = ChatRoomAdapter(chatRoomType, chatRoomName, null, false)
......
...@@ -270,6 +270,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView, ...@@ -270,6 +270,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
// TODO - Temporary stuff, remove when adding DB support // TODO - Temporary stuff, remove when adding DB support
private suspend fun subscribeRoomUpdates() { private suspend fun subscribeRoomUpdates() {
manager.addStatusChannel(stateChannel) manager.addStatusChannel(stateChannel)
view.showConnectionState(client.state)
manager.addRoomsAndSubscriptionsChannel(subscriptionsChannel) manager.addRoomsAndSubscriptionsChannel(subscriptionsChannel)
launch(CommonPool + strategy.jobs) { launch(CommonPool + strategy.jobs) {
for (message in subscriptionsChannel) { for (message in subscriptionsChannel) {
......
...@@ -24,7 +24,6 @@ import chat.rocket.android.util.extensions.textContent ...@@ -24,7 +24,6 @@ import chat.rocket.android.util.extensions.textContent
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.core.model.ChatRoom import chat.rocket.core.model.ChatRoom
import com.facebook.drawee.view.SimpleDraweeView import com.facebook.drawee.view.SimpleDraweeView
import kotlinx.android.synthetic.main.avatar.view.*
import kotlinx.android.synthetic.main.item_chat.view.* import kotlinx.android.synthetic.main.item_chat.view.*
import kotlinx.android.synthetic.main.unread_messages_badge.view.* import kotlinx.android.synthetic.main.unread_messages_badge.view.*
......
...@@ -32,9 +32,11 @@ import dagger.android.support.AndroidSupportInjection ...@@ -32,9 +32,11 @@ import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_chat_rooms.* import kotlinx.android.synthetic.main.fragment_chat_rooms.*
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.Job import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.NonCancellable.isActive
import kotlinx.coroutines.experimental.android.UI import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.async import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.experimental.launch
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
...@@ -101,8 +103,8 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -101,8 +103,8 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
} }
override fun onOptionsItemSelected(item: MenuItem?): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item?.itemId) { when (item.itemId) {
R.id.action_sort -> { R.id.action_sort -> {
val dialogLayout = layoutInflater.inflate(R.layout.chatroom_sort_dialog, null) val dialogLayout = layoutInflater.inflate(R.layout.chatroom_sort_dialog, null)
val sortType = SharedPreferenceHelper.getInt(Constants.CHATROOM_SORT_TYPE_KEY, ChatRoomsSortOrder.ACTIVITY) val sortType = SharedPreferenceHelper.getInt(Constants.CHATROOM_SORT_TYPE_KEY, ChatRoomsSortOrder.ACTIVITY)
...@@ -154,50 +156,57 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -154,50 +156,57 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
} }
override suspend fun updateChatRooms(newDataSet: List<ChatRoom>) { override suspend fun updateChatRooms(newDataSet: List<ChatRoom>) {
activity?.apply { listJob?.cancel()
listJob?.cancel() listJob = ui {
listJob = launch(UI) { val adapter = recycler_view.adapter as SimpleSectionedRecyclerViewAdapter
val adapter = recycler_view.adapter as SimpleSectionedRecyclerViewAdapter // FIXME https://fabric.io/rocketchat3/android/apps/chat.rocket.android/issues/5ac2916c36c7b235275ccccf
// FIXME https://fabric.io/rocketchat3/android/apps/chat.rocket.android/issues/5ac2916c36c7b235275ccccf // TODO - fix this bug to re-enable DiffUtil
// TODO - fix this bug to re-enable DiffUtil /*val diff = async(CommonPool) {
/*val diff = async(CommonPool) { DiffUtil.calculateDiff(RoomsDiffCallback(adapter.baseAdapter.dataSet, newDataSet))
DiffUtil.calculateDiff(RoomsDiffCallback(adapter.baseAdapter.dataSet, newDataSet)) }.await()*/
}.await()*/
if (isActive) {
if (isActive) { adapter.baseAdapter.updateRooms(newDataSet)
adapter.baseAdapter.updateRooms(newDataSet) // TODO - fix crash to re-enable diff.dispatchUpdatesTo(adapter)
// TODO - fix crash to re-enable diff.dispatchUpdatesTo(adapter) adapter.notifyDataSetChanged()
adapter.notifyDataSetChanged()
//Set sections always after data set is updated
//Set sections always after data set is updated setSections()
setSections()
}
} }
} }
} }
override fun showNoChatRoomsToDisplay() = text_no_data_to_display.setVisible(true) override fun showNoChatRoomsToDisplay() {
ui { text_no_data_to_display.setVisible(true) }
}
override fun showLoading() = view_loading.setVisible(true) override fun showLoading(){
ui { view_loading.setVisible(true) }
}
override fun hideLoading() { override fun hideLoading() {
if (view_loading != null) { ui {
view_loading.setVisible(false) view_loading.setVisible(false)
} }
} }
override fun showMessage(resId: Int) { override fun showMessage(resId: Int) {
showToast(resId) ui {
showToast(resId)
}
} }
override fun showMessage(message: String) { override fun showMessage(message: String) {
showToast(message) ui {
showToast(message)
}
} }
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error)) override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
override fun showConnectionState(state: State) { override fun showConnectionState(state: State) {
activity?.apply { Timber.d("Got new state: $state")
ui {
connection_status_text.fadeIn() connection_status_text.fadeIn()
handler.removeCallbacks(dismissStatus) handler.removeCallbacks(dismissStatus)
when (state) { when (state) {
...@@ -221,22 +230,25 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -221,22 +230,25 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
} }
private fun setupToolbar() { private fun setupToolbar() {
(activity as AppCompatActivity).supportActionBar?.title = getString(R.string.title_chats) (activity as AppCompatActivity?)?.supportActionBar?.title = getString(R.string.title_chats)
} }
private fun setupRecyclerView() { private fun setupRecyclerView() {
activity?.apply { ui {
recycler_view.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) recycler_view.layoutManager = LinearLayoutManager(it, LinearLayoutManager.VERTICAL, false)
recycler_view.addItemDecoration(DividerItemDecoration(this, recycler_view.addItemDecoration(DividerItemDecoration(it,
resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_start), resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_start),
resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_end))) resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_end)))
recycler_view.itemAnimator = DefaultItemAnimator() recycler_view.itemAnimator = DefaultItemAnimator()
// TODO - use a ViewModel Mapper instead of using settings on the adapter // TODO - use a ViewModel Mapper instead of using settings on the adapter
val baseAdapter = ChatRoomsAdapter(this, val baseAdapter = ChatRoomsAdapter(it,
settingsRepository.get(serverInteractor.get()!!), localRepository) { chatRoom -> presenter.loadChatRoom(chatRoom) } settingsRepository.get(serverInteractor.get()!!), localRepository) {
chatRoom -> presenter.loadChatRoom(chatRoom)
}
sectionedAdapter = SimpleSectionedRecyclerViewAdapter(this, R.layout.item_chatroom_header, R.id.text_chatroom_header, baseAdapter!!) sectionedAdapter = SimpleSectionedRecyclerViewAdapter(it,
R.layout.item_chatroom_header, R.id.text_chatroom_header, baseAdapter)
recycler_view.adapter = sectionedAdapter recycler_view.adapter = sectionedAdapter
} }
} }
......
package chat.rocket.android.members.presentation package chat.rocket.android.members.presentation
import chat.rocket.android.chatroom.ui.ChatRoomActivity import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.member.ui.newInstance import chat.rocket.android.members.ui.newInstance
class MembersNavigator(internal val activity: ChatRoomActivity) { class MembersNavigator(internal val activity: ChatRoomActivity) {
......
package chat.rocket.android.member.ui package chat.rocket.android.members.ui
import android.os.Bundle import android.os.Bundle
import android.support.design.widget.BottomSheetDialogFragment import android.support.design.widget.BottomSheetDialogFragment
......
...@@ -19,6 +19,7 @@ import chat.rocket.android.members.viewmodel.MemberViewModel ...@@ -19,6 +19,7 @@ import chat.rocket.android.members.viewmodel.MemberViewModel
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.setVisible import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.widget.DividerItemDecoration import chat.rocket.android.widget.DividerItemDecoration
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_members.* import kotlinx.android.synthetic.main.fragment_members.*
...@@ -70,7 +71,7 @@ class MembersFragment : Fragment(), MembersView { ...@@ -70,7 +71,7 @@ class MembersFragment : Fragment(), MembersView {
} }
override fun showMembers(dataSet: List<MemberViewModel>, total: Long) { override fun showMembers(dataSet: List<MemberViewModel>, total: Long) {
activity?.apply { ui {
setupToolbar(total) setupToolbar(total)
if (adapter.itemCount == 0) { if (adapter.itemCount == 0) {
adapter.prependData(dataSet) adapter.prependData(dataSet)
...@@ -84,8 +85,8 @@ class MembersFragment : Fragment(), MembersView { ...@@ -84,8 +85,8 @@ class MembersFragment : Fragment(), MembersView {
} else { } else {
adapter.appendData(dataSet) adapter.appendData(dataSet)
} }
if (this is ChatRoomActivity) { if (it is ChatRoomActivity) {
this.showRoomTypeIcon(false) it.showRoomTypeIcon(false)
} }
} }
} }
...@@ -98,29 +99,37 @@ class MembersFragment : Fragment(), MembersView { ...@@ -98,29 +99,37 @@ class MembersFragment : Fragment(), MembersView {
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
override fun showLoading() = view_loading.setVisible(true) override fun showLoading() {
ui { view_loading.setVisible(true) }
}
override fun hideLoading() = view_loading.setVisible(false) override fun hideLoading() {
ui { view_loading.setVisible(false) }
}
override fun showMessage(resId: Int) { override fun showMessage(resId: Int) {
showToast(resId) ui {
showToast(resId)
}
} }
override fun showMessage(message: String) { override fun showMessage(message: String) {
showToast(message) ui {
showToast(message)
}
} }
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error)) override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
private fun setupRecyclerView() { private fun setupRecyclerView() {
activity?.apply { ui {
recycler_view.layoutManager = linearLayoutManager recycler_view.layoutManager = linearLayoutManager
recycler_view.addItemDecoration(DividerItemDecoration(this)) recycler_view.addItemDecoration(DividerItemDecoration(it))
recycler_view.adapter = adapter recycler_view.adapter = adapter
} }
} }
private fun setupToolbar(totalMembers: Long) { private fun setupToolbar(totalMembers: Long) {
(activity as ChatRoomActivity).setupToolbarTitle(getString(R.string.title_members, totalMembers)) (activity as ChatRoomActivity?)?.setupToolbarTitle(getString(R.string.title_members, totalMembers))
} }
} }
\ No newline at end of file
...@@ -15,7 +15,7 @@ import java.util.concurrent.CopyOnWriteArrayList ...@@ -15,7 +15,7 @@ import java.util.concurrent.CopyOnWriteArrayList
class ConnectionManager(internal val client: RocketChatClient) { class ConnectionManager(internal val client: RocketChatClient) {
private val statusChannelList = CopyOnWriteArrayList<Channel<State>>() private val statusChannelList = CopyOnWriteArrayList<Channel<State>>()
private val statusChannel = Channel<State>() private val statusChannel = Channel<State>(Channel.CONFLATED)
private var connectJob: Job? = null private var connectJob: Job? = null
private val roomAndSubscriptionChannels = ArrayList<Channel<StreamMessage<BaseRoom>>>() private val roomAndSubscriptionChannels = ArrayList<Channel<StreamMessage<BaseRoom>>>()
...@@ -67,7 +67,8 @@ class ConnectionManager(internal val client: RocketChatClient) { ...@@ -67,7 +67,8 @@ class ConnectionManager(internal val client: RocketChatClient) {
} }
for (channel in statusChannelList) { for (channel in statusChannelList) {
channel.send(status) Timber.d("Sending status: $status to $channel")
channel.offer(status)
} }
} }
} }
......
...@@ -11,7 +11,10 @@ import chat.rocket.android.util.extensions.asObservable ...@@ -11,7 +11,10 @@ import chat.rocket.android.util.extensions.asObservable
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.textContent import chat.rocket.android.util.extensions.textContent
import android.support.v7.view.ActionMode import android.support.v7.view.ActionMode
import chat.rocket.android.util.extensions.ui
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.Observables import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.fragment_password.* import kotlinx.android.synthetic.main.fragment_password.*
import javax.inject.Inject import javax.inject.Inject
...@@ -19,6 +22,7 @@ import javax.inject.Inject ...@@ -19,6 +22,7 @@ import javax.inject.Inject
class PasswordFragment: Fragment(), PasswordView, android.support.v7.view.ActionMode.Callback { class PasswordFragment: Fragment(), PasswordView, android.support.v7.view.ActionMode.Callback {
@Inject lateinit var presenter: PasswordPresenter @Inject lateinit var presenter: PasswordPresenter
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
private val disposables = CompositeDisposable()
companion object { companion object {
fun newInstance() = PasswordFragment() fun newInstance() = PasswordFragment()
...@@ -34,13 +38,20 @@ class PasswordFragment: Fragment(), PasswordView, android.support.v7.view.Action ...@@ -34,13 +38,20 @@ class PasswordFragment: Fragment(), PasswordView, android.support.v7.view.Action
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
listenToChanges() disposables.add(listenToChanges())
}
override fun onDestroyView() {
disposables.clear()
super.onDestroyView()
} }
override fun hideLoading() { override fun hideLoading() {
layout_new_password.visibility = View.VISIBLE ui {
layout_confirm_password.visibility = View.VISIBLE layout_new_password.visibility = View.VISIBLE
view_loading.visibility = View.GONE layout_confirm_password.visibility = View.VISIBLE
view_loading.visibility = View.GONE
}
} }
override fun onActionItemClicked(mode: ActionMode, menuItem: MenuItem): Boolean { override fun onActionItemClicked(mode: ActionMode, menuItem: MenuItem): Boolean {
...@@ -69,9 +80,11 @@ class PasswordFragment: Fragment(), PasswordView, android.support.v7.view.Action ...@@ -69,9 +80,11 @@ class PasswordFragment: Fragment(), PasswordView, android.support.v7.view.Action
} }
override fun showLoading() { override fun showLoading() {
layout_new_password.visibility = View.GONE ui {
layout_confirm_password.visibility = View.GONE layout_new_password.visibility = View.GONE
view_loading.visibility = View.VISIBLE layout_confirm_password.visibility = View.GONE
view_loading.visibility = View.VISIBLE
}
} }
override fun showPasswordFailsUpdateMessage(error: String?) { override fun showPasswordFailsUpdateMessage(error: String?) {
...@@ -84,8 +97,9 @@ class PasswordFragment: Fragment(), PasswordView, android.support.v7.view.Action ...@@ -84,8 +97,9 @@ class PasswordFragment: Fragment(), PasswordView, android.support.v7.view.Action
private fun finishActionMode() = actionMode?.finish() private fun finishActionMode() = actionMode?.finish()
private fun listenToChanges() { private fun listenToChanges(): Disposable {
Observables.combineLatest(text_new_password.asObservable(), text_confirm_password.asObservable()).subscribe { return Observables.combineLatest(text_new_password.asObservable(),
text_confirm_password.asObservable()).subscribe {
val textPassword = text_new_password.textContent val textPassword = text_new_password.textContent
val textConfirmPassword = text_confirm_password.textContent val textConfirmPassword = text_confirm_password.textContent
...@@ -97,7 +111,9 @@ class PasswordFragment: Fragment(), PasswordView, android.support.v7.view.Action ...@@ -97,7 +111,9 @@ class PasswordFragment: Fragment(), PasswordView, android.support.v7.view.Action
} }
private fun showToast(msg: String?) { private fun showToast(msg: String?) {
Toast.makeText(context, msg, Toast.LENGTH_LONG).show() ui {
Toast.makeText(it, msg, Toast.LENGTH_LONG).show()
}
} }
private fun startActionMode() { private fun startActionMode() {
......
package chat.rocket.android.util.extensions
import android.os.Looper
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.launch
inline fun Fragment.ui(crossinline block: (activity: FragmentActivity) -> Unit): Job? {
// Checking first for activity and view saves us from some synchronyzed and thread local checks
if (activity != null && view != null) {
// If we already are running on the Main Thread (UI Thread), just go ahead and execute the block
return if (Looper.getMainLooper() == Looper.myLooper()) {
block(activity!!)
null
} else {
// Launch a Job on the UI context and check again if the activity and view are still valid
launch(UI) {
if (activity != null && view != null) {
block(activity!!)
}
}
}
}
return null
}
\ No newline at end of file
...@@ -10,14 +10,14 @@ ...@@ -10,14 +10,14 @@
android:paddingTop="@dimen/chat_item_top_and_bottom_padding" android:paddingTop="@dimen/chat_item_top_and_bottom_padding"
android:paddingBottom="@dimen/chat_item_top_and_bottom_padding"> android:paddingBottom="@dimen/chat_item_top_and_bottom_padding">
<include <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/layout_avatar" android:id="@+id/image_avatar"
layout="@layout/avatar"
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="40dp" android:layout_height="40dp"
app:roundedCornerRadius="3dp"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent"/>
<TextView <TextView
android:id="@+id/text_chat_name" android:id="@+id/text_chat_name"
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
app:layout_constraintStart_toEndOf="@id/layout_avatar" app:layout_constraintStart_toEndOf="@id/image_avatar"
android:textDirection="locale" android:textDirection="locale"
tools:text="General"/> tools:text="General"/>
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
app:layout_constraintTop_toBottomOf="@id/text_chat_name" app:layout_constraintTop_toBottomOf="@id/text_chat_name"
app:layout_constraintEnd_toStartOf="@id/layout_unread_messages_badge" app:layout_constraintEnd_toStartOf="@id/layout_unread_messages_badge"
android:textDirection="locale" android:textDirection="locale"
tools:text="You: Type something"/> tools:text="You: Type something that is very big and need at least to lines, or maybe even more"/>
<include <include
android:id="@+id/layout_unread_messages_badge" android:id="@+id/layout_unread_messages_badge"
......
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>
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