mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-21 17:05:39 +03:00
Fix issues with matrix.to deep linking
This commit is contained in:
parent
bcd86977d2
commit
804afc9a1d
11 changed files with 511 additions and 58 deletions
|
@ -81,7 +81,8 @@
|
|||
android:resource="@xml/shortcuts" />
|
||||
</activity-alias>
|
||||
|
||||
<activity android:name=".features.home.HomeActivity" />
|
||||
<activity android:name=".features.home.HomeActivity"
|
||||
android:launchMode="singleTask"/>
|
||||
<activity
|
||||
android:name=".features.login.LoginActivity"
|
||||
android:launchMode="singleTask"
|
||||
|
@ -189,10 +190,9 @@
|
|||
<activity
|
||||
android:name=".features.signout.soft.SoftLogoutActivity"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity android:name=".features.permalink.PermalinkHandlerActivity">
|
||||
<activity android:name=".features.permalink.PermalinkHandlerActivity" android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
|
|
|
@ -38,8 +38,12 @@ import im.vector.app.core.extensions.replaceFragment
|
|||
import im.vector.app.core.platform.ToolbarConfigurable
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.pushers.PushersManager
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.disclaimer.showDisclaimerDialog
|
||||
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||
import im.vector.app.features.permalink.NavigationInterceptor
|
||||
import im.vector.app.features.permalink.PermalinkHandler
|
||||
import im.vector.app.features.popup.DefaultVectorAlert
|
||||
import im.vector.app.features.popup.PopupAlertManager
|
||||
import im.vector.app.features.popup.VerificationVectorAlert
|
||||
|
@ -50,10 +54,12 @@ import im.vector.app.features.themes.ThemeUtils
|
|||
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
|
||||
import im.vector.app.push.fcm.FcmHelper
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.activity_home.*
|
||||
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
||||
import org.matrix.android.sdk.api.session.InitialSyncProgressService
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
@ -64,7 +70,8 @@ data class HomeActivityArgs(
|
|||
val accountCreation: Boolean
|
||||
) : Parcelable
|
||||
|
||||
class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDetectorSharedViewModel.Factory, ServerBackupStatusViewModel.Factory {
|
||||
class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDetectorSharedViewModel.Factory, ServerBackupStatusViewModel.Factory,
|
||||
NavigationInterceptor {
|
||||
|
||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||
|
||||
|
@ -82,6 +89,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
@Inject lateinit var popupAlertManager: PopupAlertManager
|
||||
@Inject lateinit var shortcutsHandler: ShortcutsHandler
|
||||
@Inject lateinit var unknownDeviceViewModelFactory: UnknownDeviceDetectorSharedViewModel.Factory
|
||||
@Inject lateinit var permalinkHandler: PermalinkHandler
|
||||
|
||||
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
||||
override fun onDrawerStateChanged(newState: Int) {
|
||||
|
@ -117,9 +125,9 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
.observe()
|
||||
.subscribe { sharedAction ->
|
||||
when (sharedAction) {
|
||||
is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.CloseDrawer -> drawerLayout.closeDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.OpenGroup -> {
|
||||
is HomeActivitySharedAction.OpenGroup -> {
|
||||
drawerLayout.closeDrawer(GravityCompat.START)
|
||||
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
|
||||
}
|
||||
|
@ -136,20 +144,42 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
homeActivityViewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is HomeActivityViewEvents.AskPasswordToInitCrossSigning -> handleAskPasswordToInitCrossSigning(it)
|
||||
is HomeActivityViewEvents.OnNewSession -> handleOnNewSession(it)
|
||||
HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush()
|
||||
is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it)
|
||||
is HomeActivityViewEvents.OnNewSession -> handleOnNewSession(it)
|
||||
HomeActivityViewEvents.PromptToEnableSessionPush -> handlePromptToEnablePush()
|
||||
is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it)
|
||||
}.exhaustive
|
||||
}
|
||||
homeActivityViewModel.subscribe(this) { renderState(it) }
|
||||
|
||||
shortcutsHandler.observeRoomsAndBuildShortcuts()
|
||||
.disposeOnDestroy()
|
||||
|
||||
if (isFirstCreation()) {
|
||||
handleIntent(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleIntent(intent: Intent?) {
|
||||
intent?.dataString?.let { deepLink ->
|
||||
if (!deepLink.startsWith(PermalinkService.MATRIX_TO_URL_BASE)) return@let
|
||||
|
||||
permalinkHandler.launch(this, deepLink,
|
||||
navigationInterceptor = this,
|
||||
buildTask = true)
|
||||
// .delay(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { isHandled ->
|
||||
if (!isHandled) {
|
||||
toast(R.string.permalink_malformed)
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderState(state: HomeActivityViewState) {
|
||||
when (val status = state.initialSyncProgressServiceStatus) {
|
||||
is InitialSyncProgressService.Status.Idle -> {
|
||||
is InitialSyncProgressService.Status.Idle -> {
|
||||
waiting_view.isVisible = false
|
||||
}
|
||||
is InitialSyncProgressService.Status.Progressing -> {
|
||||
|
@ -270,6 +300,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
if (intent?.getParcelableExtra<HomeActivityArgs>(MvRx.KEY_ARG)?.clearNotification == true) {
|
||||
notificationDrawerManager.clearAllEvents()
|
||||
}
|
||||
handleIntent(intent)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
@ -313,11 +344,11 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
bugReporter.openBugReportScreen(this, false)
|
||||
return true
|
||||
}
|
||||
R.id.menu_home_filter -> {
|
||||
R.id.menu_home_filter -> {
|
||||
navigator.openRoomsFiltering(this)
|
||||
return true
|
||||
}
|
||||
R.id.menu_home_setting -> {
|
||||
R.id.menu_home_setting -> {
|
||||
navigator.openSettings(this)
|
||||
return true
|
||||
}
|
||||
|
@ -334,6 +365,18 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
}
|
||||
}
|
||||
|
||||
override fun navToMemberProfile(userId: String): Boolean {
|
||||
val listener = object : MatrixToBottomSheet.InteractionListener {
|
||||
override fun navigateToRoom(roomId: String) {
|
||||
navigator.openRoom(this@HomeActivity, roomId)
|
||||
}
|
||||
}
|
||||
// TODO check if there is already one??
|
||||
MatrixToBottomSheet.withUserId(userId, listener)
|
||||
.show(supportFragmentManager, "HA#MatrixToBottomSheet")
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newIntent(context: Context, clearNotification: Boolean = false, accountCreation: Boolean = false): Intent {
|
||||
val args = HomeActivityArgs(
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.matrixto
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
sealed class MatrixToAction : VectorViewModelAction {
|
||||
data class StartChattingWithUser(val matrixItem: MatrixItem) : MatrixToAction()
|
||||
}
|
|
@ -17,23 +17,38 @@
|
|||
package im.vector.app.features.matrixto
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_matrix_to_card.*
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import javax.inject.Inject
|
||||
|
||||
class MatrixToBottomSheet(private val matrixItem: MatrixItem) : VectorBaseBottomSheetDialogFragment() {
|
||||
class MatrixToBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
|
||||
@Parcelize
|
||||
data class MatrixToArgs(
|
||||
val matrixToLink: String?,
|
||||
val userId: String?
|
||||
) : Parcelable
|
||||
|
||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||
|
||||
interface InteractionListener {
|
||||
fun didTapStartMessage(matrixItem: MatrixItem)
|
||||
}
|
||||
@Inject
|
||||
lateinit var matrixToBottomSheetViewModelFactory: MatrixToBottomSheetViewModel.Factory
|
||||
|
||||
override fun injectWith(injector: ScreenComponent) {
|
||||
injector.inject(this)
|
||||
|
@ -43,21 +58,100 @@ class MatrixToBottomSheet(private val matrixItem: MatrixItem) : VectorBaseBottom
|
|||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_matrix_to_card
|
||||
|
||||
private val viewModel by fragmentViewModel(MatrixToBottomSheetViewModel::class)
|
||||
|
||||
interface InteractionListener {
|
||||
fun navigateToRoom(roomId: String)
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
super.invalidate()
|
||||
when (val item = state.matrixItem) {
|
||||
Uninitialized -> {
|
||||
matrixToCardContentLoading.isVisible = false
|
||||
matrixToCardUserContentVisibility.isVisible = false
|
||||
}
|
||||
is Loading -> {
|
||||
matrixToCardContentLoading.isVisible = true
|
||||
matrixToCardUserContentVisibility.isVisible = false
|
||||
}
|
||||
is Success -> {
|
||||
matrixToCardContentLoading.isVisible = false
|
||||
matrixToCardUserContentVisibility.isVisible = true
|
||||
matrixToCardNameText.setTextOrHide(item.invoke().displayName)
|
||||
matrixToCardUserIdText.setTextOrHide(item.invoke().id)
|
||||
avatarRenderer.render(item.invoke(), matrixToCardAvatar)
|
||||
}
|
||||
is Fail -> {
|
||||
// TODO display some error copy?
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
when (state.startChattingState) {
|
||||
Uninitialized -> {
|
||||
matrixToCardButtonLoading.isVisible = false
|
||||
matrixToCardSendMessageButton.isVisible = false
|
||||
}
|
||||
is Success -> {
|
||||
matrixToCardButtonLoading.isVisible = false
|
||||
matrixToCardSendMessageButton.isVisible = true
|
||||
}
|
||||
is Fail -> {
|
||||
matrixToCardButtonLoading.isVisible = false
|
||||
matrixToCardSendMessageButton.isVisible = true
|
||||
// TODO display some error copy?
|
||||
dismiss()
|
||||
}
|
||||
is Loading -> {
|
||||
matrixToCardButtonLoading.isVisible = true
|
||||
matrixToCardSendMessageButton.isInvisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
matrixToCardSendMessageButton.debouncedClicks {
|
||||
interactionListener?.didTapStartMessage(matrixItem)
|
||||
dismiss()
|
||||
withState(viewModel) {
|
||||
it.matrixItem.invoke()?.let { item ->
|
||||
viewModel.handle(MatrixToAction.StartChattingWithUser(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrixToCardNameText.setTextOrHide(matrixItem.displayName)
|
||||
matrixToCardUserIdText.setTextOrHide(matrixItem.id)
|
||||
avatarRenderer.render(matrixItem, matrixToCardAvatar)
|
||||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is MatrixToViewEvents.NavigateToRoom -> {
|
||||
interactionListener?.navigateToRoom(it.roomId)
|
||||
dismiss()
|
||||
}
|
||||
MatrixToViewEvents.Dismiss -> dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(matrixItem: MatrixItem, listener: InteractionListener?): MatrixToBottomSheet {
|
||||
return MatrixToBottomSheet(matrixItem).apply {
|
||||
fun withLink(matrixToLink: String, listener: InteractionListener?): MatrixToBottomSheet {
|
||||
return MatrixToBottomSheet().apply {
|
||||
arguments = Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, MatrixToBottomSheet.MatrixToArgs(
|
||||
matrixToLink = matrixToLink,
|
||||
userId = null
|
||||
))
|
||||
}
|
||||
interactionListener = listener
|
||||
}
|
||||
}
|
||||
|
||||
fun withUserId(userId: String, listener: InteractionListener?): MatrixToBottomSheet {
|
||||
return MatrixToBottomSheet().apply {
|
||||
arguments = Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, MatrixToBottomSheet.MatrixToArgs(
|
||||
matrixToLink = null,
|
||||
userId = userId
|
||||
))
|
||||
}
|
||||
interactionListener = listener
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.matrixto
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
data class MatrixToBottomSheetState(
|
||||
val matrixItem: Async<MatrixItem> = Uninitialized,
|
||||
val startChattingState: Async<Unit> = Uninitialized
|
||||
) : MvRxState
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* 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.matrixto
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.raw.wellknown.getElementWellknown
|
||||
import im.vector.app.features.raw.wellknown.isE2EByDefault
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.raw.RawService
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
|
||||
import org.matrix.android.sdk.api.session.profile.ProfileService
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import org.matrix.android.sdk.internal.util.awaitCallback
|
||||
|
||||
class MatrixToBottomSheetViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: MatrixToBottomSheetState,
|
||||
@Assisted val args: MatrixToBottomSheet.MatrixToArgs,
|
||||
private val session: Session,
|
||||
private val stringProvider: StringProvider,
|
||||
private val rawService: RawService) : VectorViewModel<MatrixToBottomSheetState, MatrixToAction, MatrixToViewEvents>(initialState) {
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface Factory {
|
||||
fun create(initialState: MatrixToBottomSheetState,
|
||||
args: MatrixToBottomSheet.MatrixToArgs): MatrixToBottomSheetViewModel
|
||||
}
|
||||
|
||||
init {
|
||||
setState {
|
||||
copy(matrixItem = Loading())
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
resolveLink()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun resolveLink() {
|
||||
when {
|
||||
args.matrixToLink != null -> {
|
||||
val linkedId = PermalinkParser.parse(args.matrixToLink)
|
||||
if (linkedId is PermalinkData.FallbackLink) {
|
||||
setState {
|
||||
copy(
|
||||
matrixItem = Fail(IllegalArgumentException(stringProvider.getString(R.string.permalink_malformed))),
|
||||
startChattingState = Uninitialized
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
when (linkedId) {
|
||||
is PermalinkData.UserLink -> {
|
||||
val user = resolveUser(linkedId.userId)
|
||||
setState {
|
||||
copy(
|
||||
matrixItem = Success(user.toMatrixItem()),
|
||||
startChattingState = Success(Unit)
|
||||
)
|
||||
}
|
||||
}
|
||||
is PermalinkData.RoomLink -> TODO()
|
||||
is PermalinkData.GroupLink -> {
|
||||
// not yet supported
|
||||
}
|
||||
is PermalinkData.FallbackLink -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
args.userId != null -> {
|
||||
val user = resolveUser(args.userId)
|
||||
|
||||
setState {
|
||||
copy(
|
||||
matrixItem = Success(user.toMatrixItem()),
|
||||
startChattingState = Success(Unit)
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
setState {
|
||||
copy(
|
||||
matrixItem = Fail(IllegalArgumentException(stringProvider.getString(R.string.unexpected_error))),
|
||||
startChattingState = Uninitialized
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun resolveUser(userId: String): User {
|
||||
return (session.getUser(userId)
|
||||
?: tryOrNull {
|
||||
awaitCallback<JsonDict> {
|
||||
session.getProfile(userId, it)
|
||||
}
|
||||
}?.let {
|
||||
User(userId, it[ProfileService.DISPLAY_NAME_KEY] as? String, it[ProfileService.AVATAR_URL_KEY] as? String)
|
||||
}
|
||||
// Create raw Uxid in case the user is not searchable
|
||||
?: User(userId, null, null))
|
||||
}
|
||||
|
||||
companion object : MvRxViewModelFactory<MatrixToBottomSheetViewModel, MatrixToBottomSheetState> {
|
||||
override fun create(viewModelContext: ViewModelContext, state: MatrixToBottomSheetState): MatrixToBottomSheetViewModel? {
|
||||
val fragment: MatrixToBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
|
||||
val args: MatrixToBottomSheet.MatrixToArgs = viewModelContext.args()
|
||||
|
||||
return fragment.matrixToBottomSheetViewModelFactory.create(state, args)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handle(action: MatrixToAction) {
|
||||
when (action) {
|
||||
is MatrixToAction.StartChattingWithUser -> handleStartChatting(action)
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun handleStartChatting(action: MatrixToAction.StartChattingWithUser) {
|
||||
val mxId = action.matrixItem.id
|
||||
val existing = session.getExistingDirectRoomWithUser(mxId)
|
||||
if (existing != null) {
|
||||
// navigate to this room
|
||||
_viewEvents.post(MatrixToViewEvents.NavigateToRoom(existing))
|
||||
} else {
|
||||
setState {
|
||||
copy(startChattingState = Loading())
|
||||
}
|
||||
// we should create the room then navigate
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val adminE2EByDefault = rawService.getElementWellknown(session.myUserId)
|
||||
?.isE2EByDefault()
|
||||
?: true
|
||||
|
||||
val roomParams = CreateRoomParams()
|
||||
.apply {
|
||||
invitedUserIds.add(mxId)
|
||||
setDirectMessage()
|
||||
enableEncryptionIfInvitedUsersSupportIt = adminE2EByDefault
|
||||
}
|
||||
|
||||
val roomId =
|
||||
try {
|
||||
awaitCallback<String> { session.createRoom(roomParams, it) }.also {
|
||||
setState {
|
||||
copy(startChattingState = Success(Unit))
|
||||
}
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
setState {
|
||||
copy(startChattingState = Fail(Exception(stringProvider.getString(R.string.invite_users_to_room_failure))))
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
_viewEvents.post(MatrixToViewEvents.NavigateToRoom(roomId))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.matrixto
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
|
||||
sealed class MatrixToViewEvents : VectorViewEvents {
|
||||
data class NavigateToRoom(val roomId: String) : MatrixToViewEvents()
|
||||
object Dismiss : MatrixToViewEvents()
|
||||
}
|
|
@ -23,11 +23,9 @@ import im.vector.app.core.di.ActiveSessionHolder
|
|||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.extensions.replaceFragment
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.home.HomeActivity
|
||||
import im.vector.app.features.home.LoadingFragment
|
||||
import im.vector.app.features.login.LoginActivity
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class PermalinkHandlerActivity : VectorBaseActivity() {
|
||||
|
@ -45,23 +43,28 @@ class PermalinkHandlerActivity : VectorBaseActivity() {
|
|||
if (isFirstCreation()) {
|
||||
replaceFragment(R.id.simpleFragmentContainer, LoadingFragment::class.java)
|
||||
}
|
||||
handleIntent()
|
||||
}
|
||||
|
||||
private fun handleIntent() {
|
||||
// If we are not logged in, open login screen.
|
||||
// In the future, we might want to relaunch the process after login.
|
||||
if (!sessionHolder.hasActiveSession()) {
|
||||
startLoginActivity()
|
||||
return
|
||||
}
|
||||
val uri = intent.dataString
|
||||
permalinkHandler.launch(this, uri, buildTask = true)
|
||||
.delay(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { isHandled ->
|
||||
if (!isHandled) {
|
||||
toast(R.string.permalink_malformed)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
// We forward intent to HomeActivity (singleTask) to avoid the dueling app problem
|
||||
// https://stackoverflow.com/questions/25884954/deep-linking-and-multiple-app-instances
|
||||
intent.setClass(this, HomeActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
startActivity(intent)
|
||||
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
handleIntent()
|
||||
}
|
||||
|
||||
private fun startLoginActivity() {
|
||||
|
|
|
@ -36,7 +36,6 @@ import im.vector.app.core.utils.onPermissionDeniedSnackbar
|
|||
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.activity_simple.*
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import javax.inject.Inject
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
@ -72,7 +71,7 @@ class UserCodeActivity
|
|||
UserCodeState.Mode.SCAN -> showFragment(ScanUserCodeFragment::class, Bundle.EMPTY)
|
||||
is UserCodeState.Mode.RESULT -> {
|
||||
showFragment(ShowUserCodeFragment::class, Bundle.EMPTY)
|
||||
MatrixToBottomSheet.create(mode.matrixItem, this).show(supportFragmentManager, "MatrixToBottomSheet")
|
||||
MatrixToBottomSheet.withUserId(mode.matrixItem.id, this).show(supportFragmentManager, "MatrixToBottomSheet")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,8 +103,8 @@ class UserCodeActivity
|
|||
}
|
||||
}
|
||||
|
||||
override fun didTapStartMessage(matrixItem: MatrixItem) {
|
||||
sharedViewModel.handle(UserCodeActions.StartChattingWithUser(matrixItem))
|
||||
override fun navigateToRoom(roomId: String) {
|
||||
navigator.openRoom(this, roomId)
|
||||
}
|
||||
|
||||
override fun onBackPressed() = withState(sharedViewModel) {
|
||||
|
|
|
@ -30,12 +30,15 @@ import im.vector.app.features.raw.wellknown.getElementWellknown
|
|||
import im.vector.app.features.raw.wellknown.isE2EByDefault
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.raw.RawService
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
|
||||
import org.matrix.android.sdk.api.session.profile.ProfileService
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import org.matrix.android.sdk.internal.util.awaitCallback
|
||||
|
||||
|
@ -72,12 +75,12 @@ class UserCodeSharedViewModel @AssistedInject constructor(
|
|||
|
||||
override fun handle(action: UserCodeActions) {
|
||||
when (action) {
|
||||
UserCodeActions.DismissAction -> _viewEvents.post(UserCodeShareViewEvents.Dismiss)
|
||||
is UserCodeActions.SwitchMode -> setState { copy(mode = action.mode) }
|
||||
is UserCodeActions.DecodedQRCode -> handleQrCodeDecoded(action)
|
||||
is UserCodeActions.StartChattingWithUser -> handleStartChatting(action)
|
||||
UserCodeActions.DismissAction -> _viewEvents.post(UserCodeShareViewEvents.Dismiss)
|
||||
is UserCodeActions.SwitchMode -> setState { copy(mode = action.mode) }
|
||||
is UserCodeActions.DecodedQRCode -> handleQrCodeDecoded(action)
|
||||
is UserCodeActions.StartChattingWithUser -> handleStartChatting(action)
|
||||
UserCodeActions.CameraPermissionNotGranted -> _viewEvents.post(UserCodeShareViewEvents.CameraPermissionNotGranted)
|
||||
UserCodeActions.ShareByText -> handleShareByText()
|
||||
UserCodeActions.ShareByText -> handleShareByText()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,13 +142,21 @@ class UserCodeSharedViewModel @AssistedInject constructor(
|
|||
_viewEvents.post(UserCodeShareViewEvents.ShowWaitingScreen)
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
when (linkedId) {
|
||||
is PermalinkData.RoomLink -> TODO()
|
||||
is PermalinkData.UserLink -> {
|
||||
val user = session.getUser(linkedId.userId) ?: awaitCallback<List<User>> {
|
||||
session.searchUsersDirectory(linkedId.userId, 10, emptySet(), it)
|
||||
}.firstOrNull { it.userId == linkedId.userId }
|
||||
// Create raw Uxid in case the user is not searchable
|
||||
?: User(linkedId.userId, null, null)
|
||||
is PermalinkData.RoomLink -> {
|
||||
// not yet supported
|
||||
_viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.not_implemented)))
|
||||
}
|
||||
is PermalinkData.UserLink -> {
|
||||
val user = session.getUser(linkedId.userId)
|
||||
?: tryOrNull {
|
||||
awaitCallback<JsonDict> {
|
||||
session.getProfile(linkedId.userId, it)
|
||||
}
|
||||
}?.let {
|
||||
User(linkedId.userId, it[ProfileService.DISPLAY_NAME_KEY] as? String, it[ProfileService.AVATAR_URL_KEY] as? String)
|
||||
}
|
||||
// Create raw Uxid in case the user is not searchable
|
||||
?: User(linkedId.userId, null, null)
|
||||
|
||||
setState {
|
||||
copy(
|
||||
|
@ -153,8 +164,14 @@ class UserCodeSharedViewModel @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
is PermalinkData.GroupLink -> TODO()
|
||||
is PermalinkData.FallbackLink -> TODO()
|
||||
is PermalinkData.GroupLink -> {
|
||||
// not yet supported
|
||||
_viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.not_implemented)))
|
||||
}
|
||||
is PermalinkData.FallbackLink -> {
|
||||
// not yet supported
|
||||
_viewEvents.post(UserCodeShareViewEvents.ToastMessage(stringProvider.getString(R.string.not_implemented)))
|
||||
}
|
||||
}
|
||||
_viewEvents.post(UserCodeShareViewEvents.HideWaitingScreen)
|
||||
}
|
||||
|
|
|
@ -3,13 +3,24 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="200dp">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/matrixToCardContentLoading"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/matrixToCardAvatar"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin_big"
|
||||
android:elevation="4dp"
|
||||
android:transitionName="profile"
|
||||
|
@ -63,4 +74,23 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/matrixToCardUserIdText" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/matrixToCardButtonLoading"
|
||||
style="?android:attr/progressBarStyleSmall"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/matrixToCardSendMessageButton"
|
||||
app:layout_constraintEnd_toEndOf="@id/matrixToCardSendMessageButton"
|
||||
app:layout_constraintStart_toStartOf="@id/matrixToCardSendMessageButton"
|
||||
app:layout_constraintTop_toTopOf="@id/matrixToCardSendMessageButton"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/matrixToCardUserContentVisibility"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="matrixToCardAvatar,matrixToCardNameText,matrixToCardUserIdText"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
Loading…
Reference in a new issue