Add Avatar: UI
This commit is contained in:
parent
3276da3912
commit
1f9712d8a2
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.app.features.form
|
||||
|
||||
import android.net.Uri
|
||||
import android.widget.ImageView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import com.airbnb.epoxy.EpoxyModelWithHolder
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.ClickListener
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.onClick
|
||||
import im.vector.app.core.glide.GlideApp
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_editable_avatar)
|
||||
abstract class FormEditableAvatarItem : EpoxyModelWithHolder<FormEditableAvatarItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
lateinit var avatarRenderer: AvatarRenderer
|
||||
|
||||
@EpoxyAttribute
|
||||
var enabled: Boolean = true
|
||||
|
||||
@EpoxyAttribute
|
||||
var imageUri: Uri? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var clickListener: ClickListener? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.image.onClick(clickListener?.takeIf { enabled })
|
||||
GlideApp.with(holder.image)
|
||||
.load(imageUri)
|
||||
.apply(RequestOptions.circleCropTransform())
|
||||
.placeholder(R.drawable.bg_accent)
|
||||
.into(holder.image)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val image by bind<ImageView>(R.id.itemEditableAvatarImage)
|
||||
}
|
||||
}
|
@ -17,12 +17,15 @@
|
||||
package im.vector.app.features.roomdirectory.createroom
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
|
||||
sealed class CreateRoomAction : VectorViewModelAction {
|
||||
data class SetAvatar(val image: MultiPickerImageType) : CreateRoomAction()
|
||||
data class SetName(val name: String) : CreateRoomAction()
|
||||
data class SetTopic(val topic: String) : CreateRoomAction()
|
||||
data class SetIsPublic(val isPublic: Boolean) : CreateRoomAction()
|
||||
data class SetIsInRoomDirectory(val isInRoomDirectory: Boolean) : CreateRoomAction()
|
||||
data class SetIsEncrypted(val isEncrypted: Boolean) : CreateRoomAction()
|
||||
|
||||
object Create : CreateRoomAction()
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.discovery.settingsSectionTitleItem
|
||||
import im.vector.app.features.form.formEditTextItem
|
||||
import im.vector.app.features.form.formEditableAvatarItem
|
||||
import im.vector.app.features.form.formSubmitButtonItem
|
||||
import im.vector.app.features.form.formSwitchItem
|
||||
import javax.inject.Inject
|
||||
@ -69,6 +70,12 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin
|
||||
}
|
||||
|
||||
private fun buildForm(viewState: CreateRoomViewState, enableFormElement: Boolean) {
|
||||
formEditableAvatarItem {
|
||||
id("avatar")
|
||||
enabled(enableFormElement)
|
||||
imageUri(viewState.avatar?.contentUri)
|
||||
clickListener { listener?.onAvatarChange() }
|
||||
}
|
||||
settingsSectionTitleItem {
|
||||
id("nameSection")
|
||||
titleResId(R.string.create_room_name_section)
|
||||
@ -149,6 +156,7 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun onAvatarChange()
|
||||
fun onNameChange(newName: String)
|
||||
fun onTopicChange(newTopic: String)
|
||||
fun setIsPublic(isPublic: Boolean)
|
||||
|
@ -23,22 +23,28 @@ import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.features.roomdirectory.RoomDirectorySharedAction
|
||||
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
|
||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
import kotlinx.android.synthetic.main.fragment_create_room.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class CreateRoomFragment @Inject constructor(
|
||||
private val createRoomController: CreateRoomController
|
||||
) : VectorBaseFragment(), CreateRoomController.Listener {
|
||||
) : VectorBaseFragment(),
|
||||
CreateRoomController.Listener,
|
||||
GalleryOrCameraDialogHelper.Listener {
|
||||
|
||||
private lateinit var sharedActionViewModel: RoomDirectorySharedActionViewModel
|
||||
private val viewModel: CreateRoomViewModel by activityViewModel()
|
||||
|
||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this)
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_create_room
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@ -62,6 +68,14 @@ class CreateRoomFragment @Inject constructor(
|
||||
createRoomController.listener = this
|
||||
}
|
||||
|
||||
override fun onAvatarChange() {
|
||||
galleryOrCameraDialogHelper.show()
|
||||
}
|
||||
|
||||
override fun onImageReady(image: MultiPickerImageType) {
|
||||
viewModel.handle(CreateRoomAction.SetAvatar(image))
|
||||
}
|
||||
|
||||
override fun onNameChange(newName: String) {
|
||||
viewModel.handle(CreateRoomAction.SetName(newName))
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr
|
||||
|
||||
override fun handle(action: CreateRoomAction) {
|
||||
when (action) {
|
||||
is CreateRoomAction.SetAvatar -> setAvatar(action)
|
||||
is CreateRoomAction.SetName -> setName(action)
|
||||
is CreateRoomAction.SetTopic -> setTopic(action)
|
||||
is CreateRoomAction.SetIsPublic -> setIsPublic(action)
|
||||
@ -100,6 +101,8 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun setAvatar(action: CreateRoomAction.SetAvatar) = setState { copy(avatar = action.image) }
|
||||
|
||||
private fun setName(action: CreateRoomAction.SetName) = setState { copy(roomName = action.name) }
|
||||
|
||||
private fun setTopic(action: CreateRoomAction.SetTopic) = setState { copy(roomTopic = action.topic) }
|
||||
|
@ -19,8 +19,10 @@ package im.vector.app.features.roomdirectory.createroom
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
|
||||
data class CreateRoomViewState(
|
||||
val avatar: MultiPickerImageType? = null,
|
||||
val roomName: String = "",
|
||||
val roomTopic: String = "",
|
||||
val isPublic: Boolean = false,
|
||||
|
6
vector/src/main/res/drawable/bg_accent.xml
Normal file
6
vector/src/main/res/drawable/bg_accent.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<solid android:color="?colorAccent" />
|
||||
|
||||
</shape>
|
10
vector/src/main/res/drawable/ic_add_image.xml
Normal file
10
vector/src/main/res/drawable/ic_add_image.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="15dp"
|
||||
android:height="10dp"
|
||||
android:viewportWidth="15"
|
||||
android:viewportHeight="10">
|
||||
<path
|
||||
android:pathData="M0.5,2C0.5,0.8954 1.3954,0 2.5,0H12.5C13.6046,0 14.5,0.8954 14.5,2V8C14.5,9.1046 13.6046,10 12.5,10H2.5C1.3954,10 0.5,9.1046 0.5,8V2ZM11.5,5C11.5,7.2091 9.7091,9 7.5,9C5.2909,9 3.5,7.2091 3.5,5C3.5,2.7909 5.2909,1 7.5,1C9.7091,1 11.5,2.7909 11.5,5ZM7.5,7C8.6046,7 9.5,6.1046 9.5,5C9.5,3.8954 8.6046,3 7.5,3C6.3954,3 5.5,3.8954 5.5,5C5.5,6.1046 6.3954,7 7.5,7Z"
|
||||
android:fillColor="#8F97A3"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
10
vector/src/main/res/drawable/ic_avatar_.xml
Normal file
10
vector/src/main/res/drawable/ic_avatar_.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="15dp"
|
||||
android:height="10dp"
|
||||
android:viewportWidth="15"
|
||||
android:viewportHeight="10">
|
||||
<path
|
||||
android:pathData="M0.5,2C0.5,0.8954 1.3954,0 2.5,0H12.5C13.6046,0 14.5,0.8954 14.5,2V8C14.5,9.1046 13.6046,10 12.5,10H2.5C1.3954,10 0.5,9.1046 0.5,8V2ZM11.5,5C11.5,7.2091 9.7091,9 7.5,9C5.2909,9 3.5,7.2091 3.5,5C3.5,2.7909 5.2909,1 7.5,1C9.7091,1 11.5,2.7909 11.5,5ZM7.5,7C8.6046,7 9.5,6.1046 9.5,5C9.5,3.8954 8.6046,3 7.5,3C6.3954,3 5.5,3.8954 5.5,5C5.5,6.1046 6.3954,7 7.5,7Z"
|
||||
android:fillColor="#8F97A3"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
31
vector/src/main/res/layout/item_editable_avatar.xml
Normal file
31
vector/src/main/res/layout/item_editable_avatar.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/memberProfileInfoContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/itemEditableAvatarImage"
|
||||
android:layout_width="112dp"
|
||||
android:layout_height="112dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/itemEditableAvatarPicto"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:background="@drawable/circle"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_add_image"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/itemEditableAvatarImage"
|
||||
app:layout_constraintEnd_toEndOf="@+id/itemEditableAvatarImage" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
x
Reference in New Issue
Block a user