diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/ButtonStateView.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/ButtonStateView.kt new file mode 100755 index 00000000..151d34c0 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/ButtonStateView.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2019 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.riotredesign.core.platform + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import im.vector.riotredesign.R +import kotlinx.android.synthetic.main.view_button_state.view.* + +class ButtonStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) + : FrameLayout(context, attrs, defStyle) { + + sealed class State { + object Button : State() + object Loading : State() + object Loaded : State() + object Error : State() + } + + var callback: Callback? = null + + interface Callback { + fun onButtonClicked() + fun onRetryClicked() + } + + init { + View.inflate(context, R.layout.view_button_state, this) + layoutParams = LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + + buttonStateButton.setOnClickListener { + callback?.onButtonClicked() + } + + buttonStateRetry.setOnClickListener { + callback?.onRetryClicked() + } + + // Read attributes + context.theme.obtainStyledAttributes( + attrs, + R.styleable.ButtonStateView, + 0, 0) + .apply { + try { + buttonStateButton.text = getString(R.styleable.ButtonStateView_bsv_button_text) + buttonStateLoaded.setImageDrawable(getDrawable(R.styleable.ButtonStateView_bsv_loaded_image_src)) + } finally { + recycle() + } + } + } + + fun render(newState: State) { + if (newState == State.Button) { + buttonStateButton.isVisible = true + } else { + // We use isInvisible because we want to keep button space in the layout + buttonStateButton.isInvisible = true + } + + buttonStateLoading.isVisible = newState == State.Loading + buttonStateLoaded.isVisible = newState == State.Loaded + buttonStateRetry.isVisible = newState == State.Error + } +} diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt index 8821b1d4..6487b39c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt @@ -16,17 +16,15 @@ package im.vector.riotredesign.features.roomdirectory -import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView -import androidx.core.view.isInvisible -import androidx.core.view.isVisible import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.riotredesign.R import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder import im.vector.riotredesign.core.epoxy.VectorEpoxyModel +import im.vector.riotredesign.core.platform.ButtonStateView import im.vector.riotredesign.features.home.AvatarRenderer @EpoxyModelClass(layout = R.layout.item_public_room) @@ -68,21 +66,27 @@ abstract class PublicRoomItem : VectorEpoxyModel() { // TODO Use formatter for big numbers? holder.counterView.text = nbOfMembers.toString() - if (joinState == JoinState.NOT_JOINED) { - holder.joinButton.isVisible = true - } else { - // We use isInvisible because we want to keep button space in the layout - holder.joinButton.isInvisible = true + holder.buttonState.render( + when (joinState) { + JoinState.NOT_JOINED -> ButtonStateView.State.Button + JoinState.JOINING -> ButtonStateView.State.Loading + JoinState.JOINED -> ButtonStateView.State.Loaded + JoinState.JOINING_ERROR -> ButtonStateView.State.Error + } + ) + + holder.buttonState.callback = object : ButtonStateView.Callback { + override fun onButtonClicked() { + joinListener?.invoke() + } + + override fun onRetryClicked() { + // Same action + onButtonClicked() + } } - holder.joiningView.isVisible = joinState == JoinState.JOINING - holder.retryButton.isVisible = joinState == JoinState.JOINING_ERROR - holder.joinedView.isVisible = joinState == JoinState.JOINED - - holder.joinButton.setOnClickListener { joinListener?.invoke() } - holder.retryButton.setOnClickListener { joinListener?.invoke() } } - class Holder : VectorEpoxyHolder() { val rootView by bind(R.id.itemPublicRoomLayout) @@ -90,11 +94,7 @@ abstract class PublicRoomItem : VectorEpoxyModel() { val nameView by bind(R.id.itemPublicRoomName) val counterView by bind(R.id.itemPublicRoomMembersCount) - val joinedView by bind(R.id.itemPublicRoomJoined) - val joinButton by bind(R.id.itemPublicRoomJoin) - val joiningView by bind(R.id.itemPublicRoomJoining) - val retryButton by bind(R.id.itemPublicRoomRetry) + val buttonState by bind(R.id.itemPublicRoomButtonState) } - } diff --git a/vector/src/main/res/layout/item_public_room.xml b/vector/src/main/res/layout/item_public_room.xml index eb1f44ee..2c84698b 100644 --- a/vector/src/main/res/layout/item_public_room.xml +++ b/vector/src/main/res/layout/item_public_room.xml @@ -55,56 +55,23 @@ android:textColor="#7E899C" android:textSize="15sp" app:layout_constraintBottom_toTopOf="@+id/itemPublicRoomBottomSeparator" - app:layout_constraintEnd_toStartOf="@id/itemPublicRoomJoin" + app:layout_constraintEnd_toStartOf="@id/itemPublicRoomButtonState" app:layout_constraintStart_toEndOf="@id/itemPublicRoomName" app:layout_constraintTop_toTopOf="parent" tools:text="148" /> -