mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 05:31:21 +03:00
Space Create Wizard Flow
This commit is contained in:
parent
6c69a6055d
commit
7d2d7b411e
27 changed files with 481 additions and 68 deletions
|
@ -21,7 +21,7 @@ import org.matrix.android.sdk.api.failure.MatrixError
|
|||
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
|
||||
|
||||
sealed class CreateRoomFailure : Failure.FeatureFailure() {
|
||||
object CreatedWithTimeout : CreateRoomFailure()
|
||||
data class CreatedWithTimeout(val roomID: String) : CreateRoomFailure()
|
||||
data class CreatedWithFederationFailure(val matrixError: MatrixError) : CreateRoomFailure()
|
||||
data class AliasError(val aliasError: RoomAliasError) : CreateRoomFailure()
|
||||
}
|
||||
|
|
|
@ -17,11 +17,17 @@
|
|||
package org.matrix.android.sdk.api.session.space
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
|
||||
interface Space {
|
||||
|
||||
fun asRoom() : Room
|
||||
|
||||
/**
|
||||
* A current snapshot of [RoomSummary] associated with the room
|
||||
*/
|
||||
fun spaceSummary(): SpaceSummary?
|
||||
|
||||
suspend fun addChildren(roomId: String, viaServers: List<String>, order: String?, autoJoin: Boolean = false)
|
||||
|
||||
suspend fun removeRoom(roomId: String)
|
||||
|
|
|
@ -66,8 +66,13 @@ internal class DefaultRoomService @Inject constructor(
|
|||
private val roomChangeMembershipStateDataSource: RoomChangeMembershipStateDataSource
|
||||
) : RoomService {
|
||||
|
||||
override suspend fun createRoom(createRoomParams: CreateRoomParams): String {
|
||||
return createRoomTask.execute(createRoomParams)
|
||||
override fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback<String>): Cancelable {
|
||||
return createRoomTask
|
||||
.configureWith(createRoomParams) {
|
||||
this.callback = callback
|
||||
this.retryCount = 3
|
||||
}
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
override fun getRoom(roomId: String): Room? {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.session.room
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.session.space.Space
|
||||
import org.matrix.android.sdk.internal.session.space.DefaultSpace
|
||||
import org.matrix.android.sdk.internal.session.space.SpaceSummaryDataSource
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface SpaceGetter {
|
||||
fun get(spaceId: String): Space?
|
||||
}
|
||||
|
||||
internal class DefaultSpaceGetter @Inject constructor(
|
||||
private val roomGetter: RoomGetter,
|
||||
private val spaceSummaryDataSource: SpaceSummaryDataSource
|
||||
) : SpaceGetter {
|
||||
|
||||
override fun get(spaceId: String): Space? {
|
||||
return roomGetter.getRoom(spaceId)
|
||||
?.takeIf { it.roomSummary()?.roomType == RoomType.SPACE }
|
||||
?.let { DefaultSpace(it, spaceSummaryDataSource) }
|
||||
}
|
||||
}
|
|
@ -102,7 +102,7 @@ internal class DefaultCreateRoomTask @Inject constructor(
|
|||
.equalTo(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.JOIN.name)
|
||||
}
|
||||
} catch (exception: TimeoutCancellationException) {
|
||||
throw CreateRoomFailure.CreatedWithTimeout
|
||||
throw CreateRoomFailure.CreatedWithTimeout(roomId)
|
||||
}
|
||||
|
||||
Realm.getInstance(realmConfiguration).executeTransactionAsync {
|
||||
|
|
|
@ -73,7 +73,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
|
|||
eventType = eventType,
|
||||
body = body.toSafeJson(eventType)
|
||||
)
|
||||
sendStateTask.execute(params)
|
||||
sendStateTask.executeRetry(params, 3)
|
||||
}
|
||||
|
||||
private fun JsonDict.toSafeJson(eventType: String): JsonDict {
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.session.space
|
||||
|
||||
import io.realm.RealmConfiguration
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
||||
import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.SpaceSummaryEntityFields
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A simple wrapper of create room task that adds waiting for DB entities of spaces
|
||||
*/
|
||||
internal interface CreateSpaceTask : Task<CreateRoomParams, String>
|
||||
|
||||
internal class DefaultCreateSpaceTask @Inject constructor(
|
||||
private val createRoomTask: CreateRoomTask,
|
||||
@SessionDatabase private val realmConfiguration: RealmConfiguration
|
||||
) : CreateSpaceTask {
|
||||
|
||||
override suspend fun execute(params: CreateRoomParams): String {
|
||||
val spaceId = createRoomTask.execute(params)
|
||||
|
||||
try {
|
||||
awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm ->
|
||||
realm.where(SpaceSummaryEntity::class.java)
|
||||
.equalTo(SpaceSummaryEntityFields.SPACE_ID, spaceId)
|
||||
}
|
||||
} catch (exception: TimeoutCancellationException) {
|
||||
throw CreateRoomFailure.CreatedWithTimeout(spaceId)
|
||||
}
|
||||
|
||||
return spaceId
|
||||
}
|
||||
}
|
|
@ -22,15 +22,19 @@ import org.matrix.android.sdk.api.session.events.model.toContent
|
|||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.space.Space
|
||||
import org.matrix.android.sdk.api.session.space.SpaceSummary
|
||||
import org.matrix.android.sdk.api.session.space.model.SpaceChildContent
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
class DefaultSpace(private val room: Room) : Space {
|
||||
internal class DefaultSpace(private val room: Room, private val spaceSummaryDataSource: SpaceSummaryDataSource) : Space {
|
||||
|
||||
override fun asRoom(): Room {
|
||||
return room
|
||||
}
|
||||
|
||||
override fun spaceSummary(): SpaceSummary? {
|
||||
return spaceSummaryDataSource.getSpaceSummary(asRoom().roomId)
|
||||
}
|
||||
|
||||
override suspend fun addChildren(roomId: String, viaServers: List<String>, order: String?, autoJoin: Boolean) {
|
||||
asRoom().sendStateEvent(
|
||||
eventType = EventType.STATE_SPACE_CHILD,
|
||||
|
|
|
@ -22,7 +22,6 @@ import com.zhuinden.monarchy.Monarchy
|
|||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
||||
import org.matrix.android.sdk.api.session.space.CreateSpaceParams
|
||||
|
@ -32,40 +31,33 @@ import org.matrix.android.sdk.api.session.space.SpaceSummary
|
|||
import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.space.model.SpaceChildContent
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.session.room.RoomGetter
|
||||
import org.matrix.android.sdk.internal.session.room.alias.DeleteRoomAliasTask
|
||||
import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask
|
||||
import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource
|
||||
import org.matrix.android.sdk.internal.session.room.membership.joining.JoinRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.SpaceGetter
|
||||
import org.matrix.android.sdk.internal.session.room.membership.leaving.LeaveRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.read.MarkAllRoomsReadTask
|
||||
import org.matrix.android.sdk.internal.session.space.peeking.PeekSpaceTask
|
||||
import org.matrix.android.sdk.internal.session.space.peeking.SpacePeekResult
|
||||
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateBreadcrumbsTask
|
||||
import org.matrix.android.sdk.internal.task.TaskExecutor
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultSpaceService @Inject constructor(
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
private val createRoomTask: CreateRoomTask,
|
||||
private val joinRoomTask: JoinRoomTask,
|
||||
private val createSpaceTask: CreateSpaceTask,
|
||||
// private val joinRoomTask: JoinRoomTask,
|
||||
private val joinSpaceTask: JoinSpaceTask,
|
||||
private val markAllRoomsReadTask: MarkAllRoomsReadTask,
|
||||
private val updateBreadcrumbsTask: UpdateBreadcrumbsTask,
|
||||
private val roomIdByAliasTask: GetRoomIdByAliasTask,
|
||||
private val deleteRoomAliasTask: DeleteRoomAliasTask,
|
||||
private val roomGetter: RoomGetter,
|
||||
private val spaceGetter: SpaceGetter,
|
||||
// private val markAllRoomsReadTask: MarkAllRoomsReadTask,
|
||||
// private val updateBreadcrumbsTask: UpdateBreadcrumbsTask,
|
||||
// private val roomIdByAliasTask: GetRoomIdByAliasTask,
|
||||
// private val deleteRoomAliasTask: DeleteRoomAliasTask,
|
||||
// private val roomGetter: RoomGetter,
|
||||
private val spaceSummaryDataSource: SpaceSummaryDataSource,
|
||||
private val peekSpaceTask: PeekSpaceTask,
|
||||
private val resolveSpaceInfoTask: ResolveSpaceInfoTask,
|
||||
private val leaveRoomTask: LeaveRoomTask,
|
||||
private val roomChangeMembershipStateDataSource: RoomChangeMembershipStateDataSource,
|
||||
private val taskExecutor: TaskExecutor
|
||||
private val leaveRoomTask: LeaveRoomTask
|
||||
// private val roomChangeMembershipStateDataSource: RoomChangeMembershipStateDataSource,
|
||||
// private val taskExecutor: TaskExecutor
|
||||
) : SpaceService {
|
||||
|
||||
override suspend fun createSpace(params: CreateSpaceParams): String {
|
||||
return createRoomTask.execute(params)
|
||||
return createSpaceTask.executeRetry(params, 3)
|
||||
}
|
||||
|
||||
override suspend fun createSpace(name: String, topic: String?, avatarUri: Uri?, isPublic: Boolean): String {
|
||||
|
@ -78,9 +70,7 @@ internal class DefaultSpaceService @Inject constructor(
|
|||
}
|
||||
|
||||
override fun getSpace(spaceId: String): Space? {
|
||||
return roomGetter.getRoom(spaceId)
|
||||
?.takeIf { it.roomSummary()?.roomType == RoomType.SPACE }
|
||||
?.let { DefaultSpace(it) }
|
||||
return spaceGetter.get(spaceId)
|
||||
}
|
||||
|
||||
override fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams): LiveData<List<SpaceSummary>> {
|
||||
|
|
|
@ -20,6 +20,8 @@ import dagger.Binds
|
|||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.session.room.DefaultSpaceGetter
|
||||
import org.matrix.android.sdk.internal.session.room.SpaceGetter
|
||||
import org.matrix.android.sdk.internal.session.space.peeking.DefaultPeekSpaceTask
|
||||
import org.matrix.android.sdk.internal.session.space.peeking.PeekSpaceTask
|
||||
import retrofit2.Retrofit
|
||||
|
@ -45,4 +47,10 @@ internal abstract class SpaceModule {
|
|||
|
||||
@Binds
|
||||
abstract fun bindJoinSpaceTask(task: DefaultJoinSpaceTask): JoinSpaceTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindSpaceGetter(getter: DefaultSpaceGetter): SpaceGetter
|
||||
|
||||
@Binds
|
||||
abstract fun bindCreateSpaceTask(getter: DefaultCreateSpaceTask): CreateSpaceTask
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.form
|
|||
|
||||
import android.text.Editable
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
|
@ -50,6 +51,12 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
|||
@EpoxyAttribute
|
||||
var inputType: Int? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var singleLine: Boolean? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var imeOptions: Int? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var onTextChange: ((String) -> Unit)? = null
|
||||
|
||||
|
@ -69,6 +76,8 @@ abstract class FormEditTextItem : VectorEpoxyModel<FormEditTextItem.Holder>() {
|
|||
holder.textInputEditText.setTextSafe(value)
|
||||
holder.textInputEditText.isEnabled = enabled
|
||||
inputType?.let { holder.textInputEditText.inputType = it }
|
||||
holder.textInputEditText.isSingleLine = singleLine ?: false
|
||||
holder.textInputEditText.imeOptions = imeOptions ?: EditorInfo.IME_ACTION_NONE
|
||||
|
||||
holder.textInputEditText.addTextChangedListener(onTextChangeListener)
|
||||
holder.bottomSeparator.isVisible = showBottomSeparator
|
||||
|
|
|
@ -16,13 +16,16 @@
|
|||
package im.vector.app.features.form
|
||||
|
||||
import android.net.Uri
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import com.airbnb.epoxy.EpoxyModelWithHolder
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.load.MultiTransformation
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.ClickListener
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
|
@ -55,14 +58,25 @@ abstract class FormEditableSquareAvatarItem : EpoxyModelWithHolder<FormEditableS
|
|||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.imageContainer.onClick(clickListener?.takeIf { enabled })
|
||||
if (matrixItem != null) {
|
||||
avatarRenderer?.renderSpace(matrixItem!!, holder.image)
|
||||
} else {
|
||||
when {
|
||||
imageUri != null -> {
|
||||
val corner = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
8f,
|
||||
holder.view.resources.displayMetrics
|
||||
).toInt()
|
||||
GlideApp.with(holder.image)
|
||||
.load(imageUri)
|
||||
.apply(RequestOptions.circleCropTransform())
|
||||
.transform(MultiTransformation(CenterCrop(), RoundedCorners(corner)))
|
||||
.into(holder.image)
|
||||
}
|
||||
matrixItem != null -> {
|
||||
avatarRenderer?.renderSpace(matrixItem!!, holder.image)
|
||||
}
|
||||
else -> {
|
||||
avatarRenderer?.clear(holder.image)
|
||||
}
|
||||
}
|
||||
holder.delete.isVisible = enabled && (imageUri != null || matrixItem?.avatarUrl?.isNotEmpty() == true)
|
||||
holder.delete.onClick(deleteListener?.takeIf { enabled })
|
||||
}
|
||||
|
@ -72,6 +86,7 @@ abstract class FormEditableSquareAvatarItem : EpoxyModelWithHolder<FormEditableS
|
|||
GlideApp.with(holder.image).clear(holder.image)
|
||||
super.unbind(holder)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val imageContainer by bind<View>(R.id.itemEditableAvatarImageContainer)
|
||||
val image by bind<ImageView>(R.id.itemEditableAvatarImage)
|
||||
|
|
|
@ -35,6 +35,10 @@ abstract class HomeSpaceSummaryItem : VectorEpoxyModel<HomeSpaceSummaryItem.Hold
|
|||
@EpoxyAttribute var selected: Boolean = false
|
||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||
|
||||
override fun getViewType(): Int {
|
||||
// mm.. it's reusing the same layout for basic space item
|
||||
return R.id.space_item_home
|
||||
}
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.app.features.home
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
@ -36,6 +37,7 @@ import im.vector.app.core.di.ActiveSessionHolder
|
|||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.replaceFragment
|
||||
import im.vector.app.core.platform.ToolbarConfigurable
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
|
@ -103,6 +105,23 @@ class HomeActivity :
|
|||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||
@Inject lateinit var initSyncStepFormatter: InitSyncStepFormatter
|
||||
|
||||
private val createSpaceResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
val spaceId = activityResult.data?.extras?.getString(SpaceCreationActivity.RESULT_DATA_CREATED_SPACE_ID)
|
||||
val defaultRoomsId = activityResult.data?.extras?.getString(SpaceCreationActivity.RESULT_DATA_DEFAULT_ROOM_ID)
|
||||
views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
|
||||
// Here we want to change current space to the newly created one, and then immediatly open the default room
|
||||
if (spaceId != null) {
|
||||
navigator.switchToSpace(this, spaceId, defaultRoomsId)
|
||||
}
|
||||
|
||||
// Also we should show the share space bottomsheet
|
||||
} else {
|
||||
// viewModel.handle(CrossSigningSettingsAction.ReAuthCancelled)
|
||||
}
|
||||
}
|
||||
|
||||
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
||||
override fun onDrawerStateChanged(newState: Int) {
|
||||
hideKeyboard()
|
||||
|
@ -147,7 +166,7 @@ class HomeActivity :
|
|||
startActivity(SpacePreviewActivity.newIntent(this, sharedAction.spaceId))
|
||||
}
|
||||
is HomeActivitySharedAction.AddSpace -> {
|
||||
startActivity(SpaceCreationActivity.newIntent(this))
|
||||
createSpaceResultLauncher.launch(SpaceCreationActivity.newIntent(this))
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import androidx.core.app.ActivityOptionsCompat
|
|||
import androidx.core.app.TaskStackBuilder
|
||||
import androidx.core.util.Pair
|
||||
import androidx.core.view.ViewCompat
|
||||
import arrow.core.Option
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.error.fatalError
|
||||
|
@ -46,6 +47,7 @@ import im.vector.app.features.crypto.verification.SupportedVerificationMethodsPr
|
|||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||
import im.vector.app.features.debug.DebugMenuActivity
|
||||
import im.vector.app.features.devtools.RoomDevToolActivity
|
||||
import im.vector.app.features.grouplist.SelectedSpaceDataSource
|
||||
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
||||
import im.vector.app.features.home.room.detail.RoomDetailArgs
|
||||
import im.vector.app.features.home.room.detail.search.SearchActivity
|
||||
|
@ -77,6 +79,7 @@ import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryDat
|
|||
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -85,6 +88,7 @@ class DefaultNavigator @Inject constructor(
|
|||
private val sessionHolder: ActiveSessionHolder,
|
||||
private val vectorPreferences: VectorPreferences,
|
||||
private val widgetArgsBuilder: WidgetArgsBuilder,
|
||||
private val selectedSpaceDataSource: SelectedSpaceDataSource,
|
||||
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider
|
||||
) : Navigator {
|
||||
|
||||
|
@ -98,6 +102,23 @@ class DefaultNavigator @Inject constructor(
|
|||
startActivity(context, intent, buildTask)
|
||||
}
|
||||
|
||||
override fun switchToSpace(context: Context, spaceId: String, roomId: String?) {
|
||||
if (sessionHolder.getSafeActiveSession()?.spaceService()?.getSpace(spaceId) == null) {
|
||||
fatalError("Trying to open an unknown space $spaceId", vectorPreferences.failFast())
|
||||
return
|
||||
}
|
||||
|
||||
sessionHolder.getSafeActiveSession()?.spaceService()?.getSpace(spaceId)?.spaceSummary()?.let {
|
||||
Timber.d("## Nav: Switching to space $spaceId / ${it.roomSummary.name}")
|
||||
selectedSpaceDataSource.post(Option.just(it))
|
||||
} ?: kotlin.run {
|
||||
Timber.d("## Nav: Failed to switch to space $spaceId")
|
||||
}
|
||||
if (roomId != null) {
|
||||
openRoom(context, roomId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun performDeviceVerification(context: Context, otherUserId: String, sasTransactionId: String) {
|
||||
val session = sessionHolder.getSafeActiveSession() ?: return
|
||||
val tx = session.cryptoService().verificationService().getExistingTransaction(otherUserId, sasTransactionId)
|
||||
|
|
|
@ -38,6 +38,8 @@ interface Navigator {
|
|||
|
||||
fun openRoom(context: Context, roomId: String, eventId: String? = null, buildTask: Boolean = false)
|
||||
|
||||
fun switchToSpace(context: Context, spaceId: String, roomId: String?)
|
||||
|
||||
fun performDeviceVerification(context: Context, otherUserId: String, sasTransactionId: String)
|
||||
|
||||
fun requestSessionVerification(context: Context, otherSessionId: String)
|
||||
|
|
|
@ -20,7 +20,9 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
|
@ -91,6 +93,23 @@ class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Fac
|
|||
CreateSpaceEvents.NavigateToAddRooms -> {
|
||||
navigateToFragment(CreateSpaceDefaultRoomsFragment::class.java)
|
||||
}
|
||||
is CreateSpaceEvents.ShowModalError -> {
|
||||
hideWaitingView()
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage(it.errorMessage)
|
||||
.setPositiveButton(getString(R.string.ok), null)
|
||||
.show()
|
||||
}
|
||||
is CreateSpaceEvents.FinishSuccess -> {
|
||||
setResult(RESULT_OK, Intent().apply {
|
||||
putExtra(RESULT_DATA_CREATED_SPACE_ID, it.spaceId)
|
||||
putExtra(RESULT_DATA_DEFAULT_ROOM_ID, it.defaultRoomId)
|
||||
})
|
||||
finish()
|
||||
}
|
||||
CreateSpaceEvents.HideModalLoading -> {
|
||||
hideWaitingView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,9 +140,17 @@ class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Fac
|
|||
} ?: run {
|
||||
setTitle(getString(titleRes))
|
||||
}
|
||||
|
||||
if (state.creationResult is Loading) {
|
||||
showWaitingView(getString(R.string.create_spaces_loading_message))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val RESULT_DATA_CREATED_SPACE_ID = "RESULT_DATA_CREATED_SPACE_ID"
|
||||
const val RESULT_DATA_DEFAULT_ROOM_ID = "RESULT_DATA_DEFAULT_ROOM_ID"
|
||||
|
||||
fun newIntent(context: Context): Intent {
|
||||
return Intent(context, SpaceCreationActivity::class.java).apply {
|
||||
// putExtra(MvRx.KEY_ARG, SpaceDirectoryArgs(spaceId))
|
||||
|
|
|
@ -86,8 +86,15 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||
private var currentGroupId = ""
|
||||
|
||||
init {
|
||||
observeGroupSummaries()
|
||||
observeSpaceSummaries()
|
||||
observeSelectionState()
|
||||
selectedSpaceDataSource.observe().execute {
|
||||
if (this.selectedSpace != it.invoke()?.orNull()) {
|
||||
copy(
|
||||
selectedSpace = it.invoke()?.orNull()
|
||||
)
|
||||
} else this
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeSelectionState() {
|
||||
|
@ -143,8 +150,8 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||
_viewEvents.post(SpaceListViewEvents.AddSpace)
|
||||
}
|
||||
|
||||
private fun observeGroupSummaries() {
|
||||
val roomSummaryQueryParams = roomSummaryQueryParams() {
|
||||
private fun observeSpaceSummaries() {
|
||||
val spaceSummaryQueryParams = roomSummaryQueryParams() {
|
||||
memberships = listOf(Membership.JOIN, Membership.INVITE)
|
||||
displayName = QueryStringValue.IsNotEmpty
|
||||
excludeType = listOf(/**RoomType.MESSAGING,$*/
|
||||
|
@ -171,7 +178,7 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||
},
|
||||
session
|
||||
.rx()
|
||||
.liveSpaceSummaries(roomSummaryQueryParams),
|
||||
.liveSpaceSummaries(spaceSummaryQueryParams),
|
||||
BiFunction { allCommunityGroup, communityGroups ->
|
||||
listOf(allCommunityGroup) + communityGroups
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ class ChooseSpaceTypeFragment @Inject constructor(
|
|||
}))
|
||||
|
||||
views.privateButton.setOnClickListener(DebouncedClickListener({
|
||||
sharedViewModel.handle(CreateSpaceAction.SetRoomType(SpaceType.Private))
|
||||
// sharedViewModel.handle(CreateSpaceAction.SetRoomType(SpaceType.Private))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,10 +46,14 @@ class CreateSpaceDefaultRoomsFragment @Inject constructor(
|
|||
}
|
||||
|
||||
views.nextButton.debouncedClicks {
|
||||
sharedViewModel.handle(CreateSpaceAction.NextFromDetails)
|
||||
sharedViewModel.handle(CreateSpaceAction.NextFromDefaultRooms)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNameChange(index: Int, newName: String) {
|
||||
sharedViewModel.handle(CreateSpaceAction.DefaultRoomNameChanged(index, newName))
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// Epoxy controller listener methods
|
||||
// -----------------------------
|
||||
|
|
|
@ -16,25 +16,32 @@
|
|||
|
||||
package im.vector.app.features.spaces.create
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.databinding.FragmentSpaceCreateGenericEpoxyFormBinding
|
||||
import javax.inject.Inject
|
||||
|
||||
class CreateSpaceDetailsFragment @Inject constructor(
|
||||
private val epoxyController: SpaceDetailEpoxyController
|
||||
) : VectorBaseFragment<FragmentSpaceCreateGenericEpoxyFormBinding>(), SpaceDetailEpoxyController.Listener {
|
||||
private val epoxyController: SpaceDetailEpoxyController,
|
||||
private val colorProvider: ColorProvider
|
||||
) : VectorBaseFragment<FragmentSpaceCreateGenericEpoxyFormBinding>(), SpaceDetailEpoxyController.Listener,
|
||||
GalleryOrCameraDialogHelper.Listener {
|
||||
|
||||
private val sharedViewModel: CreateSpaceViewModel by activityViewModel()
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) =
|
||||
FragmentSpaceCreateGenericEpoxyFormBinding.inflate(layoutInflater, container, false)
|
||||
|
||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
@ -50,14 +57,19 @@ class CreateSpaceDetailsFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onImageReady(uri: Uri?) {
|
||||
sharedViewModel.handle(CreateSpaceAction.SetAvatar(uri))
|
||||
}
|
||||
// -----------------------------
|
||||
// Epoxy controller listener methods
|
||||
// -----------------------------
|
||||
|
||||
override fun onAvatarDelete() {
|
||||
sharedViewModel.handle(CreateSpaceAction.SetAvatar(null))
|
||||
}
|
||||
|
||||
override fun onAvatarChange() {
|
||||
galleryOrCameraDialogHelper.show()
|
||||
}
|
||||
|
||||
override fun onNameChange(newName: String) {
|
||||
|
|
|
@ -17,20 +17,29 @@
|
|||
package im.vector.app.features.spaces.create
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.ActivityViewModelContext
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
||||
data class CreateSpaceState(
|
||||
|
@ -40,7 +49,8 @@ data class CreateSpaceState(
|
|||
val step: Step = Step.ChooseType,
|
||||
val spaceType: SpaceType? = null,
|
||||
val nameInlineError: String? = null,
|
||||
val defaultRooms: List<String>? = null
|
||||
val defaultRooms: Map<Int, String?>? = null,
|
||||
val creationResult: Async<String> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
||||
enum class Step {
|
||||
|
@ -59,8 +69,11 @@ sealed class CreateSpaceAction : VectorViewModelAction {
|
|||
data class SetRoomType(val type: SpaceType) : CreateSpaceAction()
|
||||
data class NameChanged(val name: String) : CreateSpaceAction()
|
||||
data class TopicChanged(val topic: String) : CreateSpaceAction()
|
||||
data class SetAvatar(val uri: Uri?) : CreateSpaceAction()
|
||||
object OnBackPressed : CreateSpaceAction()
|
||||
object NextFromDetails : CreateSpaceAction()
|
||||
object NextFromDefaultRooms : CreateSpaceAction()
|
||||
data class DefaultRoomNameChanged(val index: Int, val name: String) : CreateSpaceAction()
|
||||
}
|
||||
|
||||
sealed class CreateSpaceEvents : VectorViewEvents {
|
||||
|
@ -68,12 +81,17 @@ sealed class CreateSpaceEvents : VectorViewEvents {
|
|||
object NavigateToChooseType : CreateSpaceEvents()
|
||||
object NavigateToAddRooms : CreateSpaceEvents()
|
||||
object Dismiss : CreateSpaceEvents()
|
||||
data class FinishSuccess(val spaceId: String, val defaultRoomId: String?) : CreateSpaceEvents()
|
||||
data class ShowModalError(val errorMessage: String) : CreateSpaceEvents()
|
||||
object HideModalLoading : CreateSpaceEvents()
|
||||
}
|
||||
|
||||
class CreateSpaceViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: CreateSpaceState,
|
||||
private val session: Session,
|
||||
private val stringProvider: StringProvider
|
||||
private val stringProvider: StringProvider,
|
||||
private val createSpaceViewModelTask: CreateSpaceViewModelTask,
|
||||
private val errorFormatter: ErrorFormatter
|
||||
) : VectorViewModel<CreateSpaceState, CreateSpaceAction, CreateSpaceEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
|
@ -90,6 +108,12 @@ class CreateSpaceViewModel @AssistedInject constructor(
|
|||
}
|
||||
return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
|
||||
}
|
||||
|
||||
override fun initialState(viewModelContext: ViewModelContext): CreateSpaceState? {
|
||||
return CreateSpaceState(
|
||||
defaultRooms = mapOf(0 to viewModelContext.activity.getString(R.string.create_spaces_default_public_room_name))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handle(action: CreateSpaceAction) {
|
||||
|
@ -124,6 +148,21 @@ class CreateSpaceViewModel @AssistedInject constructor(
|
|||
CreateSpaceAction.NextFromDetails -> {
|
||||
handleNextFromDetails()
|
||||
}
|
||||
CreateSpaceAction.NextFromDefaultRooms -> {
|
||||
handleNextFromDefaultRooms()
|
||||
}
|
||||
is CreateSpaceAction.DefaultRoomNameChanged -> {
|
||||
setState {
|
||||
copy(
|
||||
defaultRooms = (defaultRooms ?: emptyMap()).toMutableMap().apply {
|
||||
this[action.index] = action.name
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
is CreateSpaceAction.SetAvatar -> {
|
||||
setState { copy(avatarUri = action.uri) }
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
|
@ -167,4 +206,53 @@ class CreateSpaceViewModel @AssistedInject constructor(
|
|||
_viewEvents.post(CreateSpaceEvents.NavigateToAddRooms)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleNextFromDefaultRooms() = withState { state ->
|
||||
val spaceName = state.name ?: return@withState
|
||||
setState {
|
||||
copy(creationResult = Loading())
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val result = createSpaceViewModelTask.execute(
|
||||
CreateSpaceTaskParams(
|
||||
spaceName = spaceName,
|
||||
spaceTopic = state.topic,
|
||||
spaceAvatar = state.avatarUri,
|
||||
isPublic = state.spaceType == SpaceType.Public,
|
||||
defaultRooms = state.defaultRooms
|
||||
?.entries
|
||||
?.sortedBy { it.key }
|
||||
?.mapNotNull { it.value } ?: emptyList()
|
||||
)
|
||||
)
|
||||
when (result) {
|
||||
is CreateSpaceTaskResult.Success -> {
|
||||
setState {
|
||||
copy(creationResult = Success(result.spaceId))
|
||||
}
|
||||
_viewEvents.post(CreateSpaceEvents.FinishSuccess(result.spaceId, result.childIds.firstOrNull()))
|
||||
}
|
||||
is CreateSpaceTaskResult.PartialSuccess -> {
|
||||
// XXX what can we do here?
|
||||
setState {
|
||||
copy(creationResult = Success(result.spaceId))
|
||||
}
|
||||
_viewEvents.post(CreateSpaceEvents.FinishSuccess(result.spaceId, result.childIds.firstOrNull()))
|
||||
}
|
||||
is CreateSpaceTaskResult.FailedToCreateSpace -> {
|
||||
setState {
|
||||
copy(creationResult = Fail(result.failure))
|
||||
}
|
||||
_viewEvents.post(CreateSpaceEvents.ShowModalError(errorFormatter.toHumanReadable(result.failure)))
|
||||
}
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
setState {
|
||||
copy(creationResult = Fail(failure))
|
||||
}
|
||||
_viewEvents.post(CreateSpaceEvents.ShowModalError(errorFormatter.toHumanReadable(failure)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2021 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.spaces.create
|
||||
|
||||
import android.net.Uri
|
||||
import im.vector.app.core.platform.ViewModelTask
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
||||
import org.matrix.android.sdk.internal.util.awaitCallback
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
sealed class CreateSpaceTaskResult {
|
||||
|
||||
data class Success(val spaceId: String, val childIds: List<String>) : CreateSpaceTaskResult()
|
||||
|
||||
data class PartialSuccess(val spaceId: String, val childIds: List<String>, val failedRooms: Map<String, Throwable>) : CreateSpaceTaskResult()
|
||||
|
||||
class FailedToCreateSpace(val failure: Throwable) : CreateSpaceTaskResult()
|
||||
}
|
||||
|
||||
data class CreateSpaceTaskParams(
|
||||
val spaceName: String,
|
||||
val spaceTopic: String?,
|
||||
val spaceAvatar: Uri? = null,
|
||||
val isPublic: Boolean,
|
||||
val defaultRooms: List<String> = emptyList()
|
||||
)
|
||||
|
||||
class CreateSpaceViewModelTask @Inject constructor(
|
||||
private val session: Session,
|
||||
private val stringProvider: StringProvider
|
||||
) : ViewModelTask<CreateSpaceTaskParams, CreateSpaceTaskResult> {
|
||||
|
||||
override suspend fun execute(params: CreateSpaceTaskParams): CreateSpaceTaskResult {
|
||||
val spaceID = try {
|
||||
session.spaceService().createSpace(params.spaceName, params.spaceTopic, params.spaceAvatar, params.isPublic)
|
||||
} catch (failure: Throwable) {
|
||||
return CreateSpaceTaskResult.FailedToCreateSpace(failure)
|
||||
}
|
||||
|
||||
val createdSpace = session.spaceService().getSpace(spaceID)
|
||||
|
||||
val childErrors = mutableMapOf<String, Throwable>()
|
||||
val childIds = mutableListOf<String>()
|
||||
if (params.isPublic) {
|
||||
params.defaultRooms
|
||||
.filter { it.isNotBlank() }
|
||||
.forEach { roomName ->
|
||||
try {
|
||||
val roomId = try {
|
||||
awaitCallback<String> {
|
||||
session.createRoom(CreateRoomParams().apply {
|
||||
this.name = roomName
|
||||
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||
}, it)
|
||||
}
|
||||
} catch (timeout: CreateRoomFailure.CreatedWithTimeout) {
|
||||
// we ignore that?
|
||||
timeout.roomID
|
||||
}
|
||||
val via = session.sessionParams.homeServerHost?.let { listOf(it) } ?: emptyList()
|
||||
createdSpace!!.addChildren(roomId, via, null, true)
|
||||
childIds.add(roomId)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.d("Failed to create child room in $spaceID")
|
||||
childErrors[roomName] = failure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return if (childErrors.isEmpty()) {
|
||||
CreateSpaceTaskResult.Success(spaceID, childIds)
|
||||
} else {
|
||||
CreateSpaceTaskResult.PartialSuccess(spaceID, childIds, childErrors)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@ import javax.inject.Inject
|
|||
class SpaceDefaultRoomEpoxyController @Inject constructor(
|
||||
private val stringProvider: StringProvider,
|
||||
private val colorProvider: ColorProvider
|
||||
// private val avatarRenderer: AvatarRenderer
|
||||
) : TypedEpoxyController<CreateSpaceState>() {
|
||||
|
||||
var listener: Listener? = null
|
||||
|
@ -50,36 +49,33 @@ class SpaceDefaultRoomEpoxyController @Inject constructor(
|
|||
formEditTextItem {
|
||||
id("roomName1")
|
||||
enabled(true)
|
||||
value(data?.name)
|
||||
hint(stringProvider.getString(R.string.create_room_name_hint))
|
||||
value(data?.defaultRooms?.get(0))
|
||||
hint(stringProvider.getString(R.string.create_room_name_section))
|
||||
showBottomSeparator(false)
|
||||
// errorMessage(data?.nameInlineError)
|
||||
onTextChange { text ->
|
||||
// listener?.onNameChange(text)
|
||||
listener?.onNameChange(0, text)
|
||||
}
|
||||
}
|
||||
|
||||
formEditTextItem {
|
||||
id("roomName2")
|
||||
enabled(true)
|
||||
// value(data?.name)
|
||||
hint(stringProvider.getString(R.string.create_room_name_hint))
|
||||
value(data?.defaultRooms?.get(1))
|
||||
hint(stringProvider.getString(R.string.create_room_name_section))
|
||||
showBottomSeparator(false)
|
||||
// errorMessage(data?.nameInlineError)
|
||||
onTextChange { text ->
|
||||
// listener?.onNameChange(text)
|
||||
listener?.onNameChange(1, text)
|
||||
}
|
||||
}
|
||||
|
||||
formEditTextItem {
|
||||
id("roomName3")
|
||||
enabled(true)
|
||||
// value(data?.name)
|
||||
hint(stringProvider.getString(R.string.create_room_name_hint))
|
||||
value(data?.defaultRooms?.get(2))
|
||||
hint(stringProvider.getString(R.string.create_room_name_section))
|
||||
showBottomSeparator(false)
|
||||
// errorMessage(data?.nameInlineError)
|
||||
onTextChange { text ->
|
||||
// listener?.onNameChange(text)
|
||||
listener?.onNameChange(2, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +83,7 @@ class SpaceDefaultRoomEpoxyController @Inject constructor(
|
|||
interface Listener {
|
||||
// fun onAvatarDelete()
|
||||
// fun onAvatarChange()
|
||||
// fun onNameChange(newName: String)
|
||||
fun onNameChange(index: Int, newName: String)
|
||||
// fun onTopicChange(newTopic: String)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.spaces.create
|
|||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import androidx.appcompat.content.res.AppCompatResources.getDrawable
|
||||
|
@ -85,7 +86,7 @@ class WizardButtonView @JvmOverloads constructor(context: Context, attrs: Attrib
|
|||
|
||||
val outValue = TypedValue()
|
||||
context.theme.resolveAttribute(android.R.attr.selectableItemBackground, outValue, true)
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
this.foreground = getDrawable(context, outValue.resourceId)
|
||||
}
|
||||
|
||||
|
|
3
vector/src/main/res/values/ids.xml
Normal file
3
vector/src/main/res/values/ids.xml
Normal file
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<item type="id" name="space_item_home" />
|
||||
</resources>
|
|
@ -3275,6 +3275,8 @@
|
|||
<string name="create_space_error_empty_field_space_name">Give it a name to continue.</string>
|
||||
<string name="create_spaces_room_public_header">What are some discussions you want to have in Runner’s World?</string>
|
||||
<string name="create_spaces_room_public_header_desc">We’ll create rooms for them, and auto-join everyone. You can add more later too.</string>
|
||||
<string name="create_spaces_default_public_room_name">General</string>
|
||||
<string name="create_spaces_loading_message">Creating Space…</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue