Commit 9de81ba8 authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Merge branch 'develop' of github.com:RocketChat/Rocket.Chat.Android into...

Merge branch 'develop' of github.com:RocketChat/Rocket.Chat.Android into improvement/set-temporary-status
parents f5026f1d 73d09b24
...@@ -5,34 +5,36 @@ ...@@ -5,34 +5,36 @@
[![CircleCI](https://circleci.com/gh/RocketChat/Rocket.Chat.Android/tree/develop.svg?style=shield)](https://circleci.com/gh/RocketChat/Rocket.Chat.Android/tree/develop) [![Build Status](https://travis-ci.org/RocketChat/Rocket.Chat.Android.svg?branch=develop)](https://travis-ci.org/RocketChat/Rocket.Chat.Android) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a81156a8682e4649994270d3670c3c83)](https://www.codacy.com/app/matheusjardimb/Rocket.Chat.Android) [![CircleCI](https://circleci.com/gh/RocketChat/Rocket.Chat.Android/tree/develop.svg?style=shield)](https://circleci.com/gh/RocketChat/Rocket.Chat.Android/tree/develop) [![Build Status](https://travis-ci.org/RocketChat/Rocket.Chat.Android.svg?branch=develop)](https://travis-ci.org/RocketChat/Rocket.Chat.Android) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a81156a8682e4649994270d3670c3c83)](https://www.codacy.com/app/matheusjardimb/Rocket.Chat.Android)
## Description ## Description
Currently, the app is maintained in two branches, namely `v1+` and `v2+`. The `v1+` is maintained in the `develop` branch and the `v2+` is maintained in the `develop-2.x` branch. The older version is written partially in `java` and `kotlin`, but we intend to write the latest version completely in `kotlin`.
Clone the repository by running `git clone https://github.com/RocketChat/Rocket.Chat.Android.git` in your terminal. To build the v1.0+ of the app, run `git checkout develop` and to build the v2.0+, run `git checkout develop-2.x`. This repository contains all the code related to the Android native application of [Rocket.Chat](https://github.com/RocketChat/Rocket.Chat/#about-rocketchat). To send new pull-requests, always use the branch `develop` as base and open an issue with the description of what you want/need to accomplish, if the issue wasn't created yet.
Since both the versions use `kotlin` for some or all of their classes, following are the common prerequisites for both versions:
## How to build ## How to build
- Android Studio 3.0+ comes with built in kotlin support, so install the latest version (3.0+) of Android Studio (recommended). For older versions, you need to manually install kotlin plugin. Go to `File > Settings > Plugins` and search for `kotlin` and install it. You'll need to restart the IDE in order to see the changes. - Android Studio 3.0+ comes with built in kotlin support, so install the latest version (3.0+) of Android Studio (recommended). For older versions, you need to manually install kotlin plugin. Go to `File > Settings > Plugins` and search for `kotlin` and install it. You'll need to restart the IDE in order to see the changes.
- Make sure that you have the latest **gradle** and the **android plugin** versions installed. Go to `File > Project Structure > Project` and make sure that you have the latest versions installed. Refer [this](https://developer.android.com/studio/releases/gradle-plugin.html#updating-gradle) to see the compatible versions. - Make sure that you have the latest **gradle** and the **android plugin** versions installed. Go to `File > Project Structure > Project` and make sure that you have the latest versions installed. Refer [this](https://developer.android.com/studio/releases/gradle-plugin.html#updating-gradle) to see the compatible versions.
- Kotlin is already configured in the project. To check, go to `Tools > Kotlin > Configure Kotlin in project`. A message saying kotlin is already configured in the project pops up. You can update kotlin to the latest version by going to `Tools > Kotlin > Configure Kotlin updates` and download the latest version of kotlin. - Kotlin is already configured in the project. To check, go to `Tools > Kotlin > Configure Kotlin in project`. A message saying kotlin is already configured in the project pops up. You can update kotlin to the latest version by going to `Tools > Kotlin > Configure Kotlin updates` and download the latest version of kotlin.
### Instructions specific to version ### SDK Instructions
#### v1.0+
- After checking out to `develop` branch as mentioned above, simply import the project in Android Studio.
#### v2+
- 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`. - 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, 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: - 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:
``` ```
cd Rocket.Chat.Android/app cd Rocket.Chat.Android/app
./build-sdk.sh ./build-sdk.sh
``` ```
## How to run ## How to run
### Command Line ### Command Line
- Connect your physical device to your pc via USB or start an emulator. Run `adb devices` in terminal. You should see your device in the list of devices. - Connect your physical device to your pc via USB or start an emulator. Run `adb devices` in terminal. You should see your device in the list of devices.
- In order to build the debug apk, run `./gradlew assembleDebug`. This would generate a debug apk which can be found under `Rocket.Chat.Android/app/build/outputs/apk/debug` folder with the name `app-debug.apk`. - In order to build the debug apk, run `./gradlew assembleDebug`. This would generate a debug apk which can be found under `Rocket.Chat.Android/app/build/outputs/apk/debug` folder with the name `app-debug.apk`.
- In order to build and install the apk directly to the connected device, run `./gradlew installDebug`. - In order to build and install the apk directly to the connected device, run `./gradlew installDebug`.
### Android Studio ### Android Studio
- After importing the project in android studio, go to `Run > Run app` and then select your device, or create a new virtual device by following the wizard. - After importing the project in android studio, go to `Run > Run app` and then select your device, or create a new virtual device by following the wizard.
## Bug report & Feature request ## Bug report & Feature request
......
...@@ -13,7 +13,7 @@ android { ...@@ -13,7 +13,7 @@ android {
applicationId "chat.rocket.android" applicationId "chat.rocket.android"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion versions.targetSdk targetSdkVersion versions.targetSdk
versionCode 2013 versionCode 2015
versionName "2.1.0" versionName "2.1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission <permission
......
...@@ -26,11 +26,11 @@ private const val TYPE_LOGIN_USER_EMAIL = 0 ...@@ -26,11 +26,11 @@ private const val TYPE_LOGIN_USER_EMAIL = 0
private const val TYPE_LOGIN_CAS = 1 private const val TYPE_LOGIN_CAS = 1
private const val TYPE_LOGIN_OAUTH = 2 private const val TYPE_LOGIN_OAUTH = 2
private const val TYPE_LOGIN_DEEP_LINK = 3 private const val TYPE_LOGIN_DEEP_LINK = 3
private const val SERVICE_NAME_FACEBOOK = "facebook"
private const val SERVICE_NAME_GITHUB = "github" private const val SERVICE_NAME_GITHUB = "github"
private const val SERVICE_NAME_GOOGLE = "google" private const val SERVICE_NAME_GOOGLE = "google"
private const val SERVICE_NAME_LINKEDIN = "linkedin" private const val SERVICE_NAME_LINKEDIN = "linkedin"
private const val SERVICE_NAME_GILAB = "gitlab" private const val SERVICE_NAME_GILAB = "gitlab"
private const val SERVICE_NAME_FACEBOOK = "facebook"
class LoginPresenter @Inject constructor( class LoginPresenter @Inject constructor(
private val view: LoginView, private val view: LoginView,
...@@ -279,9 +279,10 @@ class LoginPresenter @Inject constructor( ...@@ -279,9 +279,10 @@ class LoginPresenter @Inject constructor(
} }
} }
private fun getOauthClientId(listMap: List<Map<String, String>>, serviceName: String): String? { private fun getOauthClientId(listMap: List<Map<String, Any>>, serviceName: String): String? {
return listMap.find { map -> map.containsValue(serviceName) } return listMap.find { map -> map.containsValue(serviceName) }?.let {
?.get("appId") it["clientId"] ?: it["appId"]
}.toString()
} }
private suspend fun saveAccount(username: String) { private suspend fun saveAccount(username: String) {
......
...@@ -11,8 +11,19 @@ interface VersionCheckView { ...@@ -11,8 +11,19 @@ interface VersionCheckView {
*/ */
fun blockAndAlertNotRequiredVersion() fun blockAndAlertNotRequiredVersion()
/**
* Alerts the user that an error has occurred while checking the server version
* This is optional.
*/
fun errorCheckingServerVersion() {}
/** /**
* Do some action if version is ok. This is optional. * Do some action if version is ok. This is optional.
*/ */
fun versionOk() {} fun versionOk() {}
/**
* Alters the user this protocol is invalid. This is optional.
*/
fun errorInvalidProtocol() {}
} }
\ No newline at end of file
...@@ -8,6 +8,8 @@ import android.view.LayoutInflater ...@@ -8,6 +8,8 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.widget.AdapterView
import android.widget.ArrayAdapter
import chat.rocket.android.BuildConfig import chat.rocket.android.BuildConfig
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo import chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
...@@ -38,6 +40,8 @@ class ServerFragment : Fragment(), ServerView { ...@@ -38,6 +40,8 @@ class ServerFragment : Fragment(), ServerView {
} }
} }
private var protocol = "https://"
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
...@@ -55,9 +59,40 @@ class ServerFragment : Fragment(), ServerView { ...@@ -55,9 +59,40 @@ class ServerFragment : Fragment(), ServerView {
deepLinkInfo?.let { deepLinkInfo?.let {
val uri = Uri.parse(it.url) val uri = Uri.parse(it.url)
uri?.let { text_server_protocol.hintContent = it.host } uri?.let { text_server_url.hintContent = it.host }
presenter.deepLink(it) presenter.deepLink(it)
} }
text_server_protocol.adapter = ArrayAdapter<String>(activity,
android.R.layout.simple_dropdown_item_1line, arrayOf("https://", "http://"))
text_server_protocol.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when(position) {
0 -> {
protocol = "https://"
}
1 -> {
ui{
AlertDialog.Builder(it)
.setTitle(R.string.msg_warning)
.setMessage(R.string.msg_http_insecure)
.setPositiveButton(R.string.msg_proceed) { _, _ ->
protocol = "http://"
}
.setNegativeButton(R.string.msg_cancel) { _, _ ->
text_server_protocol.setSelection(0)
}
.setCancelable(false)
.create()
.show()
}
}
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
} }
override fun onDestroyView() { override fun onDestroyView() {
...@@ -129,13 +164,23 @@ class ServerFragment : Fragment(), ServerView { ...@@ -129,13 +164,23 @@ class ServerFragment : Fragment(), ServerView {
performConnect() performConnect()
} }
override fun errorCheckingServerVersion() {
hideLoading()
showMessage(R.string.msg_error_checking_server_version)
}
override fun errorInvalidProtocol() {
hideLoading()
showMessage(R.string.msg_invalid_server_protocol)
}
private fun performConnect() { private fun performConnect() {
ui { ui {
deepLinkInfo?.let { deepLinkInfo?.let {
presenter.deepLink(it) presenter.deepLink(it)
}.ifNull { }.ifNull {
val url = text_server_url.textContent.ifEmpty(text_server_url.hintContent) val url = text_server_url.textContent.ifEmpty(text_server_url.hintContent)
presenter.connect(text_server_protocol.textContent + url) presenter.connect("${protocol}${url.sanitize()}")
} }
} }
} }
...@@ -149,7 +194,7 @@ class ServerFragment : Fragment(), ServerView { ...@@ -149,7 +194,7 @@ class ServerFragment : Fragment(), ServerView {
ui { ui {
button_connect.setOnClickListener { button_connect.setOnClickListener {
val url = text_server_url.textContent.ifEmpty(text_server_url.hintContent) val url = text_server_url.textContent.ifEmpty(text_server_url.hintContent)
presenter.checkServer(text_server_protocol.textContent + url) presenter.checkServer("${protocol}${url.sanitize()}")
} }
} }
} }
......
package chat.rocket.android.chatroom.ui package chat.rocket.android.chatroom.ui
import android.Manifest
import android.app.Activity import android.app.Activity
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.support.annotation.DrawableRes import android.support.annotation.DrawableRes
import android.support.v4.app.ActivityCompat
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.support.v7.widget.DefaultItemAnimator 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
...@@ -476,29 +472,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -476,29 +472,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun showFileSelection(filter: Array<String>) { override fun showFileSelection(filter: Array<String>) {
ui { ui {
if (ContextCompat.checkSelfPermission(it, Manifest.permission.READ_EXTERNAL_STORAGE) val intent = Intent(Intent.ACTION_GET_CONTENT)
!= PackageManager.PERMISSION_GRANTED) { intent.type = "*/*"
ActivityCompat.requestPermissions(it, intent.putExtra(Intent.EXTRA_MIME_TYPES, filter)
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), intent.addCategory(Intent.CATEGORY_OPENABLE)
1) startActivityForResult(intent, REQUEST_CODE_FOR_PERFORM_SAF)
} else {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*"
intent.putExtra(Intent.EXTRA_MIME_TYPES, filter)
startActivityForResult(intent, REQUEST_CODE_FOR_PERFORM_SAF)
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
1 -> {
if (!(grantResults.isNotEmpty() && grantResults.first() == PackageManager.PERMISSION_GRANTED)) {
handler.postDelayed({
ui { hideAttachmentOptions() }
}, 400)
}
}
} }
} }
......
...@@ -111,9 +111,13 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -111,9 +111,13 @@ class ChatRoomsPresenter @Inject constructor(
val chatRoomsCombined = mutableListOf<ChatRoom>() val chatRoomsCombined = mutableListOf<ChatRoom>()
chatRoomsCombined.addAll(usersToChatRooms(users)) chatRoomsCombined.addAll(usersToChatRooms(users))
chatRoomsCombined.addAll(roomsToChatRooms(rooms)) chatRoomsCombined.addAll(roomsToChatRooms(rooms))
view.updateChatRooms(getChatRoomsWithPreviews(chatRoomsCombined.toList())) val chatRoomsWithPreview = getChatRoomsWithPreviews(chatRoomsCombined)
val chatRoomsWithStatus = getChatRoomWithStatus(chatRoomsWithPreview)
view.updateChatRooms(chatRoomsWithStatus)
} else { } else {
view.updateChatRooms(getChatRoomsWithPreviews(roomList)) val chatRoomsWithPreview = getChatRoomsWithPreviews(roomList)
val chatRoomsWithStatus = getChatRoomWithStatus(chatRoomsWithPreview)
view.updateChatRooms(chatRoomsWithStatus)
} }
} catch (ex: RocketChatException) { } catch (ex: RocketChatException) {
Timber.e(ex) Timber.e(ex)
...@@ -121,6 +125,19 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -121,6 +125,19 @@ class ChatRoomsPresenter @Inject constructor(
} }
} }
// In the first time it will not come with the users status, but after called by the
// [reloadRooms] function may be with.
private suspend fun getUserChatRooms(): List<ChatRoom> {
val chatRooms = retryIO("chatRooms") { manager.chatRooms().update }
val chatRoomsWithPreview = getChatRoomsWithPreviews(chatRooms)
val chatRoomsWithUserStatus = getChatRoomWithStatus(chatRoomsWithPreview)
val sortedRooms = sortRooms(chatRoomsWithUserStatus)
Timber.d("Loaded rooms: ${sortedRooms.size}")
saveChatRoomsInteractor.save(currentServer, sortedRooms)
return sortedRooms
}
private fun usersToChatRooms(users: List<User>): List<ChatRoom> { private fun usersToChatRooms(users: List<User>): List<ChatRoom> {
return users.map { return users.map {
ChatRoom( ChatRoom(
...@@ -187,17 +204,7 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -187,17 +204,7 @@ class ChatRoomsPresenter @Inject constructor(
} }
} }
private suspend fun getUserChatRooms(): List<ChatRoom> {
val chatRooms = retryIO("chatRooms") { manager.chatRooms().update }
val sortedRooms = sortRooms(chatRooms)
Timber.d("Loaded rooms: ${sortedRooms.size}")
saveChatRoomsInteractor.save(currentServer, sortedRooms)
val chatRoomsWithPreview = getChatRoomsWithPreviews(sortedRooms)
return getChatRoomWithStatus(chatRoomsWithPreview)
}
fun updateSortedChatRooms() { fun updateSortedChatRooms() {
val currentServer = serverInteractor.get()!!
launchUI(strategy) { launchUI(strategy) {
val roomList = getChatRoomsInteractor.getAll(currentServer) val roomList = getChatRoomsInteractor.getAll(currentServer)
view.updateChatRooms(sortRooms(roomList)) view.updateChatRooms(sortRooms(roomList))
...@@ -501,6 +508,7 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -501,6 +508,7 @@ class ChatRoomsPresenter @Inject constructor(
} }
private fun updateChatRoomWithUserStatus(user_: User) { private fun updateChatRoomWithUserStatus(user_: User) {
Timber.d("active User: $user_")
val username = user_.username val username = user_.username
val status = user_.status val status = user_.status
if (username != null && status != null) { if (username != null && status != null) {
...@@ -542,10 +550,11 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -542,10 +550,11 @@ class ChatRoomsPresenter @Inject constructor(
private fun updateChatRooms() { private fun updateChatRooms() {
Timber.i("Updating ChatRooms") Timber.i("Updating ChatRooms")
launch(strategy.jobs) { launch(strategy.jobs) {
val chatRooms = getChatRoomsWithPreviews( val chatRoomsWithPreview = getChatRoomsWithPreviews(
getChatRoomsInteractor.getAll(currentServer) getChatRoomsInteractor.getAll(currentServer)
) )
view.updateChatRooms(chatRooms) val chatRoomsWithStatus = getChatRoomWithStatus(chatRoomsWithPreview)
view.updateChatRooms(chatRoomsWithStatus)
} }
} }
......
...@@ -32,12 +32,9 @@ import dagger.android.support.AndroidSupportInjection ...@@ -32,12 +32,9 @@ 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.Job import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.NonCancellable.isActive import kotlinx.coroutines.experimental.NonCancellable.isActive
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class ChatRoomsFragment : Fragment(), ChatRoomsView { class ChatRoomsFragment : Fragment(), ChatRoomsView {
@Inject lateinit var presenter: ChatRoomsPresenter @Inject lateinit var presenter: ChatRoomsPresenter
@Inject lateinit var serverInteractor: GetCurrentServerInteractor @Inject lateinit var serverInteractor: GetCurrentServerInteractor
...@@ -67,7 +64,11 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -67,7 +64,11 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
super.onDestroy() super.onDestroy()
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = container?.inflate(R.layout.fragment_chat_rooms) override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = container?.inflate(R.layout.fragment_chat_rooms)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
...@@ -100,7 +101,6 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -100,7 +101,6 @@ 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 -> {
......
...@@ -3,7 +3,12 @@ package chat.rocket.android.server.infraestructure ...@@ -3,7 +3,12 @@ package chat.rocket.android.server.infraestructure
import chat.rocket.common.model.BaseRoom import chat.rocket.common.model.BaseRoom
import chat.rocket.common.model.User import chat.rocket.common.model.User
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.realtime.* import chat.rocket.core.internal.realtime.subscribeSubscriptions
import chat.rocket.core.internal.realtime.subscribeRooms
import chat.rocket.core.internal.realtime.subscribeUserData
import chat.rocket.core.internal.realtime.subscribeActiveUsers
import chat.rocket.core.internal.realtime.subscribeRoomMessages
import chat.rocket.core.internal.realtime.unsubscribe
import chat.rocket.core.internal.realtime.socket.connect import chat.rocket.core.internal.realtime.socket.connect
import chat.rocket.core.internal.realtime.socket.disconnect import chat.rocket.core.internal.realtime.socket.disconnect
import chat.rocket.core.internal.realtime.socket.model.State import chat.rocket.core.internal.realtime.socket.model.State
......
...@@ -7,6 +7,7 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory ...@@ -7,6 +7,7 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.VersionInfo import chat.rocket.android.util.VersionInfo
import chat.rocket.android.util.extensions.launchUI import chat.rocket.android.util.extensions.launchUI
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatInvalidProtocolException
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.serverInfo import chat.rocket.core.internal.rest.serverInfo
import kotlinx.coroutines.experimental.Deferred import kotlinx.coroutines.experimental.Deferred
...@@ -42,6 +43,14 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra ...@@ -42,6 +43,14 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra
} }
} catch (ex: Exception) { } catch (ex: Exception) {
Timber.d(ex, "Error getting server info") Timber.d(ex, "Error getting server info")
when(ex) {
is RocketChatInvalidProtocolException -> {
view.errorInvalidProtocol()
}
else -> {
view.errorCheckingServerVersion()
}
}
} }
} }
} }
......
...@@ -4,12 +4,17 @@ import android.util.Patterns ...@@ -4,12 +4,17 @@ import android.util.Patterns
fun String.removeTrailingSlash(): String { fun String.removeTrailingSlash(): String {
return if (isNotEmpty() && this[length - 1] == '/') { return if (isNotEmpty() && this[length - 1] == '/') {
this.replace("/+$", "") this.substring(0, length - 1)
} else { } else {
this this
} }
} }
fun String.sanitize(): String {
val tmp = this.trim()
return tmp.removeTrailingSlash()
}
fun String.avatarUrl(avatar: String, isGroupOrChannel: Boolean = false, format: String = "jpeg"): String { fun String.avatarUrl(avatar: String, isGroupOrChannel: Boolean = false, format: String = "jpeg"): String {
return if (isGroupOrChannel) { return if (isGroupOrChannel) {
"${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format" "${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format"
......
...@@ -30,7 +30,7 @@ private const val JSON_CREDENTIAL_SECRET = "credentialSecret" ...@@ -30,7 +30,7 @@ private const val JSON_CREDENTIAL_SECRET = "credentialSecret"
const val INTENT_OAUTH_CREDENTIAL_TOKEN = "credential_token" const val INTENT_OAUTH_CREDENTIAL_TOKEN = "credential_token"
const val INTENT_OAUTH_CREDENTIAL_SECRET = "credential_secret" const val INTENT_OAUTH_CREDENTIAL_SECRET = "credential_secret"
// Shows a WebView to the user authenticate with your Gitlab credentials. // Shows a WebView to the user authenticate with its OAuth credential.
class OauthWebViewActivity : AppCompatActivity() { class OauthWebViewActivity : AppCompatActivity() {
private lateinit var webPageUrl: String private lateinit var webPageUrl: String
private lateinit var state: String private lateinit var state: String
......
...@@ -18,24 +18,30 @@ ...@@ -18,24 +18,30 @@
android:id="@+id/text_server_url" android:id="@+id/text_server_url"
style="@style/Authentication.EditText" style="@style/Authentication.EditText"
android:layout_below="@id/text_headline" android:layout_below="@id/text_headline"
android:layout_marginStart="-4dp" android:layout_marginStart="-6dp"
android:layout_marginTop="32dp" android:layout_marginTop="32dp"
android:layout_toEndOf="@id/text_server_protocol" android:layout_toEndOf="@id/protocol_container"
android:cursorVisible="false" android:cursorVisible="false"
android:hint="@string/default_server" android:hint="@string/default_server"
android:imeOptions="actionDone" android:imeOptions="actionDone"
android:digits="0123456789abcdefghijklmnopqrstuvwxyz.-/:" android:inputType="text|textUri"
android:inputType="textUri" android:paddingEnd="0dp" />
android:paddingEnd="0dp"
android:paddingStart="4dp" />
<TextView <FrameLayout
android:id="@+id/text_server_protocol" android:id="@+id/protocol_container"
style="@style/Authentication.TextView" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/style_edit_text_authentication"
android:layout_marginStart="@dimen/screen_edge_left_and_right_margins"
android:layout_below="@id/text_headline" android:layout_below="@id/text_headline"
android:layout_marginTop="32dp" android:layout_marginTop="32dp">
android:gravity="center_vertical" <Spinner
android:text="@string/default_protocol" /> android:id="@+id/text_server_protocol"
android:spinnerMode="dropdown"
android:layout_width="120dp"
android:layout_height="50dp"
android:backgroundTint="@color/actionMenuColor" />
</FrameLayout>
<com.wang.avi.AVLoadingIndicatorView <com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading" android:id="@+id/view_loading"
......
...@@ -15,37 +15,28 @@ ...@@ -15,37 +15,28 @@
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
app:layout_constraintEnd_toStartOf="@+id/top_container"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:roundedCornerRadius="3dp" /> app:roundedCornerRadius="3dp" />
<LinearLayout <ImageView
android:id="@+id/top_container" android:id="@+id/image_chat_icon"
android:layout_width="0dp" android:layout_width="12dp"
android:layout_height="wrap_content" android:layout_height="12dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:orientation="horizontal" app:layout_constraintStart_toEndOf="@+id/image_avatar"
app:layout_constraintEnd_toStartOf="@+id/text_last_message_date_time" app:layout_constraintTop_toTopOf="@+id/image_avatar"
app:layout_constraintStart_toEndOf="@+id/image_avatar"> tools:src="@drawable/ic_hashtag_12dp" />
<ImageView <TextView
android:id="@+id/image_chat_icon" android:id="@+id/text_chat_name"
android:layout_width="12dp" style="@style/ChatRoom.Name.TextView"
android:layout_height="12dp" android:layout_width="wrap_content"
android:layout_gravity="center" android:layout_height="wrap_content"
tools:src="@drawable/ic_lock_12_dp" /> android:layout_marginStart="8dp"
android:textDirection="locale"
<TextView app:layout_constraintStart_toEndOf="@+id/image_chat_icon"
android:id="@+id/text_chat_name" tools:text="general" />
style="@style/ChatRoom.Name.TextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_marginStart="8dp"
android:textDirection="locale"
tools:text="A very very very very big chat room name" />
</LinearLayout>
<TextView <TextView
android:id="@+id/text_last_message_date_time" android:id="@+id/text_last_message_date_time"
...@@ -53,10 +44,9 @@ ...@@ -53,10 +44,9 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
app:layout_constraintBottom_toBottomOf="@+id/top_container" app:layout_constraintBottom_toBottomOf="@+id/text_chat_name"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/top_container" app:layout_constraintTop_toTopOf="@+id/text_chat_name"
app:layout_constraintTop_toTopOf="@+id/top_container"
tools:text="11:45 AM" /> tools:text="11:45 AM" />
<TextView <TextView
...@@ -69,8 +59,8 @@ ...@@ -69,8 +59,8 @@
android:maxLines="2" android:maxLines="2"
android:textDirection="locale" android:textDirection="locale"
app:layout_constraintEnd_toStartOf="@+id/layout_unread_messages_badge" app:layout_constraintEnd_toStartOf="@+id/layout_unread_messages_badge"
app:layout_constraintStart_toStartOf="@+id/top_container" app:layout_constraintStart_toStartOf="@+id/image_chat_icon"
app:layout_constraintTop_toBottomOf="@+id/top_container" app:layout_constraintTop_toBottomOf="@+id/text_chat_name"
tools:text="Filipe de Lima Brito: Type something that is very big and need at least to lines, or maybe even more" /> tools:text="Filipe de Lima Brito: Type something that is very big and need at least to lines, or maybe even more" />
<include <include
......
...@@ -80,6 +80,8 @@ ...@@ -80,6 +80,8 @@
<string name="msg_preview_photo">तस्वीरें</string> <string name="msg_preview_photo">तस्वीरें</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_version">वर्शन</string>
<string name="msg_build">बिल्ड</string>
<string name="msg_ok">OK</string> <string name="msg_ok">OK</string>
<string name="msg_ver_not_recommended"> <string name="msg_ver_not_recommended">
ऐसा लगता है कि आपका सर्वर संस्करण अनुशंसित संस्करण %1$s के नीचे है।\nआप अभी भी लॉगिन कर सकते हैं लेकिन आप अप्रत्याशित व्यवहार का अनुभव कर सकते हैं ऐसा लगता है कि आपका सर्वर संस्करण अनुशंसित संस्करण %1$s के नीचे है।\nआप अभी भी लॉगिन कर सकते हैं लेकिन आप अप्रत्याशित व्यवहार का अनुभव कर सकते हैं
...@@ -87,8 +89,12 @@ ...@@ -87,8 +89,12 @@
<string name="msg_ver_not_minimum"> <string name="msg_ver_not_minimum">
ऐसा लगता है कि आपका सर्वर संस्करण न्यूनतम आवश्यक संस्करण %1$s से कम है।\nकृपया लॉगिन करने के लिए अपने सर्वर को अपग्रेड करें! ऐसा लगता है कि आपका सर्वर संस्करण न्यूनतम आवश्यक संस्करण %1$s से कम है।\nकृपया लॉगिन करने के लिए अपने सर्वर को अपग्रेड करें!
</string> </string>
<string name="msg_version">वर्शन %1$s</string> <string name="msg_proceed">आगे बढ़ें</string>
<string name="msg_build">बिल्ड %1$d</string> <string name="msg_cancel">रद्द करना</string>
<string name="msg_warning">चेतावनी</string>
<string name="msg_http_insecure">HTTP का उपयोग करते समय, आप एक असुरक्षित सर्वर से कनेक्ट हो रहे हैं। हम आपको ऐसा करने की सलाह नहीं देते हैं।</string>
<string name="msg_error_checking_server_version">आपके सर्वर संस्करण की जांच करते समय एक त्रुटि आई है, कृपया पुनः प्रयास करें</string>
<string name="msg_invalid_server_protocol">चयनित प्रोटोकॉल इस सर्वर द्वारा स्वीकार नहीं किया गया है, HTTPS का उपयोग करने का प्रयास करें</string>
<!-- System messages --> <!-- System messages -->
<string name="message_room_name_changed">%2$s ने रूम का नाम बदलकर %1$s किया</string> <string name="message_room_name_changed">%2$s ने रूम का नाम बदलकर %1$s किया</string>
...@@ -187,4 +193,4 @@ ...@@ -187,4 +193,4 @@
<string name="notif_action_reply_hint">जवाब</string> <string name="notif_action_reply_hint">जवाब</string>
<string name="notif_error_sending">उत्तर विफल हुआ है। कृपया फिर से प्रयास करें।</string> <string name="notif_error_sending">उत्तर विफल हुआ है। कृपया फिर से प्रयास करें।</string>
<string name="notif_success_sending">संदेश भेजा गया %1$s!</string> <string name="notif_success_sending">संदेश भेजा गया %1$s!</string>
</resources> </resources>
\ No newline at end of file
...@@ -89,6 +89,12 @@ ...@@ -89,6 +89,12 @@
<string name="msg_ver_not_minimum"> <string name="msg_ver_not_minimum">
Parece que a versão do seu servidor está abaixo da mínima requerida %1$s.\nPor favor, atualize seus servidores antes de continuar! Parece que a versão do seu servidor está abaixo da mínima requerida %1$s.\nPor favor, atualize seus servidores antes de continuar!
</string> </string>
<string name="msg_proceed">CONTINUAR</string>
<string name="msg_cancel">CANCELAR</string>
<string name="msg_warning">AVISO</string>
<string name="msg_http_insecure">Usando HTTP, você estará conectando a um servidor não seguro, não recomendamos sua utilização.</string>
<string name="msg_error_checking_server_version">Ocorreu um erro verificando a versão do servidor, por favor tente novamente</string>
<string name="msg_invalid_server_protocol">O protocolo selecionado não é suportado pelo servidor, por favor utilize HTTPS e tente novamente</string>
<!-- System messages --> <!-- System messages -->
<string name="message_room_name_changed">Nome da sala alterado para: %1$s por %2$s</string> <string name="message_room_name_changed">Nome da sala alterado para: %1$s por %2$s</string>
...@@ -130,12 +136,12 @@ ...@@ -130,12 +136,12 @@
<string name="max_file_size_exceeded">Tamanho de arquivo (%1$d bytes) excedeu tamanho máximo de upload (%2$d bytes)</string> <string name="max_file_size_exceeded">Tamanho de arquivo (%1$d bytes) excedeu tamanho máximo de upload (%2$d bytes)</string>
<!-- Socket status --> <!-- Socket status -->
<string name="status_connected">conectado</string> <string name="status_connected">Conectado</string>
<string name="status_disconnected">desconetado</string> <string name="status_disconnected">Desconetado</string>
<string name="status_connecting">conectando</string> <string name="status_connecting">Conectando</string>
<string name="status_authenticating">autenticando</string> <string name="status_authenticating">Autenticando</string>
<string name="status_disconnecting">desconectando</string> <string name="status_disconnecting">Desconectando</string>
<string name="status_waiting">conectando em %d segundos</string> <string name="status_waiting">Conectando em %d segundos</string>
<!--Suggestions--> <!--Suggestions-->
<string name="suggest_all_description">Notifica todos nesta sala</string> <string name="suggest_all_description">Notifica todos nesta sala</string>
......
...@@ -90,6 +90,12 @@ ...@@ -90,6 +90,12 @@
<string name="msg_ver_not_minimum"> <string name="msg_ver_not_minimum">
Looks like your server version is below the minimum required version %1$s.\nPlease upgrade your server to login! Looks like your server version is below the minimum required version %1$s.\nPlease upgrade your server to login!
</string> </string>
<string name="msg_proceed">PROCEED</string>
<string name="msg_cancel">CANCEL</string>
<string name="msg_warning">WARNING</string>
<string name="msg_http_insecure">When using HTTP, you\'re connecting to an insecure server. We don\'t recommend you doing that.</string>
<string name="msg_error_checking_server_version">An error has occurred while checking your server version, please try again</string>
<string name="msg_invalid_server_protocol">The selected protocol is not accepted by this server, try using HTTPS</string>
<!-- System messages --> <!-- System messages -->
<string name="message_room_name_changed">Room name changed to: %1$s by %2$s</string> <string name="message_room_name_changed">Room name changed to: %1$s by %2$s</string>
...@@ -131,12 +137,12 @@ ...@@ -131,12 +137,12 @@
<string name="max_file_size_exceeded">File size %1$d bytes exceeded max upload size of %2$d bytes</string> <string name="max_file_size_exceeded">File size %1$d bytes exceeded max upload size of %2$d bytes</string>
<!-- Socket status --> <!-- Socket status -->
<string name="status_connected">connected</string> <string name="status_connected">Connected</string>
<string name="status_disconnected">disconnected</string> <string name="status_disconnected">Disconnected</string>
<string name="status_connecting">connecting</string> <string name="status_connecting">Connecting</string>
<string name="status_authenticating">authenticating</string> <string name="status_authenticating">Authenticating</string>
<string name="status_disconnecting">disconnecting</string> <string name="status_disconnecting">Disconnecting</string>
<string name="status_waiting">connecting in %d seconds</string> <string name="status_waiting">Connecting in %d seconds</string>
<!--Suggestions--> <!--Suggestions-->
<string name="suggest_all_description">Notify all in this room</string> <string name="suggest_all_description">Notify all in this room</string>
......
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