Benoit's review
- Cleanup - Force refresh of HomeServerCapabilities - add some doc - remove dead code - remove commented code - remove duplicated comment - use getBestName() - improve code formatting - Fix isAudioOnly parameter in jitsi url - Fix layout issue between "Active conference" banner and "Jump to first unread message banner" - Improve "Active conference" banner - Remove Calendar permission from Manifest
This commit is contained in:
parent
157f22ac2d
commit
4f8fd7b994
|
@ -3,7 +3,7 @@ Changes in Element 1.0.5 (2020-XX-XX)
|
|||
|
||||
Features ✨:
|
||||
- Protect access to the app by a pin code (#1700)
|
||||
- Conference with Jitsi support (#43)
|
||||
- Conference with Jitsi support (#43)
|
||||
|
||||
Improvements 🙌:
|
||||
- Give user the possibility to prevent accidental call (#1869)
|
||||
|
|
|
@ -137,7 +137,7 @@ dependencies {
|
|||
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.8.1"))
|
||||
implementation 'com.squareup.okhttp3:okhttp'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor'
|
||||
implementation("com.squareup.okhttp3:okhttp-urlconnection")
|
||||
implementation 'com.squareup.okhttp3:okhttp-urlconnection'
|
||||
|
||||
implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
|
||||
|
|
|
@ -74,9 +74,7 @@ data class E2EWellKnownConfig(
|
|||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class WellKnownPreferredConfig {
|
||||
|
||||
@JvmField
|
||||
@Json(name = "preferredDomain")
|
||||
var preferredDomain: String? = null
|
||||
}
|
||||
data class WellKnownPreferredConfig(
|
||||
@Json(name = "preferredDomain")
|
||||
val preferredDomain: String? = null
|
||||
)
|
||||
|
|
|
@ -39,7 +39,9 @@ data class HomeServerCapabilities(
|
|||
* (as it was before) for various environments where this is desired.
|
||||
*/
|
||||
val adminE2EByDefault: Boolean = true,
|
||||
|
||||
/**
|
||||
* Preferred Jitsi domain, provided in Wellknown
|
||||
*/
|
||||
val preferredJitsiDomain: String? = null
|
||||
) {
|
||||
companion object {
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.database
|
||||
|
||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||
import io.realm.DynamicRealm
|
||||
import io.realm.RealmMigration
|
||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -55,8 +55,12 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration {
|
|||
}
|
||||
|
||||
private fun migrateTo3(realm: DynamicRealm) {
|
||||
Timber.d("Step 1 -> 2")
|
||||
Timber.d("Step 2 -> 3")
|
||||
realm.schema.get("HomeServerCapabilitiesEntity")
|
||||
?.addField(HomeServerCapabilitiesEntityFields.PREFERRED_JITSI_DOMAIN, String::class.java)
|
||||
?.transform { obj ->
|
||||
// Schedule a refresh of the capabilities
|
||||
obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,14 @@
|
|||
<!-- Needed for incoming calls -->
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
|
||||
<!-- Jitsi libs adds CALENDAR permissions, but we can remove them safely according to https://github.com/jitsi/jitsi-meet/issues/4068#issuecomment-480482481 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_CALENDAR"
|
||||
tools:node="remove" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_CALENDAR"
|
||||
tools:node="remove" />
|
||||
|
||||
<!-- Adding CAMERA permission prevents Chromebooks to see the application on the PlayStore -->
|
||||
<!-- Tell that the Camera is not mandatory to install the application -->
|
||||
<uses-feature
|
||||
|
|
|
@ -36,7 +36,7 @@ abstract class GenericButtonItem : VectorEpoxyModel<GenericButtonItem.Holder>()
|
|||
var text: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var itemClickAction: View.OnClickListener? = null
|
||||
var buttonClickAction: View.OnClickListener? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
@ColorInt
|
||||
|
@ -57,7 +57,7 @@ abstract class GenericButtonItem : VectorEpoxyModel<GenericButtonItem.Holder>()
|
|||
holder.button.icon = null
|
||||
}
|
||||
|
||||
itemClickAction?.let { holder.button.setOnClickListener(it) }
|
||||
buttonClickAction?.let { holder.button.setOnClickListener(it) }
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
|
|
|
@ -92,7 +92,7 @@ class ActiveConferenceView @JvmOverloads constructor(
|
|||
val summary = state.asyncRoomSummary()
|
||||
if (summary?.membership == Membership.JOIN) {
|
||||
// We only display banner for 'live' widgets
|
||||
val activeConf = // for now only jitsi?
|
||||
val activeConf =
|
||||
state.activeRoomWidgets()?.firstOrNull {
|
||||
// for now only jitsi?
|
||||
it.type == WidgetType.Jitsi
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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.call.conference
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
|
||||
sealed class JitsiCallViewActions : VectorViewModelAction
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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.call.conference
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
|
||||
sealed class JitsiCallViewEvents : VectorViewEvents
|
|
@ -23,11 +23,8 @@ import com.airbnb.mvrx.Success
|
|||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
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 im.vector.app.features.call.WebRtcPeerConnectionManager
|
||||
import org.jitsi.meet.sdk.JitsiMeetUserInfo
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -36,16 +33,11 @@ import org.matrix.android.sdk.api.util.toMatrixItem
|
|||
import org.matrix.android.sdk.rx.asObservable
|
||||
import java.net.URL
|
||||
|
||||
sealed class JitsiCallViewActions : VectorViewModelAction
|
||||
|
||||
sealed class JitsiCallViewEvents : VectorViewEvents
|
||||
|
||||
class JitsiCallViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: JitsiCallViewState,
|
||||
@Assisted val args: VectorJitsiActivity.Args,
|
||||
val session: Session,
|
||||
val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
|
||||
val stringProvider: StringProvider
|
||||
private val session: Session,
|
||||
private val stringProvider: StringProvider
|
||||
) : VectorViewModel<JitsiCallViewState, JitsiCallViewActions, JitsiCallViewEvents>(initialState) {
|
||||
|
||||
@AssistedInject.Factory
|
||||
|
@ -56,7 +48,7 @@ class JitsiCallViewModel @AssistedInject constructor(
|
|||
init {
|
||||
val me = session.getUser(session.myUserId)?.toMatrixItem()
|
||||
val userInfo = JitsiMeetUserInfo().apply {
|
||||
displayName = me?.displayName
|
||||
displayName = me?.getBestName()
|
||||
avatar = me?.avatarUrl?.let { session.contentUrlResolver().resolveFullSize(it) }?.let { URL(it) }
|
||||
}
|
||||
val roomName = session.getRoomSummary(args.roomId)?.displayName
|
||||
|
@ -73,7 +65,7 @@ class JitsiCallViewModel @AssistedInject constructor(
|
|||
if (jitsiWidget != null) {
|
||||
val uri = Uri.parse(jitsiWidget.computedUrl)
|
||||
val confId = uri.getQueryParameter("confId")
|
||||
val ppt = jitsiWidget.computedUrl?.let { JitsiWidgetProperties(it, stringProvider) }
|
||||
val ppt = jitsiWidget.computedUrl?.let { url -> JitsiWidgetProperties(url, stringProvider) }
|
||||
setState {
|
||||
copy(
|
||||
widget = Success(jitsiWidget),
|
||||
|
@ -89,7 +81,8 @@ class JitsiCallViewModel @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
}.disposeOnClear()
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
override fun handle(action: JitsiCallViewActions) {
|
||||
|
@ -108,7 +101,6 @@ class JitsiCallViewModel @AssistedInject constructor(
|
|||
|
||||
override fun initialState(viewModelContext: ViewModelContext): JitsiCallViewState? {
|
||||
val args: VectorJitsiActivity.Args = viewModelContext.args()
|
||||
// val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession()
|
||||
|
||||
return JitsiCallViewState(
|
||||
roomId = args.roomId,
|
||||
|
|
|
@ -55,7 +55,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji
|
|||
|
||||
@Inject lateinit var viewModelFactory: JitsiCallViewModel.Factory
|
||||
|
||||
var jitsiMeetView: JitsiMeetView? = null
|
||||
private var jitsiMeetView: JitsiMeetView? = null
|
||||
|
||||
private val jitsiViewModel: JitsiCallViewModel by viewModel()
|
||||
|
||||
|
|
|
@ -82,7 +82,8 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
|||
object SelectStickerAttachment : RoomDetailAction()
|
||||
object OpenIntegrationManager: RoomDetailAction()
|
||||
object ManageIntegrations: RoomDetailAction()
|
||||
data class AddJitsiWidget(val video: Boolean): RoomDetailAction()
|
||||
data class AddJitsiWidget(val withVideo: Boolean): RoomDetailAction()
|
||||
data class RemoveWidget(val widgetId: String): RoomDetailAction()
|
||||
data class EnsureNativeWidgetAllowed(val widget: Widget, val grantedEvents: RoomDetailViewEvents) : RoomDetailAction()
|
||||
data class EnsureNativeWidgetAllowed(val widget: Widget,
|
||||
val grantedEvents: RoomDetailViewEvents) : RoomDetailAction()
|
||||
}
|
||||
|
|
|
@ -154,6 +154,14 @@ import im.vector.app.features.widgets.WidgetActivity
|
|||
import im.vector.app.features.widgets.WidgetArgs
|
||||
import im.vector.app.features.widgets.WidgetKind
|
||||
import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
||||
import kotlinx.android.synthetic.main.merge_composer_layout.view.*
|
||||
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
||||
import org.billcarsonfr.jsonviewer.JSonViewerDialog
|
||||
import org.commonmark.parser.Parser
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.permalinks.PermalinkFactory
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
@ -176,21 +184,13 @@ import org.matrix.android.sdk.api.session.room.send.SendState
|
|||
import org.matrix.android.sdk.api.session.room.timeline.Timeline
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import org.matrix.android.sdk.internal.crypto.attachments.toElementToDecrypt
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
||||
import kotlinx.android.synthetic.main.merge_composer_layout.view.*
|
||||
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
||||
import org.billcarsonfr.jsonviewer.JSonViewerDialog
|
||||
import org.commonmark.parser.Parser
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
@ -370,24 +370,24 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
private fun requestNativeWidgetPermission(it: RoomDetailViewEvents.RequestNativeWidgetPermission) {
|
||||
val tag = RoomWidgetPermissionBottomSheet::class.java.name
|
||||
val dFrag = childFragmentManager
|
||||
.findFragmentByTag(tag) as? RoomWidgetPermissionBottomSheet
|
||||
val dFrag = childFragmentManager.findFragmentByTag(tag) as? RoomWidgetPermissionBottomSheet
|
||||
if (dFrag != null && dFrag.dialog?.isShowing == true && !dFrag.isRemoving) {
|
||||
return
|
||||
} else {
|
||||
RoomWidgetPermissionBottomSheet
|
||||
.newInstance(WidgetArgs(
|
||||
RoomWidgetPermissionBottomSheet.newInstance(
|
||||
WidgetArgs(
|
||||
baseUrl = it.domain,
|
||||
kind = WidgetKind.ROOM,
|
||||
roomId = roomDetailArgs.roomId,
|
||||
widgetId = it.widget.widgetId
|
||||
)).apply {
|
||||
directListener = { granted ->
|
||||
if (granted) {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnsureNativeWidgetAllowed(it.widget, it.grantedEvents))
|
||||
}
|
||||
}
|
||||
)
|
||||
).apply {
|
||||
directListener = { granted ->
|
||||
if (granted) {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnsureNativeWidgetAllowed(it.widget, it.grantedEvents))
|
||||
}
|
||||
}
|
||||
}
|
||||
.show(childFragmentManager, tag)
|
||||
}
|
||||
}
|
||||
|
@ -592,7 +592,8 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
menu.findItem(R.id.open_matrix_apps).let { menuItem ->
|
||||
// We use a custom layout for this menu item, so we need to set a ClickListener
|
||||
menu.findItem(R.id.open_matrix_apps)?.let { menuItem ->
|
||||
menuItem.actionView.setOnClickListener {
|
||||
onOptionsItemSelected(menuItem)
|
||||
}
|
||||
|
@ -604,24 +605,23 @@ class RoomDetailFragment @Inject constructor(
|
|||
it.isVisible = roomDetailViewModel.isMenuItemVisible(it.itemId)
|
||||
}
|
||||
withState(roomDetailViewModel) { state ->
|
||||
val findItem = menu.findItem(R.id.open_matrix_apps)
|
||||
val widgetsCount = state.activeRoomWidgets.invoke()?.size
|
||||
if (widgetsCount ?: 0 > 0) {
|
||||
val actionView = findItem.actionView
|
||||
val matrixAppsMenuItem = menu.findItem(R.id.open_matrix_apps)
|
||||
val widgetsCount = state.activeRoomWidgets.invoke()?.size ?: 0
|
||||
if (widgetsCount > 0) {
|
||||
val actionView = matrixAppsMenuItem.actionView
|
||||
actionView
|
||||
.findViewById<ImageView>(R.id.action_view_icon_image)
|
||||
.setColorFilter(ContextCompat.getColor(requireContext(), R.color.riotx_accent))
|
||||
actionView.findViewById<TextView>(R.id.cart_badge).isVisible = true
|
||||
actionView.findViewById<TextView>(R.id.cart_badge).text = "$widgetsCount"
|
||||
findItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
|
||||
actionView.findViewById<TextView>(R.id.cart_badge).setTextOrHide("$widgetsCount")
|
||||
matrixAppsMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
|
||||
} else {
|
||||
// icon should be default color no badge
|
||||
val actionView = findItem.actionView
|
||||
val actionView = matrixAppsMenuItem.actionView
|
||||
actionView
|
||||
.findViewById<ImageView>(R.id.action_view_icon_image)
|
||||
.setColorFilter(ThemeUtils.getColor(requireContext(), R.attr.riotx_text_secondary))
|
||||
actionView.findViewById<TextView>(R.id.cart_badge).isVisible = false
|
||||
findItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
|
||||
matrixAppsMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -646,6 +646,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
R.id.voice_call,
|
||||
R.id.video_call -> {
|
||||
handleCallRequest(item)
|
||||
true
|
||||
}
|
||||
R.id.hangup_call -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EndCall)
|
||||
|
@ -655,10 +656,10 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleCallRequest(item: MenuItem): Boolean = withState(roomDetailViewModel) { state ->
|
||||
val roomSummary = state.asyncRoomSummary.invoke() ?: return@withState true
|
||||
private fun handleCallRequest(item: MenuItem) = withState(roomDetailViewModel) { state ->
|
||||
val roomSummary = state.asyncRoomSummary.invoke() ?: return@withState
|
||||
val isVideoCall = item.itemId == R.id.video_call
|
||||
return@withState when (roomSummary.joinedMembersCount) {
|
||||
when (roomSummary.joinedMembersCount) {
|
||||
1 -> {
|
||||
val pendingInvite = roomSummary.invitedMembersCount ?: 0 > 0
|
||||
if (pendingInvite) {
|
||||
|
@ -668,7 +669,6 @@ class RoomDetailFragment @Inject constructor(
|
|||
// You cannot place a call with yourself.
|
||||
showDialogWithMessage(getString(R.string.cannot_call_yourself))
|
||||
}
|
||||
true
|
||||
}
|
||||
2 -> {
|
||||
val activeCall = sharedCallActionViewModel.activeCall.value
|
||||
|
@ -685,7 +685,6 @@ class RoomDetailFragment @Inject constructor(
|
|||
} else {
|
||||
safeStartCall(isVideoCall)
|
||||
}
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
// it's jitsi call
|
||||
|
@ -709,7 +708,6 @@ class RoomDetailFragment @Inject constructor(
|
|||
.show()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1725,10 +1723,6 @@ class RoomDetailFragment @Inject constructor(
|
|||
.show()
|
||||
}
|
||||
|
||||
// private fun joinCurrentJitsiCall(withVideo: Boolean) {
|
||||
//
|
||||
// }
|
||||
|
||||
// VectorInviteView.Callback
|
||||
|
||||
override fun onAcceptInvite() {
|
||||
|
|
|
@ -72,7 +72,9 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
|
|||
|
||||
object OpenIntegrationManager: RoomDetailViewEvents()
|
||||
object OpenActiveWidgetBottomSheet: RoomDetailViewEvents()
|
||||
data class RequestNativeWidgetPermission(val widget: Widget, val domain: String, val grantedEvents: RoomDetailViewEvents) : RoomDetailViewEvents()
|
||||
data class RequestNativeWidgetPermission(val widget: Widget,
|
||||
val domain: String,
|
||||
val grantedEvents: RoomDetailViewEvents) : RoomDetailViewEvents()
|
||||
|
||||
object MessageSent : SendMessageResult()
|
||||
data class JoinRoomCommandSuccess(val roomId: String) : SendMessageResult()
|
||||
|
|
|
@ -332,15 +332,9 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
private fun handleAddJitsiConference(action: RoomDetailAction.AddJitsiWidget) {
|
||||
_viewEvents.post(RoomDetailViewEvents.ShowWaitingView)
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
// Build data for a jitsi widget
|
||||
|
||||
// Build data for a jitsi widget
|
||||
val widgetId: String = WidgetType.Jitsi.preferred + "_" + session.myUserId + "_" + System.currentTimeMillis()
|
||||
|
||||
// Create a random enough jitsi conference id
|
||||
// Note: the jitsi server automatically creates conference when the conference
|
||||
// id does not exist yet
|
||||
|
||||
// Create a random enough jitsi conference id
|
||||
// Note: the jitsi server automatically creates conference when the conference
|
||||
// id does not exist yet
|
||||
|
@ -356,9 +350,14 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
|
||||
// We use the default element wrapper for this widget
|
||||
// https://github.com/vector-im/element-web/blob/develop/docs/jitsi-dev.md
|
||||
val url = "https://app.element.io/jitsi.html?" +
|
||||
"confId=$confId#conferenceDomain=\$domain&conferenceId=\$conferenceId&isAudioOnly=${action.video}" +
|
||||
"&displayName=\$matrix_display_name&avatarUrl=\$matrix_avatar_url&userId=\$matrix_user_id"
|
||||
val url = "https://app.element.io/jitsi.html" +
|
||||
"?confId=$confId" +
|
||||
"#conferenceDomain=\$domain" +
|
||||
"&conferenceId=\$conferenceId" +
|
||||
"&isAudioOnly=${!action.withVideo}" +
|
||||
"&displayName=\$matrix_display_name" +
|
||||
"&avatarUrl=\$matrix_avatar_url" +
|
||||
"&userId=\$matrix_user_id"
|
||||
|
||||
val widgetEventContent = mapOf(
|
||||
"url" to url,
|
||||
|
@ -366,7 +365,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
"data" to mapOf(
|
||||
"conferenceId" to confId,
|
||||
"domain" to jitsiDomain,
|
||||
"isAudioOnly" to !action.video
|
||||
"isAudioOnly" to !action.withVideo
|
||||
),
|
||||
"creatorUserId" to session.myUserId,
|
||||
"id" to widgetId,
|
||||
|
@ -377,7 +376,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
val widget = awaitCallback<Widget> {
|
||||
session.widgetService().createRoomWidget(roomId, widgetId, widgetEventContent, it)
|
||||
}
|
||||
_viewEvents.post(RoomDetailViewEvents.JoinJitsiConference(widget, action.video))
|
||||
_viewEvents.post(RoomDetailViewEvents.JoinJitsiConference(widget, action.withVideo))
|
||||
} catch (failure: Throwable) {
|
||||
_viewEvents.post(RoomDetailViewEvents.ShowMessage(stringProvider.getString(R.string.failed_to_add_widget)))
|
||||
} finally {
|
||||
|
|
|
@ -38,9 +38,9 @@ import javax.inject.Inject
|
|||
/**
|
||||
* Bottom sheet displaying active widgets in a room
|
||||
*/
|
||||
class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidgetController.Listener {
|
||||
class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidgetsController.Listener {
|
||||
|
||||
@Inject lateinit var epoxyController: RoomWidgetController
|
||||
@Inject lateinit var epoxyController: RoomWidgetsController
|
||||
@Inject lateinit var colorProvider: ColorProvider
|
||||
@Inject lateinit var navigator: Navigator
|
||||
|
||||
|
|
|
@ -29,7 +29,10 @@ import javax.inject.Inject
|
|||
/**
|
||||
* Epoxy controller for room widgets list
|
||||
*/
|
||||
class RoomWidgetController @Inject constructor(val stringProvider: StringProvider, val colorProvider: ColorProvider) : TypedEpoxyController<List<Widget>>() {
|
||||
class RoomWidgetsController @Inject constructor(
|
||||
val stringProvider: StringProvider,
|
||||
val colorProvider: ColorProvider)
|
||||
: TypedEpoxyController<List<Widget>>() {
|
||||
|
||||
var listener: Listener? = null
|
||||
|
||||
|
@ -41,18 +44,18 @@ class RoomWidgetController @Inject constructor(val stringProvider: StringProvide
|
|||
}
|
||||
} else {
|
||||
widgets.forEach {
|
||||
RoomWidgetItem_()
|
||||
.id(it.widgetId)
|
||||
.widget(it)
|
||||
.widgetClicked { listener?.didSelectWidget(it) }
|
||||
.addTo(this)
|
||||
roomWidgetItem {
|
||||
id(it.widgetId)
|
||||
widget(it)
|
||||
widgetClicked { listener?.didSelectWidget(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
genericButtonItem {
|
||||
id("addIntegration")
|
||||
text(stringProvider.getString(R.string.room_manage_integrations))
|
||||
textColor(colorProvider.getColor(R.color.riotx_accent))
|
||||
itemClickAction(View.OnClickListener { listener?.didSelectManageWidgets() })
|
||||
buttonClickAction(View.OnClickListener { listener?.didSelectManageWidgets() })
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ class DevicesController @Inject constructor(private val errorFormatter: ErrorFor
|
|||
// id("complete_security")
|
||||
// iconRes(R.drawable.ic_shield_warning)
|
||||
// text(stringProvider.getString(R.string.complete_security))
|
||||
// itemClickAction(DebouncedClickListener(View.OnClickListener { _ ->
|
||||
// buttonClickAction(DebouncedClickListener(View.OnClickListener { _ ->
|
||||
// callback?.completeSecurity()
|
||||
// }))
|
||||
// }
|
||||
|
|
|
@ -48,7 +48,7 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
injector.inject(this)
|
||||
}
|
||||
|
||||
// Use this if you don't need to full activity view model
|
||||
// Use this if you don't need the full activity view model
|
||||
var directListener: ((Boolean) -> Unit)? = null
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
|
@ -91,16 +91,16 @@ class RoomWidgetPermissionBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
@OnClick(R.id.widgetPermissionDecline)
|
||||
fun doDecline() {
|
||||
viewModel.handle(RoomWidgetPermissionActions.BlockWidget)
|
||||
// optimistic dismiss
|
||||
directListener?.invoke(false)
|
||||
// optimistic dismiss
|
||||
dismiss()
|
||||
}
|
||||
|
||||
@OnClick(R.id.widgetPermissionContinue)
|
||||
fun doAccept() {
|
||||
viewModel.handle(RoomWidgetPermissionActions.AllowWidget)
|
||||
// optimistic dismiss
|
||||
directListener?.invoke(true)
|
||||
// optimistic dismiss
|
||||
dismiss()
|
||||
}
|
||||
|
||||
|
|
|
@ -129,17 +129,17 @@
|
|||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/activeCallView">
|
||||
app:layout_constraintTop_toBottomOf="@id/activeConferenceView">
|
||||
|
||||
<!-- <im.vector.app.features.home.room.detail.widget.RoomWidgetsBannerView-->
|
||||
<!-- android:id="@+id/roomWidgetsBannerView"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_marginStart="8dp"-->
|
||||
<!-- android:layout_marginTop="8dp"-->
|
||||
<!-- android:layout_marginEnd="8dp"-->
|
||||
<!-- android:visibility="gone"-->
|
||||
<!-- tools:visibility="visible" />-->
|
||||
<!-- <im.vector.app.features.home.room.detail.widget.RoomWidgetsBannerView-->
|
||||
<!-- android:id="@+id/roomWidgetsBannerView"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_marginStart="8dp"-->
|
||||
<!-- android:layout_marginTop="8dp"-->
|
||||
<!-- android:layout_marginEnd="8dp"-->
|
||||
<!-- android:visibility="gone"-->
|
||||
<!-- tools:visibility="visible" />-->
|
||||
|
||||
<im.vector.app.core.ui.views.JumpToReadMarkerView
|
||||
android:id="@+id/jumpToReadMarkerView"
|
||||
|
@ -198,7 +198,7 @@
|
|||
android:focusable="true"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/activeCallView">
|
||||
app:layout_constraintTop_toBottomOf="@id/activeConferenceView">
|
||||
|
||||
<org.webrtc.SurfaceViewRenderer
|
||||
android:id="@+id/activeCallPiP"
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="64dp"
|
||||
|
@ -14,36 +13,35 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/roomWidgetAvatar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
app:layout_constraintStart_toEndOf="@id/roomWidgetAvatar"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/roomWidgetUrl"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:id="@+id/roomWidgetName"
|
||||
style="@style/BottomSheetItemTextMain"
|
||||
tools:text="@sample/matrix.json/data/displayName" />
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/roomWidgetUrl"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/roomWidgetAvatar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="Widget name" />
|
||||
|
||||
|
||||
<TextView
|
||||
app:layout_constraintStart_toStartOf="@id/roomWidgetName"
|
||||
app:layout_constraintEnd_toEndOf="@id/roomWidgetName"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomWidgetName"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:textStyle="normal"
|
||||
android:id="@+id/roomWidgetUrl"
|
||||
style="@style/BottomSheetItemTextSecondary"
|
||||
android:textStyle="normal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/roomWidgetName"
|
||||
app:layout_constraintStart_toStartOf="@id/roomWidgetName"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomWidgetName"
|
||||
tools:text="https://foobar" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -25,8 +25,9 @@
|
|||
android:textColor="@color/white"
|
||||
app:drawableTint="@color/white" />
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/returnToCallButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/activeCallInfo"
|
||||
|
@ -38,7 +39,6 @@
|
|||
android:paddingStart="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/return_to_call"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?colorPrimary"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
tools:parentTag="android.widget.RelativeLayout">
|
||||
|
||||
<TextView
|
||||
|
@ -13,7 +12,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toStartOf="@id/deleteWidgetButton"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:drawableStart="@drawable/ic_call"
|
||||
android:drawablePadding="10dp"
|
||||
android:gravity="center_vertical"
|
||||
|
@ -26,8 +24,9 @@
|
|||
app:drawableTint="@color/white"
|
||||
tools:text="@string/ongoing_conference_call" />
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/deleteWidgetButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/activeConferenceInfo"
|
||||
|
@ -39,7 +38,6 @@
|
|||
android:paddingStart="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/action_close"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
<string name="conference_call_in_progress">A conference is already in progress!</string>
|
||||
<string name="video_meeting">Start video meeting</string>
|
||||
<string name="audio_meeting">Start audio meeting</string>
|
||||
<string name="audio_video_meeting_description">Meetings use Jitsi security and permission policies. All people currently in the room will see an invite to join while your meeting is happening.</string>
|
||||
<string name="audio_video_meeting_description">Meetings use Jitsi security and permission policies. All people currently in the room will see an invite to join while your meeting is happening.</string>
|
||||
<string name="missing_permissions_title_to_start_conf_call">Cannot start call</string>
|
||||
<string name="cannot_call_yourself">You cannot place a call with yourself</string>
|
||||
<string name="cannot_call_yourself_with_invite">You cannot place a call with yourself, wait for participants to accept invitation</string>
|
||||
|
|
Loading…
Reference in New Issue