Unverified Commit 2bc41c37 authored by Pancor's avatar Pancor Committed by GitHub

Merge branch 'develop-2.x' into feature/save-unfinished-message

parents b47bd9a7 032a72a0
......@@ -13,8 +13,8 @@ android {
applicationId "chat.rocket.android"
minSdkVersion 21
targetSdkVersion versions.targetSdk
versionCode 2007
versionName "2.0.0-beta5"
versionCode 2008
versionName "2.0.0-beta6"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
......
......@@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<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" />
<permission
......
......@@ -2,7 +2,6 @@ package chat.rocket.android.authentication.login.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.helper.OauthHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.*
......@@ -190,7 +189,6 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
private fun doAuthentication(loginType: Int) {
launchUI(strategy) {
if (NetworkHelper.hasInternetAccess()) {
view.disableUserInput()
view.showLoading()
try {
......@@ -246,9 +244,6 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
view.hideLoading()
view.enableUserInput()
}
} else {
view.showNoInternetConnection()
}
}
}
......
package chat.rocket.android.authentication.login.presentation
import chat.rocket.android.authentication.server.presentation.VersionCheckView
import chat.rocket.android.core.behaviours.InternetView
import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
interface LoginView : LoadingView, MessageView, InternetView, VersionCheckView {
interface LoginView : LoadingView, MessageView, VersionCheckView {
/**
* Shows the form view (i.e the username/email and password fields) if it is enabled by the server settings.
......
......@@ -105,10 +105,6 @@ class LoginFragment : Fragment(), LoginView {
view_loading.setVisible(false)
}
override fun showNoInternetConnection() {
showMessage(R.string.msg_no_internet_connection)
}
override fun showMessage(resId: Int) {
showToast(resId)
}
......
......@@ -2,7 +2,6 @@ package chat.rocket.android.authentication.registerusername.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.*
import chat.rocket.android.server.domain.model.Account
......@@ -40,7 +39,6 @@ class RegisterUsernamePresenter @Inject constructor(
view.alertBlankUsername()
} else {
launchUI(strategy) {
if (NetworkHelper.hasInternetAccess()) {
view.showLoading()
try {
val me = retryIO("updateOwnBasicInformation(username = $username)") {
......@@ -62,9 +60,6 @@ class RegisterUsernamePresenter @Inject constructor(
} finally {
view.hideLoading()
}
} else {
view.showNoInternetConnection()
}
}
}
}
......
package chat.rocket.android.authentication.registerusername.presentation
import chat.rocket.android.core.behaviours.InternetView
import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
interface RegisterUsernameView : LoadingView, MessageView, InternetView {
interface RegisterUsernameView : LoadingView, MessageView {
/**
* Alerts the user about a blank username.
......
......@@ -85,10 +85,6 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
showMessage(getString(R.string.msg_generic_error))
}
override fun showNoInternetConnection() {
showMessage(getString(R.string.msg_no_internet_connection))
}
private fun tintEditTextDrawableStart() {
activity?.apply {
val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_24dp, this)
......
......@@ -2,7 +2,6 @@ package chat.rocket.android.authentication.server.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.domain.SaveCurrentServerInteractor
......@@ -29,7 +28,6 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
return@launchUI
}
if (NetworkHelper.hasInternetAccess()) {
view.showLoading()
try {
refreshSettingsInteractor.refresh(server)
......@@ -44,9 +42,6 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
} finally {
view.hideLoading()
}
} else {
view.showNoInternetConnection()
}
}
}
}
......
package chat.rocket.android.authentication.server.presentation
import chat.rocket.android.core.behaviours.InternetView
import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
interface ServerView : LoadingView, MessageView, InternetView {
interface ServerView : LoadingView, MessageView {
/**
* Shows an invalid server URL message.
......
......@@ -68,10 +68,6 @@ class ServerFragment : Fragment(), ServerView {
showMessage(getString(R.string.msg_generic_error))
}
override fun showNoInternetConnection() {
showMessage(getString(R.string.msg_no_internet_connection))
}
private fun enableUserInput(value: Boolean) {
button_connect.isEnabled = value
text_server_url.isEnabled = value
......
......@@ -2,7 +2,6 @@ package chat.rocket.android.authentication.signup.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.*
import chat.rocket.android.server.domain.model.Account
......@@ -57,9 +56,7 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
else -> {
val client = factory.create(server)
launchUI(strategy) {
if (NetworkHelper.hasInternetAccess()) {
view.showLoading()
try {
// TODO This function returns a user so should we save it?
retryIO("signup") { client.signup(email, name, username, password) }
......@@ -80,9 +77,6 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
view.hideLoading()
}
} else {
view.showNoInternetConnection()
}
}
}
}
......
package chat.rocket.android.authentication.signup.presentation
import chat.rocket.android.core.behaviours.InternetView
import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
interface SignupView : LoadingView, MessageView, InternetView {
interface SignupView : LoadingView, MessageView {
/**
* Alerts the user about a blank name.
......
......@@ -109,10 +109,6 @@ class SignupFragment : Fragment(), SignupView {
showMessage(getString(R.string.msg_generic_error))
}
override fun showNoInternetConnection() {
Toast.makeText(activity, getString(R.string.msg_no_internet_connection), Toast.LENGTH_SHORT).show()
}
private fun tintEditTextDrawableStart() {
activity?.apply {
val personDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_person_black_24dp, this)
......
......@@ -2,7 +2,6 @@ package chat.rocket.android.authentication.twofactor.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.*
import chat.rocket.android.server.domain.model.Account
......@@ -48,7 +47,6 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
else -> {
launchUI(strategy) {
val client = factory.create(server)
if (NetworkHelper.hasInternetAccess()) {
view.showLoading()
try {
// The token is saved via the client TokenProvider
......@@ -73,9 +71,6 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
} finally {
view.hideLoading()
}
} else {
view.showNoInternetConnection()
}
}
}
}
......
package chat.rocket.android.authentication.twofactor.presentation
import chat.rocket.android.core.behaviours.InternetView
import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
interface TwoFAView : LoadingView, MessageView, InternetView {
interface TwoFAView : LoadingView, MessageView {
/**
* Alerts the user about a blank Two Factor Authentication code.
......
......@@ -91,8 +91,6 @@ class TwoFAFragment : Fragment(), TwoFAView {
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
override fun showNoInternetConnection() = showMessage(getString(R.string.msg_no_internet_connection))
private fun tintEditTextDrawableStart() {
activity?.apply {
val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_vpn_key_black_24dp, this)
......
package chat.rocket.android.chatroom.ui
import android.Manifest
import android.app.Activity
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.support.annotation.DrawableRes
import android.support.v4.app.ActivityCompat
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
......@@ -226,10 +230,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private val layoutChangeListener = View.OnLayoutChangeListener { _, _, _, _, bottom, _, _, _, oldBottom ->
val y = oldBottom - bottom
if (y.absoluteValue > 0 && isAdded) {
if (Math.abs(y) > 0 && isAdded) {
// if y is positive the keyboard is up else it's down
recycler_view.post {
if (y > 0 || verticalScrollOffset.get().absoluteValue >= y.absoluteValue) {
if (y > 0 || Math.abs(verticalScrollOffset.get()) >= Math.abs(y)) {
recycler_view.scrollBy(0, y)
} else {
recycler_view.scrollBy(0, verticalScrollOffset.get())
......@@ -437,11 +441,32 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
override fun showFileSelection(filter: Array<String>) {
activity?.let {
if (ContextCompat.checkSelfPermission(it, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(it,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
1)
} 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({
hideAttachmentOptions()
}, 400)
}
}
}
}
override fun showInvalidFileSize(fileSize: Int, maxFileSize: Int) {
showMessage(getString(R.string.max_file_size_exceeded, fileSize, maxFileSize))
......
......@@ -74,14 +74,17 @@ class ChatRoomsAdapter(private val context: Context,
}
private fun bindAvatar(chatRoom: ChatRoom, drawee: SimpleDraweeView) {
val avatarId = if (chatRoom.type is RoomType.DirectMessage) chatRoom.name else "@${chatRoom.name}"
drawee.setImageURI(chatRoom.client.url.avatarUrl(avatarId))
if (chatRoom.type is RoomType.DirectMessage) {
drawee.setImageURI(chatRoom.client.url.avatarUrl(chatRoom.name))
} else {
drawee.setImageURI(chatRoom.client.url.avatarUrl(chatRoom.name, true))
}
}
private fun bindName(chatRoom: ChatRoom, textView: TextView) {
textView.textContent = chatRoom.name
var drawable = when (chatRoom.type) {
val drawable = when (chatRoom.type) {
is RoomType.Channel -> {
DrawableHelper.getDrawableFromId(R.drawable.ic_room_channel, context)
}
......
package chat.rocket.android.core.behaviours
interface InternetView {
fun showNoInternetConnection()
}
\ No newline at end of file
package chat.rocket.android.helper
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.withContext
import java.io.IOException
import java.net.InetSocketAddress
import java.net.Socket
object NetworkHelper {
/**
* Checks whether there is internet access.
*
* The original author of this code is Levit and you can see his answer here: https://stackoverflow.com/a/27312494/4744263
*
* @return true if there is internet access, false otherwise.
*/
suspend fun hasInternetAccess(): Boolean = withContext(CommonPool) {
try {
val socket = Socket()
val inetSocketAddress = InetSocketAddress("8.8.8.8", 53)
socket.connect(inetSocketAddress, 1500)
socket.close()
true
} catch (e: IOException) {
false
}
}
}
\ No newline at end of file
......@@ -25,7 +25,7 @@ class MemberViewModel(private val member: User, private val settings: Map<String
private fun getUserAvatar(): String? {
val username = member.username ?: "?"
return baseUrl?.let {
baseUrl.avatarUrl(username,"png")
baseUrl.avatarUrl(username, format = "png")
}
}
......
......@@ -9,10 +9,11 @@ import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.launch
import timber.log.Timber
import java.util.concurrent.CopyOnWriteArrayList
class ConnectionManager(internal val client: RocketChatClient) {
private val statusChannelList = ArrayList<Channel<State>>()
private val statusChannelList = CopyOnWriteArrayList<Channel<State>>()
private val statusChannel = Channel<State>()
private var connectJob: Job? = null
......
......@@ -10,8 +10,13 @@ fun String.removeTrailingSlash(): String {
}
}
fun String.avatarUrl(avatar: String, format: String = "jpeg") =
fun String.avatarUrl(avatar: String, isGroupOrChannel: Boolean = false, format: String = "jpeg"): String {
return if (isGroupOrChannel) {
"${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format"
} else {
"${removeTrailingSlash()}/avatar/${avatar.removeTrailingSlash()}?format=$format"
}
}
fun String.serverLogoUrl(favicon: String) = "${removeTrailingSlash()}/$favicon"
......
......@@ -9,10 +9,7 @@ import android.provider.DocumentsContract
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.webkit.MimeTypeMap
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
import java.io.*
fun Uri.getFileName(context: Context): String? {
val cursor = context.contentResolver.query(this, null, null, null, null, null)
......@@ -27,16 +24,22 @@ fun Uri.getFileName(context: Context): String? {
}
fun Uri.getFileSize(context: Context): Int {
val cursor = context.contentResolver.query(this, null, null, null, null, null)
val fileSize = cursor?.use {
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
if (cursor.moveToFirst()) {
if (!cursor.isNull(sizeIndex)) {
return@use cursor.getString(sizeIndex)
var fileSize: String? = null
if (scheme == ContentResolver.SCHEME_CONTENT) {
try {
val fileInputStream = context.contentResolver.openInputStream(this)
fileSize = fileInputStream.available().toString()
} catch (e: Exception) {
e.printStackTrace()
}
} else if (scheme == ContentResolver.SCHEME_FILE) {
val path = this.path
try {
val f = File(path)
fileSize = f.length().toString()
} catch (e: Exception) {
e.printStackTrace()
}
return@use null
}
return fileSize?.toIntOrNull() ?: -1
}
......@@ -46,7 +49,11 @@ fun Uri.getMimeType(context: Context): String {
context.contentResolver.getType(this)
} else {
val fileExtension = MimeTypeMap.getFileExtensionFromUrl(toString())
if (fileExtension != null) {
MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension.toLowerCase())
} else {
"application/octet-stream"
}
}
}
......
......@@ -10,45 +10,52 @@
android:id="@+id/text_online"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:paddingBottom="8dp"
android:paddingEnd="16dp"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:drawablePadding="10dp"
android:drawableStart="@drawable/ic_status_online_24dp"
android:text="@string/action_online" />
android:text="@string/action_online"
android:background="?selectableItemBackground"/>
<TextView
android:id="@+id/text_away"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:paddingBottom="8dp"
android:paddingEnd="16dp"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:drawablePadding="10dp"
android:drawableStart="@drawable/ic_status_away_24dp"
android:text="@string/action_away" />
android:text="@string/action_away"
android:background="?selectableItemBackground"/>
<TextView
android:id="@+id/text_busy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:paddingBottom="8dp"
android:paddingEnd="16dp"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:drawablePadding="10dp"
android:drawableStart="@drawable/ic_status_busy_24dp"
android:text="@string/action_busy" />
android:text="@string/action_busy"
android:background="?selectableItemBackground"/>
<TextView
android:id="@+id/text_invisible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:paddingBottom="8dp"
android:paddingEnd="16dp"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:drawablePadding="10dp"
android:drawableStart="@drawable/ic_status_invisible_24dp"
android:text="@string/action_invisible" />
android:text="@string/action_invisible"
android:background="?selectableItemBackground"/>
</LinearLayout>
\ No newline at end of file
......@@ -41,7 +41,6 @@
</string-array>
<!-- Regular information messages -->
<string name="msg_no_internet_connection">कोई इंटरनेट कनेक्शन नहीं है</string>
<string name="msg_generic_error">क्षमा करें, एक त्रुटि हुई है, कृपया पुनः प्रयास करें</string>
<string name="msg_no_data_to_display">डेटा प्रदर्शित करने के लिए उपलब्ध नहीं हैं</string>
<string name="msg_profile_update_successfully">प्रोफ़ाइल सफलतापूर्वक अपडेट हो गया है</string>
......
......@@ -41,7 +41,6 @@
</string-array>
<!-- Regular information messages -->
<string name="msg_no_internet_connection">Sem conexão à internet</string>
<string name="msg_generic_error">Desculpe, ocorreu um erro, tente novamente</string>
<string name="msg_no_data_to_display">Nenhum dado para exibir</string>
<string name="msg_profile_update_successfully">Perfil atualizado com sucesso</string>
......
......@@ -42,7 +42,6 @@
</string-array>
<!-- Regular information messages -->
<string name="msg_no_internet_connection">No internet connection</string>
<string name="msg_generic_error">Sorry, an error has occurred, please try again</string>
<string name="msg_no_data_to_display">No data to display</string>
<string name="msg_profile_update_successfully">Profile update successfully</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