Unverified Commit 4d3e1402 authored by Lucio Maciel's avatar Lucio Maciel Committed by GitHub

Merge pull request #1527 from RocketChat/new/update-avatar-by-photo

[NEW] Upload/reset avatar.
parents 2358e213 c412154b
...@@ -330,7 +330,7 @@ class DatabaseManager(val context: Application, ...@@ -330,7 +330,7 @@ class DatabaseManager(val context: Application,
id = room.id, id = room.id,
subscriptionId = subscription.id, subscriptionId = subscription.id,
type = room.type.toString(), type = room.type.toString(),
name = room.name ?: subscription.name ?: throw NullPointerException(),// this should be filtered on the SDK name = room.name ?: subscription.name ?: throw NullPointerException(), // this should be filtered on the SDK
fullname = subscription.fullName ?: room.fullName, fullname = subscription.fullName ?: room.fullName,
userId = userId, userId = userId,
ownerId = room.user?.id, ownerId = room.user?.id,
......
...@@ -135,7 +135,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -135,7 +135,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
text_user_name.text = userDisplayName text_user_name.text = userDisplayName
} }
if (userAvatar != null) { if (userAvatar != null) {
image_avatar.setImageURI(userAvatar) setAvatar(userAvatar)
} }
if (serverLogo != null) { if (serverLogo != null) {
server_logo.setImageURI(serverLogo) server_logo.setImageURI(serverLogo)
...@@ -257,6 +257,10 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -257,6 +257,10 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
} }
} }
fun setAvatar(avatarUrl: String) {
headerLayout.image_avatar.setImageURI(avatarUrl)
}
fun getDrawerLayout(): DrawerLayout = drawer_layout fun getDrawerLayout(): DrawerLayout = drawer_layout
fun openDrawer() = drawer_layout.openDrawer(Gravity.START) fun openDrawer() = drawer_layout.openDrawer(Gravity.START)
......
package chat.rocket.android.profile.presentation package chat.rocket.android.profile.presentation
import android.graphics.Bitmap
import android.net.Uri
import chat.rocket.android.chatroom.domain.UriInteractor
import chat.rocket.android.core.behaviours.showMessage import chat.rocket.android.core.behaviours.showMessage
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extension.compressImageAndGetByteArray
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.me import chat.rocket.core.internal.rest.resetAvatar
import chat.rocket.core.internal.rest.setAvatar import chat.rocket.core.internal.rest.setAvatar
import chat.rocket.core.internal.rest.updateProfile import chat.rocket.core.internal.rest.updateProfile
import java.util.*
import javax.inject.Inject import javax.inject.Inject
class ProfilePresenter @Inject constructor( class ProfilePresenter @Inject constructor(
private val view: ProfileView, private val view: ProfileView,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val uriInteractor: UriInteractor,
val userHelper: UserHelper,
serverInteractor: GetCurrentServerInteractor, serverInteractor: GetCurrentServerInteractor,
factory: RocketChatClientFactory factory: RocketChatClientFactory
) { ) {
private val serverUrl = serverInteractor.get()!! private val serverUrl = serverInteractor.get()!!
private val client: RocketChatClient = factory.create(serverUrl) private val client: RocketChatClient = factory.create(serverUrl)
private lateinit var myselfId: String private val myselfId = userHelper.user()?.id ?: ""
private var myselfName = userHelper.user()?.name ?: ""
private var myselfUsername = userHelper.username() ?: ""
private var myselfEmailAddress = userHelper.user()?.emails?.getOrNull(0)?.address ?: ""
fun loadUserProfile() { fun loadUserProfile() {
launchUI(strategy) { launchUI(strategy) {
view.showLoading() view.showLoading()
try { try {
val myself = retryIO("me") { client.me() } view.showProfile(
val id = myself.id serverUrl.avatarUrl(myselfUsername),
val username = myself.username myselfName,
if (id == null || username == null) { myselfUsername,
myselfEmailAddress
)
} catch (exception: RocketChatException) {
view.showMessage(exception)
} finally {
view.hideLoading()
}
}
}
fun updateUserProfile(email: String, name: String, username: String) {
launchUI(strategy) {
view.showLoading()
try {
retryIO { client.updateProfile(myselfId, email, name, username) }
myselfEmailAddress = email
myselfName = name
myselfUsername = username
view.showProfileUpdateSuccessfullyMessage()
loadUserProfile()
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage() view.showGenericErrorMessage()
} else {
myselfId = id
val avatarUrl = serverUrl.avatarUrl(username)
val email = myself.emails?.getOrNull(0)?.address
view.showProfile(
avatarUrl,
myself.name ?: "",
myself.username ?: "",
email
)
} }
} finally {
view.hideLoading()
}
}
}
fun updateAvatar(uri: Uri) {
launchUI(strategy) {
view.showLoading()
try {
retryIO {
client.setAvatar(
uriInteractor.getFileName(uri) ?: uri.toString(),
uriInteractor.getMimeType(uri)
) {
uriInteractor.getInputStream(uri)
}
}
view.reloadUserAvatar(serverUrl.avatarUrl(myselfUsername))
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
view.showMessage(exception) exception.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
} finally { } finally {
view.hideLoading() view.hideLoading()
} }
} }
} }
fun updateUserProfile(email: String, name: String, username: String, avatarUrl: String = "") { fun preparePhotoAndUpdateAvatar(bitmap: Bitmap) {
launchUI(strategy) { launchUI(strategy) {
view.showLoading() view.showLoading()
try { try {
if (avatarUrl != "") { val byteArray = bitmap.compressImageAndGetByteArray("image/png")
retryIO { client.setAvatar(avatarUrl) }
retryIO {
client.setAvatar(
UUID.randomUUID().toString() + ".png",
"image/png"
) {
byteArray?.inputStream()
}
} }
val user = retryIO { view.reloadUserAvatar(serverUrl.avatarUrl(myselfUsername))
client.updateProfile( } catch (exception: RocketChatException) {
userId = myselfId, email = email, name = name, username = username exception.message?.let {
) view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
} }
view.showProfileUpdateSuccessfullyMessage() } finally {
loadUserProfile() view.hideLoading()
}
}
}
fun resetAvatar() {
launchUI(strategy) {
view.showLoading()
try {
retryIO { client.resetAvatar(myselfId) }
view.reloadUserAvatar(serverUrl.avatarUrl(myselfUsername))
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
exception.message?.let { exception.message?.let {
view.showMessage(it) view.showMessage(it)
......
...@@ -15,6 +15,13 @@ interface ProfileView : LoadingView, MessageView { ...@@ -15,6 +15,13 @@ interface ProfileView : LoadingView, MessageView {
*/ */
fun showProfile(avatarUrl: String, name: String, username: String, email: String?) fun showProfile(avatarUrl: String, name: String, username: String, email: String?)
/**
* Reloads the user avatar (after successfully updating it).
*
* @param avatarUrl The user avatar URL.
*/
fun reloadUserAvatar(avatarUrl: String)
/** /**
* Shows a profile update successfully message * Shows a profile update successfully message
*/ */
......
package chat.rocket.android.profile.ui package chat.rocket.android.profile.ui
import DrawableHelper import DrawableHelper
import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.appcompat.view.ActionMode
import android.view.* import android.view.*
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.net.toUri
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.profile.presentation.ProfilePresenter import chat.rocket.android.profile.presentation.ProfilePresenter
import chat.rocket.android.profile.presentation.ProfileView import chat.rocket.android.profile.presentation.ProfileView
import chat.rocket.android.util.extension.asObservable import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.* import chat.rocket.android.util.extension.dispatchImageSelection
import chat.rocket.android.util.extension.dispatchTakePicture
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import com.facebook.drawee.backends.pipeline.Fresco
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable 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.avatar_profile.* import kotlinx.android.synthetic.main.avatar_profile.*
import kotlinx.android.synthetic.main.fragment_profile.* import kotlinx.android.synthetic.main.fragment_profile.*
import kotlinx.android.synthetic.main.update_avatar_options.*
import javax.inject.Inject import javax.inject.Inject
private const val REQUEST_CODE_FOR_PERFORM_SAF = 1
private const val REQUEST_CODE_FOR_PERFORM_CAMERA = 2
class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
@Inject @Inject
lateinit var presenter: ProfilePresenter lateinit var presenter: ProfilePresenter
private lateinit var currentName: String private var currentName = ""
private lateinit var currentUsername: String private var currentUsername = ""
private lateinit var currentEmail: String private var currentEmail = ""
private lateinit var currentAvatar: String
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
private val editTextsDisposable = CompositeDisposable() private val editTextsDisposable = CompositeDisposable()
...@@ -50,11 +63,12 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -50,11 +63,12 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setupToolbar() setupToolbar()
setupListeners()
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
tintEditTextDrawableStart() tintEditTextDrawableStart()
} }
presenter.loadUserProfile() presenter.loadUserProfile()
subscribeEditTexts()
} }
override fun onDestroyView() { override fun onDestroyView() {
...@@ -62,56 +76,61 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -62,56 +76,61 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
unsubscribeEditTexts() unsubscribeEditTexts()
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (resultData != null && resultCode == Activity.RESULT_OK) {
if (requestCode == REQUEST_CODE_FOR_PERFORM_SAF) {
presenter.updateAvatar(resultData.data)
} else if (requestCode == REQUEST_CODE_FOR_PERFORM_CAMERA) {
presenter.preparePhotoAndUpdateAvatar(resultData.extras["data"] as Bitmap)
}
}
}
override fun showProfile(avatarUrl: String, name: String, username: String, email: String?) { override fun showProfile(avatarUrl: String, name: String, username: String, email: String?) {
ui { ui {
image_avatar.setImageURI(avatarUrl) image_avatar.setImageURI(avatarUrl)
text_name.textContent = name text_name.textContent = name
text_username.textContent = username text_username.textContent = username
text_email.textContent = email ?: "" text_email.textContent = email ?: ""
text_avatar_url.textContent = ""
currentName = name currentName = name
currentUsername = username currentUsername = username
currentEmail = email ?: "" currentEmail = email ?: ""
currentAvatar = avatarUrl
profile_container.setVisible(true) profile_container.isVisible = true
subscribeEditTexts()
} }
} }
override fun reloadUserAvatar(avatarUrl: String) {
Fresco.getImagePipeline().evictFromCache(avatarUrl.toUri())
image_avatar.setImageURI(avatarUrl)
(activity as MainActivity).setAvatar(avatarUrl)
}
override fun showProfileUpdateSuccessfullyMessage() { override fun showProfileUpdateSuccessfullyMessage() {
showMessage(getString(R.string.msg_profile_update_successfully)) showMessage(getString(R.string.msg_profile_update_successfully))
} }
override fun showLoading() { override fun showLoading() {
enableUserInput(false) enableUserInput(false)
ui { ui { view_loading.isVisible = true }
view_loading.setVisible(true)
}
} }
override fun hideLoading() { override fun hideLoading() {
ui { ui {
if (view_loading != null) { if (view_loading != null) {
view_loading.setVisible(false) view_loading.isVisible = false
} }
} }
enableUserInput(true) enableUserInput(true)
} }
override fun showMessage(resId: Int) { override fun showMessage(resId: Int) {
ui { ui { showToast(resId) }
showToast(resId)
}
} }
override fun showMessage(message: String) { override fun showMessage(message: String) {
ui { ui { showToast(message) }
showToast(message)
}
} }
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error)) override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
...@@ -130,8 +149,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -130,8 +149,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
presenter.updateUserProfile( presenter.updateUserProfile(
text_email.textContent, text_email.textContent,
text_name.textContent, text_name.textContent,
text_username.textContent, text_username.textContent
text_avatar_url.textContent
) )
mode.finish() mode.finish()
true true
...@@ -151,6 +169,37 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -151,6 +169,37 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
getString(R.string.title_profile) getString(R.string.title_profile)
} }
private fun setupListeners() {
image_avatar.setOnClickListener { showUpdateAvatarOptions() }
view_dim.setOnClickListener { hideUpdateAvatarOptions() }
button_open_gallery.setOnClickListener {
dispatchImageSelection(REQUEST_CODE_FOR_PERFORM_SAF)
hideUpdateAvatarOptions()
}
button_take_photo.setOnClickListener {
dispatchTakePicture(REQUEST_CODE_FOR_PERFORM_CAMERA)
hideUpdateAvatarOptions()
}
button_reset_avatar.setOnClickListener {
hideUpdateAvatarOptions()
presenter.resetAvatar()
}
}
private fun showUpdateAvatarOptions() {
view_dim.isVisible = true
layout_update_avatar_options.isVisible = true
}
private fun hideUpdateAvatarOptions() {
layout_update_avatar_options.isVisible = false
view_dim.isVisible = false
}
private fun tintEditTextDrawableStart() { private fun tintEditTextDrawableStart() {
(activity as MainActivity).apply { (activity as MainActivity).apply {
val personDrawable = val personDrawable =
...@@ -158,14 +207,12 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -158,14 +207,12 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_24dp, this) val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_24dp, this)
val emailDrawable = val emailDrawable =
DrawableHelper.getDrawableFromId(R.drawable.ic_email_black_24dp, this) DrawableHelper.getDrawableFromId(R.drawable.ic_email_black_24dp, this)
val linkDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_link_black_24dp, this)
val drawables = arrayOf(personDrawable, atDrawable, emailDrawable, linkDrawable) val drawables = arrayOf(personDrawable, atDrawable, emailDrawable)
DrawableHelper.wrapDrawables(drawables) DrawableHelper.wrapDrawables(drawables)
DrawableHelper.tintDrawables(drawables, this, R.color.colorDrawableTintGrey) DrawableHelper.tintDrawables(drawables, this, R.color.colorDrawableTintGrey)
DrawableHelper.compoundDrawables( DrawableHelper.compoundDrawables(
arrayOf(text_name, text_username, text_email, text_avatar_url), arrayOf(text_name, text_username, text_email), drawables
drawables
) )
} }
} }
...@@ -174,13 +221,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -174,13 +221,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
editTextsDisposable.add(Observables.combineLatest( editTextsDisposable.add(Observables.combineLatest(
text_name.asObservable(), text_name.asObservable(),
text_username.asObservable(), text_username.asObservable(),
text_email.asObservable(), text_email.asObservable()
text_avatar_url.asObservable() ) { text_name, text_username, text_email ->
) { text_name, text_username, text_email, text_avatar_url ->
return@combineLatest (text_name.toString() != currentName || return@combineLatest (text_name.toString() != currentName ||
text_username.toString() != currentUsername || text_username.toString() != currentUsername ||
text_email.toString() != currentEmail || text_email.toString() != currentEmail)
(text_avatar_url.toString() != "" && text_avatar_url.toString() != currentAvatar))
}.subscribe { isValid -> }.subscribe { isValid ->
if (isValid) { if (isValid) {
startActionMode() startActionMode()
...@@ -190,9 +235,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -190,9 +235,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}) })
} }
private fun unsubscribeEditTexts() { private fun unsubscribeEditTexts() = editTextsDisposable.clear()
editTextsDisposable.clear()
}
private fun startActionMode() { private fun startActionMode() {
if (actionMode == null) { if (actionMode == null) {
...@@ -207,7 +250,6 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -207,7 +250,6 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
text_username.isEnabled = value text_username.isEnabled = value
text_username.isEnabled = value text_username.isEnabled = value
text_email.isEnabled = value text_email.isEnabled = value
text_avatar_url.isEnabled = value
} }
} }
} }
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M3.9,12c0,-1.71 1.39,-3.1 3.1,-3.1h4L11,7L7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h4v-1.9L7,15.1c-1.71,0 -3.1,-1.39 -3.1,-3.1zM8,13h8v-2L8,11v2zM17,7h-4v1.9h4c1.71,0 3.1,1.39 3.1,3.1s-1.39,3.1 -3.1,3.1h-4L13,17h4c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" />
<path
android:fillColor="#FF000000"
android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z" />
</vector>
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingBottom="16dp" android:paddingBottom="16dp"
app:layout_behavior=" com.google.android.material.bottomsheet.BottomSheetBehavior"> app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image_bottom_sheet_avatar" android:id="@+id/image_bottom_sheet_avatar"
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/relative_layout"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/relative_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:focusableInTouchMode="true" android:focusableInTouchMode="true"
...@@ -48,20 +48,11 @@ ...@@ -48,20 +48,11 @@
android:id="@+id/text_email" android:id="@+id/text_email"
style="@style/Profile.EditText" style="@style/Profile.EditText"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:drawableStart="@drawable/ic_email_black_24dp" android:drawableStart="@drawable/ic_email_black_24dp"
android:hint="@string/msg_email" android:hint="@string/msg_email"
android:inputType="textEmailAddress" /> android:inputType="textEmailAddress" />
<EditText
android:id="@+id/text_avatar_url"
style="@style/Profile.EditText"
android:layout_marginTop="16dp"
android:drawableStart="@drawable/ic_link_black_24dp"
android:hint="@string/msg_avatar_url"
android:inputType="text"
android:layout_marginBottom="16dp"/>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>
<com.wang.avi.AVLoadingIndicatorView <com.wang.avi.AVLoadingIndicatorView
...@@ -72,4 +63,19 @@ ...@@ -72,4 +63,19 @@
app:indicatorColor="@color/colorBlack" app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator" /> app:indicatorName="BallPulseIndicator" />
<View
android:id="@+id/view_dim"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorDim"
android:visibility="gone" />
<include
android:id="@+id/layout_update_avatar_options"
layout="@layout/update_avatar_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="gone" />
</RelativeLayout> </RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/style_attachment_options"
android:orientation="vertical">
<Button
android:id="@+id/button_open_gallery"
style="?android:attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_image_black_24dp"
android:drawablePadding="20dp"
android:gravity="start|center"
android:text="@string/action_select_photo_from_gallery" />
<Button
android:id="@+id/button_take_photo"
style="?android:attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_photo_camera_black_24dp"
android:drawablePadding="20dp"
android:gravity="start|center"
android:text="@string/action_take_photo" />
<Button
android:id="@+id/button_reset_avatar"
style="?android:attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_close_black_24dp"
android:drawablePadding="20dp"
android:gravity="start|center"
android:text="@string/action_reset_avatar" />
</LinearLayout>
\ No newline at end of file
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
<string name="action_invisible">Unsichtbar</string> <string name="action_invisible">Unsichtbar</string>
<string name="action_drawing">Zeichnung</string> <string name="action_drawing">Zeichnung</string>
<string name="action_save_to_gallery">Sichern in Gallerie</string> <string name="action_save_to_gallery">Sichern in Gallerie</string>
<string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_reset_avatar">Reset avatar</string> <!-- TODO Add translation -->
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
...@@ -78,6 +81,7 @@ ...@@ -78,6 +81,7 @@
<string name="msg_content_description_log_in_using_meteor">Login mit Meteor</string> <string name="msg_content_description_log_in_using_meteor">Login mit Meteor</string>
<string name="msg_content_description_log_in_using_twitter">Login mit Twitter</string> <string name="msg_content_description_log_in_using_twitter">Login mit Twitter</string>
<string name="msg_content_description_log_in_using_gitlab">Login mit Gitlab</string> <string name="msg_content_description_log_in_using_gitlab">Login mit Gitlab</string>
<string name="msg_content_description_log_in_using_wordprees">Login using WordPress</string> <!-- TODO Translate-->
<string name="msg_content_description_send_message">Sende Nachricht</string> <string name="msg_content_description_send_message">Sende Nachricht</string>
<string name="msg_content_description_show_attachment_options">Zeige Anhang Optionen</string> <string name="msg_content_description_show_attachment_options">Zeige Anhang Optionen</string>
<string name="msg_you">Du</string> <string name="msg_you">Du</string>
......
...@@ -36,8 +36,11 @@ ...@@ -36,8 +36,11 @@
<string name="action_away">Ausente</string> <string name="action_away">Ausente</string>
<string name="action_busy">Ocupado</string> <string name="action_busy">Ocupado</string>
<string name="action_invisible">Invisible</string> <string name="action_invisible">Invisible</string>
<string name="action_drawing">dibujo</string> <string name="action_drawing">Dibujo</string>
<string name="action_save_to_gallery">Guardar en la galería</string> <string name="action_save_to_gallery">Guardar en la galería</string>
<string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_reset_avatar">Reset avatar</string> <!-- TODO Add translation -->
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
...@@ -135,7 +138,6 @@ ...@@ -135,7 +138,6 @@
<string name="msg_member_not_found">Miembro no encontrado</string> <string name="msg_member_not_found">Miembro no encontrado</string>
<string name="msg_channel_created_successfully">Canal creado con éxito</string> <string name="msg_channel_created_successfully">Canal creado con éxito</string>
<!-- System messages --> <!-- System messages -->
<string name="message_room_name_changed">Nombre de la sala cambiado para: %1$s por %2$s</string> <string name="message_room_name_changed">Nombre de la sala cambiado para: %1$s por %2$s</string>
<string name="message_user_added_by">Usuario %1$s añadido por %2$s</string> <string name="message_user_added_by">Usuario %1$s añadido por %2$s</string>
......
...@@ -27,8 +27,7 @@ ...@@ -27,8 +27,7 @@
<string name="action_search">Chercher</string> <string name="action_search">Chercher</string>
<string name="action_update">Mettre à jour</string> <string name="action_update">Mettre à jour</string>
<string name="action_settings">Paramètres</string> <string name="action_settings">Paramètres</string>
// TODO: Add proper translation. <string name="action_create_channel">Create channel</string> <!-- TODO Add translation -->
<string name="action_create_channel">Create channel</string>
<string name="action_create">Create</string> <string name="action_create">Create</string>
<string name="action_logout">Se déconnecter</string> <string name="action_logout">Se déconnecter</string>
<string name="action_files">Fichiers</string> <string name="action_files">Fichiers</string>
...@@ -40,8 +39,10 @@ ...@@ -40,8 +39,10 @@
<string name="action_busy">Occupé</string> <string name="action_busy">Occupé</string>
<string name="action_invisible">Invisible</string> <string name="action_invisible">Invisible</string>
<string name="action_drawing">Dessin</string> <string name="action_drawing">Dessin</string>
// TODO: Add proper translation. <string name="action_save_to_gallery">Save to gallery</string> <!-- TODO Add translation -->
<string name="action_save_to_gallery">Save to gallery</string> <string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_reset_avatar">Reset avatar</string> <!-- TODO Add translation -->
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
......
...@@ -39,6 +39,9 @@ ...@@ -39,6 +39,9 @@
<string name="action_invisible">अदृश्य</string> <string name="action_invisible">अदृश्य</string>
<string name="action_save_to_gallery">गैलरी में सहेजें</string> <string name="action_save_to_gallery">गैलरी में सहेजें</string>
<string name="action_drawing">चित्रकारी</string> <string name="action_drawing">चित्रकारी</string>
<string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_reset_avatar">Reset avatar</string> <!-- TODO Add translation -->
<string name="action_share">शेयर</string> <string name="action_share">शेयर</string>
<!-- Settings List --> <!-- Settings List -->
......
...@@ -39,6 +39,9 @@ ...@@ -39,6 +39,9 @@
<string name="action_invisible">Invisível</string> <string name="action_invisible">Invisível</string>
<string name="action_drawing">Desenhando</string> <string name="action_drawing">Desenhando</string>
<string name="action_save_to_gallery">Salvar na galeria</string> <string name="action_save_to_gallery">Salvar na galeria</string>
<string name="action_select_photo_from_gallery">Escolher foto da galeria</string>
<string name="action_take_photo">Tirar foto</string>
<string name="action_reset_avatar">Resetar avatar</string>
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
......
...@@ -39,6 +39,9 @@ ...@@ -39,6 +39,9 @@
<string name="action_invisible">Невидимый</string> <string name="action_invisible">Невидимый</string>
<string name="action_drawing">Рисование</string> <string name="action_drawing">Рисование</string>
<string name="action_save_to_gallery">Сохранить в галерею</string> <string name="action_save_to_gallery">Сохранить в галерею</string>
<string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_reset_avatar">Reset avatar</string> <!-- TODO Add translation -->
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
......
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
<string name="action_invisible">Invisible</string> <string name="action_invisible">Invisible</string>
<string name="action_drawing">Drawing</string> <string name="action_drawing">Drawing</string>
<string name="action_save_to_gallery">Save to gallery</string> <string name="action_save_to_gallery">Save to gallery</string>
<string name="action_select_photo_from_gallery">Select photo from gallery</string>
<string name="action_take_photo">Take photo</string>
<string name="action_reset_avatar">Reset avatar</string>
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
......
package chat.rocket.android.util.extension package chat.rocket.android.util.extension
import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.provider.MediaStore
import androidx.fragment.app.Fragment
import kotlinx.coroutines.experimental.DefaultDispatcher import kotlinx.coroutines.experimental.DefaultDispatcher
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
...@@ -61,4 +64,18 @@ fun String.getCompressFormat(): Bitmap.CompressFormat { ...@@ -61,4 +64,18 @@ fun String.getCompressFormat(): Bitmap.CompressFormat {
this.contains("webp") -> Bitmap.CompressFormat.WEBP this.contains("webp") -> Bitmap.CompressFormat.WEBP
else -> Bitmap.CompressFormat.PNG else -> Bitmap.CompressFormat.PNG
} }
}
fun Fragment.dispatchImageSelection(requestCode: Int) {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
intent.addCategory(Intent.CATEGORY_OPENABLE)
startActivityForResult(intent, requestCode)
}
fun Fragment.dispatchTakePicture(requestCode: Int) {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent.resolveActivity(context?.packageManager) != null) {
startActivityForResult(takePictureIntent, requestCode)
}
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment