Unverified Commit 7ec44a55 authored by Benoît Marty's avatar Benoît Marty Committed by GitHub
Browse files

Merge pull request #3290 from vector-im/feature/bca/spaces_various_fixes

Various fixes on spaces explore
parents 711ee24c f1919be1
...@@ -127,24 +127,30 @@ internal class DefaultSpaceService @Inject constructor( ...@@ -127,24 +127,30 @@ internal class DefaultSpaceService @Inject constructor(
), ),
second = response.rooms second = response.rooms
?.filter { it.roomId != spaceId } ?.filter { it.roomId != spaceId }
?.map { childSummary -> ?.flatMap { childSummary ->
val childStateEv = response.events response.events
?.firstOrNull { it.stateKey == childSummary.roomId && it.type == EventType.STATE_SPACE_CHILD } ?.filter { it.stateKey == childSummary.roomId && it.type == EventType.STATE_SPACE_CHILD }
val childStateEvContent = childStateEv?.content.toModel<SpaceChildContent>() ?.mapNotNull { childStateEv ->
SpaceChildInfo( // create a child entry for everytime this room is the child of a space
childRoomId = childSummary.roomId, // beware that a room could appear then twice in this list
isKnown = true, childStateEv.content.toModel<SpaceChildContent>()?.let { childStateEvContent ->
roomType = childSummary.roomType, SpaceChildInfo(
name = childSummary.name, childRoomId = childSummary.roomId,
topic = childSummary.topic, isKnown = true,
avatarUrl = childSummary.avatarUrl, roomType = childSummary.roomType,
order = childStateEvContent?.order, name = childSummary.name,
autoJoin = childStateEvContent?.autoJoin ?: false, topic = childSummary.topic,
viaServers = childStateEvContent?.via ?: emptyList(), avatarUrl = childSummary.avatarUrl,
activeMemberCount = childSummary.numJoinedMembers, order = childStateEvContent.order,
parentRoomId = childStateEv?.roomId autoJoin = childStateEvContent.autoJoin ?: false,
) viaServers = childStateEvContent.via.orEmpty(),
}.orEmpty() activeMemberCount = childSummary.numJoinedMembers,
parentRoomId = childStateEv.roomId
)
}
}.orEmpty()
}
.orEmpty()
) )
} }
} }
......
...@@ -194,7 +194,7 @@ class SpaceRoomListSectionBuilder( ...@@ -194,7 +194,7 @@ class SpaceRoomListSectionBuilder(
} else { } else {
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) { liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
val spaceSum = tryOrNull { session.spaceService().querySpaceChildren(selectedSpace.roomId, suggestedOnly = true) } val spaceSum = tryOrNull { session.spaceService().querySpaceChildren(selectedSpace.roomId, suggestedOnly = true) }
val value = spaceSum?.second ?: emptyList() val value = spaceSum?.second.orEmpty().distinctBy { it.childRoomId }
// i need to check if it's already joined. // i need to check if it's already joined.
val filtered = value.filter { val filtered = value.filter {
session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
......
...@@ -36,6 +36,7 @@ import im.vector.app.databinding.BottomSheetMatrixToCardBinding ...@@ -36,6 +36,7 @@ import im.vector.app.databinding.BottomSheetMatrixToCardBinding
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkData
import java.lang.ref.WeakReference
import javax.inject.Inject import javax.inject.Inject
import kotlin.reflect.KClass import kotlin.reflect.KClass
...@@ -56,7 +57,13 @@ class MatrixToBottomSheet : ...@@ -56,7 +57,13 @@ class MatrixToBottomSheet :
injector.inject(this) injector.inject(this)
} }
private var interactionListener: InteractionListener? = null private var weakReference = WeakReference<InteractionListener>(null)
var interactionListener: InteractionListener?
set(value) {
weakReference = WeakReference(value)
}
get() = weakReference.get()
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetMatrixToCardBinding { override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetMatrixToCardBinding {
return BottomSheetMatrixToCardBinding.inflate(inflater, container, false) return BottomSheetMatrixToCardBinding.inflate(inflater, container, false)
......
...@@ -120,6 +120,7 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( ...@@ -120,6 +120,7 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
?.roomSummary() ?.roomSummary()
// don't take if not active, as it could be outdated // don't take if not active, as it could be outdated
?.takeIf { it.membership.isActive() } ?.takeIf { it.membership.isActive() }
// XXX fix that
val forceRefresh = true val forceRefresh = true
if (!forceRefresh && knownRoom != null) { if (!forceRefresh && knownRoom != null) {
setState { setState {
...@@ -147,7 +148,7 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( ...@@ -147,7 +148,7 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor(
topic = peekResult.topic ?: "", topic = peekResult.topic ?: "",
memberCount = peekResult.numJoinedMembers, memberCount = peekResult.numJoinedMembers,
alias = peekResult.alias, alias = peekResult.alias,
membership = Membership.NONE, membership = knownRoom?.membership ?: Membership.NONE,
roomType = peekResult.roomType, roomType = peekResult.roomType,
viaServers = peekResult.viaServers.takeIf { it.isNotEmpty() } ?: permalinkData.viaParameters viaServers = peekResult.viaServers.takeIf { it.isNotEmpty() } ?: permalinkData.viaParameters
).also { ).also {
......
...@@ -21,7 +21,6 @@ import android.view.LayoutInflater ...@@ -21,7 +21,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Loading
...@@ -31,6 +30,7 @@ import com.airbnb.mvrx.parentFragmentViewModel ...@@ -31,6 +30,7 @@ import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.platform.ButtonStateView
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentMatrixToRoomSpaceCardBinding import im.vector.app.databinding.FragmentMatrixToRoomSpaceCardBinding
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
...@@ -50,11 +50,18 @@ class MatrixToRoomSpaceFragment @Inject constructor( ...@@ -50,11 +50,18 @@ class MatrixToRoomSpaceFragment @Inject constructor(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
views.matrixToCardMainButton.debouncedClicks { views.matrixToCardMainButton.callback = object : ButtonStateView.Callback {
mainButtonClicked() override fun onButtonClicked() {
mainButtonClicked()
}
override fun onRetryClicked() = onButtonClicked()
} }
views.matrixToCardSecondaryButton.debouncedClicks { views.matrixToCardSecondaryButton.callback = object : ButtonStateView.Callback {
secondaryButtonClicked() override fun onButtonClicked() {
secondaryButtonClicked()
}
override fun onRetryClicked() = onButtonClicked()
} }
} }
...@@ -164,16 +171,20 @@ class MatrixToRoomSpaceFragment @Inject constructor( ...@@ -164,16 +171,20 @@ class MatrixToRoomSpaceFragment @Inject constructor(
when (state.peopleYouKnow) { when (state.peopleYouKnow) {
is Success -> { is Success -> {
val someYouKnow = state.peopleYouKnow.invoke() val someYouKnow = state.peopleYouKnow.invoke()
someYouKnow.forEachIndexed { index, item -> if (someYouKnow.isEmpty()) {
images[index].isVisible = true views.peopleYouMayKnowText.isVisible = false
avatarRenderer.render(item, images[index]) } else {
someYouKnow.forEachIndexed { index, item ->
images[index].isVisible = true
avatarRenderer.render(item, images[index])
}
views.peopleYouMayKnowText.setTextOrHide(
resources.getQuantityString(R.plurals.space_people_you_know,
someYouKnow.count(),
someYouKnow.count()
)
)
} }
views.peopleYouMayKnowText.setTextOrHide(
resources.getQuantityString(R.plurals.space_people_you_know,
someYouKnow.count(),
someYouKnow.count()
)
)
} }
else -> { else -> {
views.peopleYouMayKnowText.isVisible = false views.peopleYouMayKnowText.isVisible = false
...@@ -182,21 +193,17 @@ class MatrixToRoomSpaceFragment @Inject constructor( ...@@ -182,21 +193,17 @@ class MatrixToRoomSpaceFragment @Inject constructor(
when (state.startChattingState) { when (state.startChattingState) {
Uninitialized -> { Uninitialized -> {
views.matrixToCardButtonLoading.isVisible = false views.matrixToCardMainButton.render(ButtonStateView.State.Button)
// views.matrixToCardMainButton.isVisible = false
} }
is Success -> { is Success -> {
views.matrixToCardButtonLoading.isVisible = false views.matrixToCardMainButton.render(ButtonStateView.State.Button)
views.matrixToCardMainButton.isVisible = true
} }
is Fail -> { is Fail -> {
views.matrixToCardButtonLoading.isVisible = false views.matrixToCardMainButton.render(ButtonStateView.State.Error)
views.matrixToCardMainButton.isVisible = true
// TODO display some error copy? // TODO display some error copy?
} }
is Loading -> { is Loading -> {
views.matrixToCardButtonLoading.isVisible = true views.matrixToCardMainButton.render(ButtonStateView.State.Loading)
views.matrixToCardMainButton.isInvisible = true
} }
} }
} }
......
...@@ -19,6 +19,8 @@ package im.vector.app.features.spaces ...@@ -19,6 +19,8 @@ package im.vector.app.features.spaces
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
import im.vector.app.R import im.vector.app.R
...@@ -26,6 +28,7 @@ import im.vector.app.core.di.ScreenComponent ...@@ -26,6 +28,7 @@ import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.commitTransaction
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.databinding.ActivitySimpleBinding
import im.vector.app.features.matrixto.MatrixToBottomSheet
import im.vector.app.features.spaces.explore.SpaceDirectoryArgs import im.vector.app.features.spaces.explore.SpaceDirectoryArgs
import im.vector.app.features.spaces.explore.SpaceDirectoryFragment import im.vector.app.features.spaces.explore.SpaceDirectoryFragment
import im.vector.app.features.spaces.explore.SpaceDirectoryState import im.vector.app.features.spaces.explore.SpaceDirectoryState
...@@ -33,7 +36,7 @@ import im.vector.app.features.spaces.explore.SpaceDirectoryViewEvents ...@@ -33,7 +36,7 @@ import im.vector.app.features.spaces.explore.SpaceDirectoryViewEvents
import im.vector.app.features.spaces.explore.SpaceDirectoryViewModel import im.vector.app.features.spaces.explore.SpaceDirectoryViewModel
import javax.inject.Inject import javax.inject.Inject
class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceDirectoryViewModel.Factory { class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceDirectoryViewModel.Factory, MatrixToBottomSheet.InteractionListener {
@Inject lateinit var spaceDirectoryViewModelFactory: SpaceDirectoryViewModel.Factory @Inject lateinit var spaceDirectoryViewModelFactory: SpaceDirectoryViewModel.Factory
...@@ -47,8 +50,25 @@ class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceD ...@@ -47,8 +50,25 @@ class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceD
val sharedViewModel: SpaceDirectoryViewModel by viewModel() val sharedViewModel: SpaceDirectoryViewModel by viewModel()
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentAttached(fm: FragmentManager, f: Fragment, context: Context) {
if (f is MatrixToBottomSheet) {
f.interactionListener = this@SpaceExploreActivity
}
super.onFragmentAttached(fm, f, context)
}
override fun onFragmentDetached(fm: FragmentManager, f: Fragment) {
if (f is MatrixToBottomSheet) {
f.interactionListener = null
}
super.onFragmentDetached(fm, f)
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false)
if (isFirstCreation()) { if (isFirstCreation()) {
val simpleName = SpaceDirectoryFragment::class.java.simpleName val simpleName = SpaceDirectoryFragment::class.java.simpleName
...@@ -72,10 +92,18 @@ class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceD ...@@ -72,10 +92,18 @@ class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceD
is SpaceDirectoryViewEvents.NavigateToRoom -> { is SpaceDirectoryViewEvents.NavigateToRoom -> {
navigator.openRoom(this, it.roomId) navigator.openRoom(this, it.roomId)
} }
is SpaceDirectoryViewEvents.NavigateToMxToBottomSheet -> {
MatrixToBottomSheet.withLink(it.link, this).show(supportFragmentManager, "ShowChild")
}
} }
} }
} }
override fun onDestroy() {
supportFragmentManager.unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks)
super.onDestroy()
}
companion object { companion object {
fun newIntent(context: Context, spaceId: String): Intent { fun newIntent(context: Context, spaceId: String): Intent {
return Intent(context, SpaceExploreActivity::class.java).apply { return Intent(context, SpaceExploreActivity::class.java).apply {
...@@ -86,4 +114,8 @@ class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceD ...@@ -86,4 +114,8 @@ class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), SpaceD
override fun create(initialState: SpaceDirectoryState): SpaceDirectoryViewModel = override fun create(initialState: SpaceDirectoryState): SpaceDirectoryViewModel =
spaceDirectoryViewModelFactory.create(initialState) spaceDirectoryViewModelFactory.create(initialState)
override fun navigateToRoom(roomId: String) {
navigator.openRoom(this, roomId)
}
} }
...@@ -38,6 +38,7 @@ class SpaceDirectoryController @Inject constructor( ...@@ -38,6 +38,7 @@ class SpaceDirectoryController @Inject constructor(
interface InteractionListener { interface InteractionListener {
fun onButtonClick(spaceChildInfo: SpaceChildInfo) fun onButtonClick(spaceChildInfo: SpaceChildInfo)
fun onSpaceChildClick(spaceChildInfo: SpaceChildInfo) fun onSpaceChildClick(spaceChildInfo: SpaceChildInfo)
fun onRoomClick(spaceChildInfo: SpaceChildInfo)
} }
var listener: InteractionListener? = null var listener: InteractionListener? = null
...@@ -81,6 +82,8 @@ class SpaceDirectoryController @Inject constructor( ...@@ -81,6 +82,8 @@ class SpaceDirectoryController @Inject constructor(
apply { apply {
if (isSpace) { if (isSpace) {
itemClickListener(View.OnClickListener { listener?.onSpaceChildClick(info) }) itemClickListener(View.OnClickListener { listener?.onSpaceChildClick(info) })
} else {
itemClickListener(View.OnClickListener { listener?.onRoomClick(info) })
} }
} }
buttonClickListener(View.OnClickListener { listener?.onButtonClick(info) }) buttonClickListener(View.OnClickListener { listener?.onButtonClick(info) })
......
...@@ -23,13 +23,13 @@ import android.view.View ...@@ -23,13 +23,13 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.OnBackPressed
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
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.SpaceChildInfo
import javax.inject.Inject import javax.inject.Inject
...@@ -68,8 +68,13 @@ class SpaceDirectoryFragment @Inject constructor( ...@@ -68,8 +68,13 @@ class SpaceDirectoryFragment @Inject constructor(
super.onDestroyView() super.onDestroyView()
} }
override fun invalidate() = withState(viewModel) { override fun invalidate() = withState(viewModel) { state ->
epoxyController.setData(it) epoxyController.setData(state)
val title = state.hierarchyStack.lastOrNull()?.let { currentParent ->
state.spaceSummaryApiResult.invoke()?.firstOrNull { it.childRoomId == currentParent }
}?.name ?: getString(R.string.space_explore_activity_title)
views.toolbar.title = title
} }
override fun onButtonClick(spaceChildInfo: SpaceChildInfo) { override fun onButtonClick(spaceChildInfo: SpaceChildInfo) {
...@@ -77,13 +82,19 @@ class SpaceDirectoryFragment @Inject constructor( ...@@ -77,13 +82,19 @@ class SpaceDirectoryFragment @Inject constructor(
} }
override fun onSpaceChildClick(spaceChildInfo: SpaceChildInfo) { override fun onSpaceChildClick(spaceChildInfo: SpaceChildInfo) {
if (spaceChildInfo.roomType == RoomType.SPACE) { viewModel.handle(SpaceDirectoryViewAction.ExploreSubSpace(spaceChildInfo))
viewModel.handle(SpaceDirectoryViewAction.ExploreSubSpace(spaceChildInfo)) }
}
override fun onRoomClick(spaceChildInfo: SpaceChildInfo) {
viewModel.handle(SpaceDirectoryViewAction.ShowDetails(spaceChildInfo))
} }
override fun onBackPressed(toolbarButton: Boolean): Boolean { override fun onBackPressed(toolbarButton: Boolean): Boolean {
viewModel.handle(SpaceDirectoryViewAction.HandleBack) viewModel.handle(SpaceDirectoryViewAction.HandleBack)
return true return true
} }
// override fun navigateToRoom(roomId: String) {
// viewModel.handle(SpaceDirectoryViewAction.NavigateToRoom(roomId))
// }
} }
...@@ -22,5 +22,7 @@ import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo ...@@ -22,5 +22,7 @@ import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
sealed class SpaceDirectoryViewAction : VectorViewModelAction { sealed class SpaceDirectoryViewAction : VectorViewModelAction {
data class ExploreSubSpace(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction() data class ExploreSubSpace(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction()
data class JoinOrOpen(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction() data class JoinOrOpen(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction()
data class ShowDetails(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction()
data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewAction()
object HandleBack : SpaceDirectoryViewAction() object HandleBack : SpaceDirectoryViewAction()
} }
...@@ -21,4 +21,5 @@ import im.vector.app.core.platform.VectorViewEvents ...@@ -21,4 +21,5 @@ import im.vector.app.core.platform.VectorViewEvents
sealed class SpaceDirectoryViewEvents : VectorViewEvents { sealed class SpaceDirectoryViewEvents : VectorViewEvents {
object Dismiss : SpaceDirectoryViewEvents() object Dismiss : SpaceDirectoryViewEvents()
data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewEvents() data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewEvents()
data class NavigateToMxToBottomSheet(val link: String) : SpaceDirectoryViewEvents()
} }
...@@ -91,6 +91,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor( ...@@ -91,6 +91,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
private fun observeJoinedRooms() { private fun observeJoinedRooms() {
val queryParams = roomSummaryQueryParams { val queryParams = roomSummaryQueryParams {
memberships = listOf(Membership.JOIN) memberships = listOf(Membership.JOIN)
excludeType = null
} }
session session
.rx() .rx()
...@@ -135,6 +136,16 @@ class SpaceDirectoryViewModel @AssistedInject constructor( ...@@ -135,6 +136,16 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
is SpaceDirectoryViewAction.JoinOrOpen -> { is SpaceDirectoryViewAction.JoinOrOpen -> {
handleJoinOrOpen(action.spaceChildInfo) handleJoinOrOpen(action.spaceChildInfo)
} }
is SpaceDirectoryViewAction.NavigateToRoom -> {
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToRoom(action.roomId))
}
is SpaceDirectoryViewAction.ShowDetails -> {
// This is temporary for now to at least display something for the space beta
// It's not ideal as it's doing some peeking that is not needed.
session.permalinkService().createRoomPermalink(action.spaceChildInfo.childRoomId)?.let {
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToMxToBottomSheet(it))
}
}
} }
} }
......
Supports Markdown
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