Initial commit jitsi
This commit is contained in:
parent
5a3894036c
commit
42a24300a1
|
@ -14,6 +14,7 @@
|
|||
<w>gplay</w>
|
||||
<w>hmac</w>
|
||||
<w>homeserver</w>
|
||||
<w>jitsi</w>
|
||||
<w>ktlint</w>
|
||||
<w>linkified</w>
|
||||
<w>linkify</w>
|
||||
|
|
|
@ -52,6 +52,10 @@ allprojects {
|
|||
}
|
||||
}
|
||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
|
||||
// Jitsi repo
|
||||
maven {
|
||||
url "https://github.com/vector-im/jitsi_libre_maven/raw/master/releases"
|
||||
}
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
|
|
@ -132,8 +132,13 @@ dependencies {
|
|||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||
implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"
|
||||
implementation "com.squareup.retrofit2:converter-scalars:$retrofit_version"
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.2.2'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:4.2.2'
|
||||
|
||||
|
||||
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.moshi:moshi-adapters:$moshi_version"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
|
||||
|
||||
|
@ -175,7 +180,9 @@ dependencies {
|
|||
|
||||
// Web RTC
|
||||
// TODO meant for development purposes only. See http://webrtc.github.io/webrtc-org/native-code/android/
|
||||
implementation 'org.webrtc:google-webrtc:1.0.+'
|
||||
// implementation 'org.webrtc:google-webrtc:1.0.+'
|
||||
// WebRTC
|
||||
implementation('com.facebook.react:react-native-webrtc:1.69.2-jitsi-2062090@aar')
|
||||
|
||||
debugImplementation 'com.airbnb.okreplay:okreplay:1.5.0'
|
||||
releaseImplementation 'com.airbnb.okreplay:noop:1.5.0'
|
||||
|
|
|
@ -77,7 +77,11 @@ internal object NetworkModule {
|
|||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(60, TimeUnit.SECONDS)
|
||||
.writeTimeout(60, TimeUnit.SECONDS)
|
||||
.addNetworkInterceptor(stethoInterceptor)
|
||||
.apply {
|
||||
if (BuildConfig.DEBUG) {
|
||||
addNetworkInterceptor(stethoInterceptor)
|
||||
}
|
||||
}
|
||||
.addInterceptor(timeoutInterceptor)
|
||||
.addInterceptor(userAgentInterceptor)
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
|
|
|
@ -406,7 +406,10 @@ dependencies {
|
|||
implementation 'com.github.BillCarsonFr:JsonViewer:0.5'
|
||||
|
||||
// TODO meant for development purposes only
|
||||
implementation 'org.webrtc:google-webrtc:1.0.+'
|
||||
// implementation 'org.webrtc:google-webrtc:1.0.+'
|
||||
// WebRTC
|
||||
// implementation('com.facebook.react:react-native-webrtc:1.69.2-jitsi-2062090@aar')
|
||||
implementation('org.jitsi.react:jitsi-meet-sdk:2.2.2') { transitive = true }
|
||||
|
||||
// QR-code
|
||||
// Stick to 3.3.3 because of https://github.com/zxing/zxing/issues/1170
|
||||
|
|
|
@ -24,3 +24,44 @@
|
|||
|
||||
## print all the rules in a file
|
||||
# -printconfiguration ../proguard_files/full-r8-config.txt
|
||||
|
||||
# WebRTC
|
||||
|
||||
-keep class org.webrtc.** { *; }
|
||||
-dontwarn org.chromium.build.BuildHooksAndroid
|
||||
|
||||
# Jitsi (else callbacks are not called)
|
||||
|
||||
-keep class org.jitsi.meet.** { *; }
|
||||
-keep class org.jitsi.meet.sdk.** { *; }
|
||||
|
||||
# React Native
|
||||
|
||||
# Keep our interfaces so they can be used by other ProGuard rules.
|
||||
# See http://sourceforge.net/p/proguard/bugs/466/
|
||||
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
|
||||
-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
|
||||
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
|
||||
|
||||
# Do not strip any method/class that is annotated with @DoNotStrip
|
||||
-keep @com.facebook.proguard.annotations.DoNotStrip class *
|
||||
-keep @com.facebook.common.internal.DoNotStrip class *
|
||||
-keepclassmembers class * {
|
||||
@com.facebook.proguard.annotations.DoNotStrip *;
|
||||
@com.facebook.common.internal.DoNotStrip *;
|
||||
}
|
||||
|
||||
-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
|
||||
void set*(***);
|
||||
*** get*();
|
||||
}
|
||||
|
||||
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
|
||||
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
|
||||
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
|
||||
-keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
|
||||
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
|
||||
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
|
||||
|
||||
-dontwarn com.facebook.react.**
|
||||
-keep,includedescriptorclasses class com.facebook.react.bridge.** { *; }
|
|
@ -202,6 +202,9 @@
|
|||
android:name="im.vector.app.features.attachments.preview.AttachmentsPreviewActivity"
|
||||
android:theme="@style/AppTheme.AttachmentsPreview" />
|
||||
<activity android:name="im.vector.app.features.call.VectorCallActivity" />
|
||||
<activity
|
||||
android:name="im.vector.app.features.call.conference.VectorJitsiActivity"
|
||||
android:configChanges="orientation|screenSize" />
|
||||
|
||||
<activity android:name="im.vector.app.features.terms.ReviewTermsActivity" />
|
||||
<activity android:name="im.vector.app.features.widgets.WidgetActivity" />
|
||||
|
|
|
@ -27,6 +27,7 @@ import im.vector.app.core.preference.UserAvatarPreference
|
|||
import im.vector.app.features.MainActivity
|
||||
import im.vector.app.features.call.CallControlsBottomSheet
|
||||
import im.vector.app.features.call.VectorCallActivity
|
||||
import im.vector.app.features.call.conference.VectorJitsiActivity
|
||||
import im.vector.app.features.createdirect.CreateDirectRoomActivity
|
||||
import im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
||||
import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
|
||||
|
@ -140,6 +141,7 @@ interface ScreenComponent {
|
|||
fun inject(activity: WidgetActivity)
|
||||
fun inject(activity: VectorCallActivity)
|
||||
fun inject(activity: VectorAttachmentViewerActivity)
|
||||
fun inject(activity: VectorJitsiActivity)
|
||||
|
||||
/* ==========================================================================================
|
||||
* BottomSheets
|
||||
|
|
|
@ -57,7 +57,7 @@ abstract class GenericButtonItem : VectorEpoxyModel<GenericButtonItem.Holder>()
|
|||
holder.button.icon = null
|
||||
}
|
||||
|
||||
itemClickAction?.let { holder.view.setOnClickListener(it) }
|
||||
itemClickAction?.let { holder.button.setOnClickListener(it) }
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.core.ui.views
|
||||
|
||||
import android.content.Context
|
||||
import android.text.SpannableString
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.style.ClickableSpan
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.utils.tappableMatchingText
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
|
||||
class ActiveConferenceView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : RelativeLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
interface Callback {
|
||||
fun onTapJoinAudio(jitsiWidget: Widget)
|
||||
fun onTapJoinVideo(jitsiWidget: Widget)
|
||||
}
|
||||
|
||||
var callback: Callback? = null
|
||||
var jitsiWidget: Widget? = null
|
||||
|
||||
init {
|
||||
setupView()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
inflate(context, R.layout.view_active_conference_view, this)
|
||||
setBackgroundColor(ThemeUtils.getColor(context, R.attr.colorPrimary))
|
||||
|
||||
// "voice" and "video" texts are underlined and clickable
|
||||
val voiceString = context.getString(R.string.ongoing_conference_call_voice)
|
||||
val videoString = context.getString(R.string.ongoing_conference_call_video)
|
||||
|
||||
val fullMessage = context.getString(R.string.ongoing_conference_call, voiceString, videoString)
|
||||
|
||||
val styledText = SpannableString(fullMessage)
|
||||
styledText.tappableMatchingText(voiceString, object : ClickableSpan() {
|
||||
override fun onClick(widget: View) {
|
||||
jitsiWidget?.let {
|
||||
callback?.onTapJoinAudio(it)
|
||||
}
|
||||
}
|
||||
})
|
||||
styledText.tappableMatchingText(videoString, object : ClickableSpan() {
|
||||
override fun onClick(widget: View) {
|
||||
jitsiWidget?.let {
|
||||
callback?.onTapJoinVideo(it)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
findViewById<TextView>(R.id.activeConferenceInfo).apply {
|
||||
text = styledText
|
||||
movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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 android.net.Uri
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
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.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
|
||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||
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
|
||||
) : VectorViewModel<JitsiCallViewState, JitsiCallViewActions, JitsiCallViewEvents>(initialState) {
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface Factory {
|
||||
fun create(initialState: JitsiCallViewState, args: VectorJitsiActivity.Args): JitsiCallViewModel
|
||||
}
|
||||
|
||||
init {
|
||||
val me = session.getUser(session.myUserId)?.toMatrixItem()
|
||||
val userInfo = JitsiMeetUserInfo().apply {
|
||||
displayName = me?.displayName
|
||||
avatar = me?.avatarUrl?.let { session.contentUrlResolver().resolveFullSize(it) }?.let { URL(it) }
|
||||
}
|
||||
val roomName = session.getRoomSummary(args.roomId)?.displayName
|
||||
|
||||
setState {
|
||||
copy(userInfo = userInfo)
|
||||
}
|
||||
|
||||
session.widgetService().getRoomWidgetsLive(args.roomId, QueryStringValue.Equals(args.widgetId), WidgetType.Jitsi.values())
|
||||
.asObservable()
|
||||
.distinctUntilChanged()
|
||||
.subscribe {
|
||||
val jitsiWidget = it.firstOrNull()
|
||||
if (jitsiWidget != null) {
|
||||
val uri = Uri.parse(jitsiWidget.computedUrl)
|
||||
val confId = uri.getQueryParameter("confId")
|
||||
val ppt = jitsiWidget.computedUrl?.let { JitsiWidgetProperties(it) }
|
||||
setState {
|
||||
copy(
|
||||
widget = Success(jitsiWidget),
|
||||
jitsiUrl = "https://${ppt?.domain}",
|
||||
confId = confId ?: "",
|
||||
subject = roomName ?: ""
|
||||
)
|
||||
}
|
||||
} else {
|
||||
setState {
|
||||
copy(
|
||||
widget = Fail(IllegalArgumentException("Widget not found"))
|
||||
)
|
||||
}
|
||||
}
|
||||
}.disposeOnClear()
|
||||
}
|
||||
|
||||
override fun handle(action: JitsiCallViewActions) {
|
||||
}
|
||||
|
||||
companion object : MvRxViewModelFactory<JitsiCallViewModel, JitsiCallViewState> {
|
||||
|
||||
const val ENABLE_VIDEO_OPTION = "ENABLE_VIDEO_OPTION"
|
||||
|
||||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: JitsiCallViewState): JitsiCallViewModel? {
|
||||
val callActivity: VectorJitsiActivity = viewModelContext.activity()
|
||||
val callArgs: VectorJitsiActivity.Args = viewModelContext.args()
|
||||
return callActivity.viewModelFactory.create(state, callArgs)
|
||||
}
|
||||
|
||||
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,
|
||||
widgetId = args.widgetId,
|
||||
enableVideo = args.enableVideo
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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 com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import org.jitsi.meet.sdk.JitsiMeetUserInfo
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
|
||||
data class JitsiCallViewState(
|
||||
val roomId: String = "",
|
||||
val widgetId: String = "",
|
||||
val enableVideo: Boolean = true,
|
||||
val jitsiUrl: String = "",
|
||||
val subject: String = "",
|
||||
val confId: String = "",
|
||||
val userInfo: JitsiMeetUserInfo = JitsiMeetUserInfo(),
|
||||
val widget: Async<Widget> = Uninitialized
|
||||
) : MvRxState
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 android.net.Uri
|
||||
|
||||
class JitsiWidgetProperties(private val uriString: String) {
|
||||
val domain: String by lazy { configs["conferenceDomain"] ?: DEFAULT_JITSI_DOMAIN }
|
||||
val displayName: String? by lazy { configs["displayName"] }
|
||||
val avatarUrl: String? by lazy { configs["avatarUrl"] }
|
||||
|
||||
private val configString: String? by lazy { Uri.parse(uriString).fragment }
|
||||
|
||||
private val configs: Map<String, String?> by lazy {
|
||||
configString?.split("&")
|
||||
?.map { it.split("=") }
|
||||
?.map { (key, value) -> key to value }
|
||||
?.toMap()
|
||||
?: mapOf()
|
||||
}
|
||||
}
|
||||
|
||||
private const val DEFAULT_JITSI_DOMAIN = "jitsi.riot.im"
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* 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 android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.widget.FrameLayout
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import com.facebook.react.modules.core.PermissionListener
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.activity_jitsi.*
|
||||
import org.jitsi.meet.sdk.JitsiMeetActivityDelegate
|
||||
import org.jitsi.meet.sdk.JitsiMeetActivityInterface
|
||||
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions
|
||||
import org.jitsi.meet.sdk.JitsiMeetView
|
||||
import org.jitsi.meet.sdk.JitsiMeetViewListener
|
||||
import org.matrix.android.sdk.api.extensions.tryThis
|
||||
import java.net.URL
|
||||
import javax.inject.Inject
|
||||
|
||||
class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, JitsiMeetViewListener {
|
||||
|
||||
@Parcelize
|
||||
data class Args(
|
||||
val roomId: String,
|
||||
val widgetId: String,
|
||||
val enableVideo: Boolean
|
||||
) : Parcelable
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_jitsi
|
||||
|
||||
@Inject lateinit var viewModelFactory: JitsiCallViewModel.Factory
|
||||
|
||||
var jitsiMeetView: JitsiMeetView? = null
|
||||
|
||||
private val jitsiViewModel: JitsiCallViewModel by viewModel()
|
||||
|
||||
override fun injectWith(injector: ScreenComponent) {
|
||||
super.injectWith(injector)
|
||||
injector.inject(this)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
jitsiViewModel.subscribe(this) {
|
||||
renderState(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun initUiAndData() {
|
||||
super.initUiAndData()
|
||||
jitsiMeetView = JitsiMeetView(this)
|
||||
val params = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
|
||||
jitsi_layout.addView(jitsiMeetView, params)
|
||||
jitsiMeetView?.listener = this
|
||||
}
|
||||
|
||||
private fun renderState(viewState: JitsiCallViewState) {
|
||||
when (viewState.widget) {
|
||||
is Fail -> finish()
|
||||
is Success -> {
|
||||
// val widget = viewState.widget.invoke()
|
||||
configureJitsiView(viewState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureJitsiView(viewState: JitsiCallViewState) {
|
||||
val jitsiMeetConferenceOptions = JitsiMeetConferenceOptions.Builder()
|
||||
.setVideoMuted(!viewState.enableVideo)
|
||||
.setUserInfo(viewState.userInfo)
|
||||
.apply {
|
||||
tryThis { URL(viewState.jitsiUrl) }?.let {
|
||||
setServerURL(it)
|
||||
}
|
||||
}
|
||||
// https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/flags/constants.js
|
||||
.setFeatureFlag("chat.enabled", false)
|
||||
.setFeatureFlag("invite.enabled", false)
|
||||
.setFeatureFlag("add-people.enabled", false)
|
||||
.setFeatureFlag("video-share.enabled", false)
|
||||
.setRoom(viewState.confId)
|
||||
.setSubject(viewState.subject)
|
||||
.build()
|
||||
jitsiMeetView?.join(jitsiMeetConferenceOptions)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
JitsiMeetActivityDelegate.onHostPause(this)
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
JitsiMeetActivityDelegate.onHostResume(this)
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
JitsiMeetActivityDelegate.onBackPressed()
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
JitsiMeetActivityDelegate.onHostDestroy(this)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
// override fun onUserLeaveHint() {
|
||||
// super.onUserLeaveHint()
|
||||
// jitsiMeetView?.enterPictureInPicture()
|
||||
// }
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
JitsiMeetActivityDelegate.onNewIntent(intent)
|
||||
super.onNewIntent(intent)
|
||||
}
|
||||
|
||||
override fun requestPermissions(permissions: Array<out String>?, requestCode: Int, listener: PermissionListener?) {
|
||||
JitsiMeetActivityDelegate.requestPermissions(this, permissions, requestCode, listener)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
JitsiMeetActivityDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
}
|
||||
|
||||
override fun onConferenceTerminated(p0: MutableMap<String, Any>?) {
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onConferenceJoined(p0: MutableMap<String, Any>?) {
|
||||
}
|
||||
|
||||
override fun onConferenceWillJoin(p0: MutableMap<String, Any>?) {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newIntent(context: Context, roomId: String, widgetId: String, enableVideo: Boolean): Intent {
|
||||
return Intent(context, VectorJitsiActivity::class.java).apply {
|
||||
putExtra(MvRx.KEY_ARG, Args(roomId, widgetId, enableVideo))
|
||||
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -80,4 +80,5 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
|||
|
||||
object SelectStickerAttachment : RoomDetailAction()
|
||||
object OpenIntegrationManager: RoomDetailAction()
|
||||
object ManageIntegrations: RoomDetailAction()
|
||||
}
|
||||
|
|
|
@ -29,8 +29,11 @@ import android.text.Spannable
|
|||
import android.view.HapticFeedbackConstants
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
|
@ -77,6 +80,7 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.ui.views.ActiveCallView
|
||||
import im.vector.app.core.ui.views.ActiveCallViewHolder
|
||||
import im.vector.app.core.ui.views.ActiveConferenceView
|
||||
import im.vector.app.core.ui.views.JumpToReadMarkerView
|
||||
import im.vector.app.core.ui.views.NotificationAreaView
|
||||
import im.vector.app.core.utils.Debouncer
|
||||
|
@ -110,6 +114,7 @@ import im.vector.app.features.attachments.toGroupedContentAttachmentData
|
|||
import im.vector.app.features.call.SharedActiveCallViewModel
|
||||
import im.vector.app.features.call.VectorCallActivity
|
||||
import im.vector.app.features.call.WebRtcPeerConnectionManager
|
||||
import im.vector.app.features.call.conference.JitsiCallViewModel
|
||||
import im.vector.app.features.command.Command
|
||||
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
|
||||
import im.vector.app.features.crypto.util.toImageRes
|
||||
|
@ -129,7 +134,6 @@ import im.vector.app.features.home.room.detail.timeline.item.MessageInformationD
|
|||
import im.vector.app.features.home.room.detail.timeline.item.MessageTextItem
|
||||
import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData
|
||||
import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
|
||||
import im.vector.app.features.home.room.detail.widget.RoomWidgetsBannerView
|
||||
import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet
|
||||
import im.vector.app.features.home.room.detail.widget.WidgetRequestCodes
|
||||
import im.vector.app.features.html.EventHtmlRenderer
|
||||
|
@ -183,6 +187,7 @@ 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
|
||||
|
@ -217,7 +222,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
JumpToReadMarkerView.Callback,
|
||||
AttachmentTypeSelectorView.Callback,
|
||||
AttachmentsHelper.Callback,
|
||||
RoomWidgetsBannerView.Callback,
|
||||
// RoomWidgetsBannerView.Callback,
|
||||
ActiveCallView.Callback {
|
||||
|
||||
companion object {
|
||||
|
@ -292,7 +297,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
setupJumpToReadMarkerView()
|
||||
setupActiveCallView()
|
||||
setupJumpToBottomView()
|
||||
setupWidgetsBannerView()
|
||||
setupConfBannerView()
|
||||
|
||||
roomToolbarContentView.debouncedClicks {
|
||||
navigator.openRoomProfile(requireActivity(), roomDetailArgs.roomId)
|
||||
|
@ -350,6 +355,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
is RoomDetailViewEvents.DisplayEnableIntegrationsWarning -> displayDisabledIntegrationDialog()
|
||||
is RoomDetailViewEvents.OpenIntegrationManager -> openIntegrationManager()
|
||||
is RoomDetailViewEvents.OpenFile -> startOpenFileIntent(it)
|
||||
RoomDetailViewEvents.OpenActiveWidgetBottomSheet -> onViewWidgetsClicked()
|
||||
}.exhaustive
|
||||
}
|
||||
}
|
||||
|
@ -363,8 +369,16 @@ class RoomDetailFragment @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun setupWidgetsBannerView() {
|
||||
roomWidgetsBannerView.callback = this
|
||||
private fun setupConfBannerView() {
|
||||
activeConferenceView.callback = object : ActiveConferenceView.Callback {
|
||||
override fun onTapJoinAudio(jitsiWidget: Widget) {
|
||||
navigator.openRoomWidget(requireContext(), roomDetailArgs.roomId, jitsiWidget, mapOf(JitsiCallViewModel.ENABLE_VIDEO_OPTION to false))
|
||||
}
|
||||
|
||||
override fun onTapJoinVideo(jitsiWidget: Widget) {
|
||||
navigator.openRoomWidget(requireContext(), roomDetailArgs.roomId, jitsiWidget, mapOf(JitsiCallViewModel.ENABLE_VIDEO_OPTION to true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openStickerPicker(event: RoomDetailViewEvents.OpenStickerPicker) {
|
||||
|
@ -529,10 +543,40 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
menu.findItem(R.id.open_matrix_apps).let { menuItem ->
|
||||
menuItem.actionView.setOnClickListener {
|
||||
onOptionsItemSelected(menuItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.forEach {
|
||||
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
|
||||
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)
|
||||
} else {
|
||||
// icon should be default color no badge
|
||||
val actionView = findItem.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
@ -549,7 +593,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
true
|
||||
}
|
||||
R.id.open_matrix_apps -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.OpenIntegrationManager)
|
||||
roomDetailViewModel.handle(RoomDetailAction.ManageIntegrations)
|
||||
true
|
||||
}
|
||||
R.id.voice_call,
|
||||
|
@ -873,7 +917,19 @@ class RoomDetailFragment @Inject constructor(
|
|||
renderToolbar(summary, state.typingMessage)
|
||||
val inviter = state.asyncInviter()
|
||||
if (summary?.membership == Membership.JOIN) {
|
||||
roomWidgetsBannerView.render(state.activeRoomWidgets())
|
||||
// We only display banner for 'live' widgets
|
||||
val activeConf = // for now only jitsi?
|
||||
state.activeRoomWidgets()?.firstOrNull {
|
||||
// for now only jitsi?
|
||||
it.type == WidgetType.Jitsi
|
||||
}
|
||||
|
||||
if (activeConf == null) {
|
||||
activeConferenceView.isVisible = false
|
||||
} else {
|
||||
activeConferenceView.isVisible = true
|
||||
activeConferenceView.jitsiWidget = activeConf
|
||||
}
|
||||
jumpToBottomView.count = summary.notificationCount
|
||||
jumpToBottomView.drawBadge = summary.hasUnreadMessages
|
||||
scrollOnHighlightedEventCallback.timeline = roomDetailViewModel.timeline
|
||||
|
@ -1662,7 +1718,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
roomDetailViewModel.handle(RoomDetailAction.SendMessage(formattedContact, false))
|
||||
}
|
||||
|
||||
override fun onViewWidgetsClicked() {
|
||||
private fun onViewWidgetsClicked() {
|
||||
RoomWidgetsBottomSheet.newInstance()
|
||||
.show(childFragmentManager, "ROOM_WIDGETS_BOTTOM_SHEET")
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
|
|||
data class OpenStickerPicker(val widget: Widget): RoomDetailViewEvents()
|
||||
|
||||
object OpenIntegrationManager: RoomDetailViewEvents()
|
||||
object OpenActiveWidgetBottomSheet: RoomDetailViewEvents()
|
||||
|
||||
object MessageSent : SendMessageResult()
|
||||
data class JoinRoomCommandSuccess(val roomId: String) : SendMessageResult()
|
||||
|
|
|
@ -269,6 +269,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
is RoomDetailAction.OpenIntegrationManager -> handleOpenIntegrationManager()
|
||||
is RoomDetailAction.StartCall -> handleStartCall(action)
|
||||
is RoomDetailAction.EndCall -> handleEndCall()
|
||||
is RoomDetailAction.ManageIntegrations -> handleManageIntegrations()
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
|
@ -306,6 +307,16 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleManageIntegrations() = withState { state ->
|
||||
if (state.activeRoomWidgets().isNullOrEmpty()) {
|
||||
// Directly open integration manager screen
|
||||
handleOpenIntegrationManager()
|
||||
} else {
|
||||
// Display bottomsheet with widget list
|
||||
_viewEvents.post(RoomDetailViewEvents.OpenActiveWidgetBottomSheet)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startTrackingUnreadMessages() {
|
||||
trackUnreadMessages.set(true)
|
||||
setState { copy(canShowJumpToReadMarker = false) }
|
||||
|
|
|
@ -16,28 +16,48 @@
|
|||
|
||||
package im.vector.app.features.home.room.detail.widget
|
||||
|
||||
import android.view.View
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.ui.list.genericButtonItem
|
||||
import im.vector.app.core.ui.list.genericFooterItem
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Epoxy controller for room widgets list
|
||||
*/
|
||||
class RoomWidgetController @Inject constructor() : TypedEpoxyController<List<Widget>>() {
|
||||
class RoomWidgetController @Inject constructor(val stringProvider: StringProvider, val colorProvider: ColorProvider) : TypedEpoxyController<List<Widget>>() {
|
||||
|
||||
var listener: Listener? = null
|
||||
|
||||
override fun buildModels(widget: List<Widget>) {
|
||||
widget.forEach {
|
||||
RoomWidgetItem_()
|
||||
.id(it.widgetId)
|
||||
.widget(it)
|
||||
.widgetClicked { listener?.didSelectWidget(it) }
|
||||
.addTo(this)
|
||||
override fun buildModels(widgets: List<Widget>) {
|
||||
if (widgets.isEmpty()) {
|
||||
genericFooterItem {
|
||||
id("empty")
|
||||
text(stringProvider.getString(R.string.room_no_active_widgets))
|
||||
}
|
||||
} else {
|
||||
widgets.forEach {
|
||||
RoomWidgetItem_()
|
||||
.id(it.widgetId)
|
||||
.widget(it)
|
||||
.widgetClicked { listener?.didSelectWidget(it) }
|
||||
.addTo(this)
|
||||
}
|
||||
}
|
||||
genericButtonItem {
|
||||
id("addIntegration")
|
||||
text(stringProvider.getString(R.string.room_manage_integrations))
|
||||
textColor(colorProvider.getColor(R.color.riotx_accent))
|
||||
itemClickAction(View.OnClickListener { listener?.didSelectManageWidgets() })
|
||||
}
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun didSelectWidget(widget: Widget)
|
||||
fun didSelectManageWidgets()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
package im.vector.app.features.home.room.detail.widget
|
||||
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import com.airbnb.epoxy.EpoxyModelWithHolder
|
||||
|
@ -24,21 +27,34 @@ import im.vector.app.R
|
|||
import im.vector.app.core.epoxy.ClickListener
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.onClick
|
||||
import org.matrix.android.sdk.api.extensions.tryThis
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import java.net.URL
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_room_widget)
|
||||
abstract class RoomWidgetItem : EpoxyModelWithHolder<RoomWidgetItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute lateinit var widget: Widget
|
||||
@EpoxyAttribute var widgetClicked: ClickListener? = null
|
||||
@DrawableRes
|
||||
@EpoxyAttribute var iconRes: Int? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.widgetName.text = widget.name
|
||||
holder.widgetUrl.text = tryThis { URL(widget.computedUrl) }?.host ?: widget.computedUrl
|
||||
if (iconRes != null) {
|
||||
holder.iconImage.isVisible = true
|
||||
holder.iconImage.setImageResource(iconRes!!)
|
||||
} else {
|
||||
holder.iconImage.isVisible = false
|
||||
}
|
||||
holder.view.onClick(widgetClicked)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val widgetName by bind<TextView>(R.id.roomWidgetName)
|
||||
val widgetUrl by bind<TextView>(R.id.roomWidgetUrl)
|
||||
val iconImage by bind<ImageView>(R.id.roomWidgetAvatar)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import im.vector.app.core.extensions.cleanup
|
|||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.features.home.room.detail.RoomDetailAction
|
||||
import im.vector.app.features.home.room.detail.RoomDetailViewModel
|
||||
import im.vector.app.features.home.room.detail.RoomDetailViewState
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
|
@ -77,6 +78,11 @@ class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidget
|
|||
dismiss()
|
||||
}
|
||||
|
||||
override fun didSelectManageWidgets() {
|
||||
roomDetailViewModel.handle(RoomDetailAction.OpenIntegrationManager)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(): RoomWidgetsBottomSheet {
|
||||
return RoomWidgetsBottomSheet()
|
||||
|
|
|
@ -31,6 +31,8 @@ import im.vector.app.core.di.ActiveSessionHolder
|
|||
import im.vector.app.core.error.fatalError
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.call.conference.JitsiCallViewModel
|
||||
import im.vector.app.features.call.conference.VectorJitsiActivity
|
||||
import im.vector.app.features.createdirect.CreateDirectRoomActivity
|
||||
import im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
||||
import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity
|
||||
|
@ -66,6 +68,7 @@ import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
|||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
@ -270,9 +273,14 @@ class DefaultNavigator @Inject constructor(
|
|||
fragment.startActivityForResult(intent, WidgetRequestCodes.INTEGRATION_MANAGER_REQUEST_CODE)
|
||||
}
|
||||
|
||||
override fun openRoomWidget(context: Context, roomId: String, widget: Widget) {
|
||||
val widgetArgs = widgetArgsBuilder.buildRoomWidgetArgs(roomId, widget)
|
||||
context.startActivity(WidgetActivity.newIntent(context, widgetArgs))
|
||||
override fun openRoomWidget(context: Context, roomId: String, widget: Widget, options: Map<String, Any>?) {
|
||||
if (widget.type is WidgetType.Jitsi) {
|
||||
val enableVideo = options?.get(JitsiCallViewModel.ENABLE_VIDEO_OPTION) == true
|
||||
context.startActivity(VectorJitsiActivity.newIntent(context, roomId = roomId, widgetId = widget.widgetId, enableVideo = enableVideo))
|
||||
} else {
|
||||
val widgetArgs = widgetArgsBuilder.buildRoomWidgetArgs(roomId, widget)
|
||||
context.startActivity(WidgetActivity.newIntent(context, widgetArgs))
|
||||
}
|
||||
}
|
||||
|
||||
override fun openPinCode(fragment: Fragment, pinMode: PinMode, requestCode: Int) {
|
||||
|
|
|
@ -97,7 +97,7 @@ interface Navigator {
|
|||
|
||||
fun openIntegrationManager(fragment: Fragment, roomId: String, integId: String?, screen: String?)
|
||||
|
||||
fun openRoomWidget(context: Context, roomId: String, widget: Widget)
|
||||
fun openRoomWidget(context: Context, roomId: String, widget: Widget, options: Map<String, Any>? = null)
|
||||
|
||||
fun openMediaViewer(activity: Activity,
|
||||
roomId: String,
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M1,5C1,2.7909 2.7909,1 5,1H19C21.2091,1 23,2.7909 23,5V19C23,21.2091 21.2091,23 19,23H5C2.7909,23 1,21.2091 1,19V5ZM11,7.5C11,9.433 9.433,11 7.5,11C5.567,11 4,9.433 4,7.5C4,5.567 5.567,4 7.5,4C9.433,4 11,5.567 11,7.5ZM7.5,20C9.433,20 11,18.433 11,16.5C11,14.567 9.433,13 7.5,13C5.567,13 4,14.567 4,16.5C4,18.433 5.567,20 7.5,20ZM20,16.5C20,18.433 18.433,20 16.5,20C14.567,20 13,18.433 13,16.5C13,14.567 14.567,13 16.5,13C18.433,13 20,14.567 20,16.5ZM16.5,11C18.433,11 20,9.433 20,7.5C20,5.567 18.433,4 16.5,4C14.567,4 13,5.567 13,7.5C13,9.433 14.567,11 16.5,11Z"
|
||||
android:fillColor="#000000"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/jitsi_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/black">
|
||||
|
||||
<!-- Note: A org.jitsi.meet.sdk.JitsiMeetView will be added here -->
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/jitsi_progress_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/call_connecting"
|
||||
android:textColor="@android:color/white" />
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||
android:indeterminate="true" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout style="?attr/actionButtonStyle"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:focusable="true"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/action_view_icon_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:tint="@color/riotx_accent"
|
||||
android:src="@drawable/ic_integrations"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cart_badge"
|
||||
android:layout_width="12dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_gravity="right|end|top"
|
||||
android:layout_marginEnd="-4dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/bg_unread_highlight"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/white"
|
||||
tools:text="8"
|
||||
android:textSize="8sp"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -104,6 +104,14 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/syncStateView"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<im.vector.app.core.ui.views.ActiveConferenceView
|
||||
android:id="@+id/activeConferenceView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/activeCallView"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="0dp"
|
||||
|
@ -112,7 +120,7 @@
|
|||
app:layout_constraintBottom_toTopOf="@+id/recyclerViewBarrier"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/activeCallView"
|
||||
app:layout_constraintTop_toBottomOf="@id/activeConferenceView"
|
||||
tools:listitem="@layout/item_timeline_event_base" />
|
||||
|
||||
<FrameLayout
|
||||
|
@ -123,15 +131,15 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/activeCallView">
|
||||
|
||||
<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"
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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"
|
||||
|
@ -13,14 +14,36 @@
|
|||
|
||||
<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"
|
||||
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" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<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"
|
||||
tools:text="https://foobar" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge 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"
|
||||
android:background="?colorPrimary"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
tools:parentTag="android.widget.RelativeLayout">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/activeConferenceInfo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toStartOf="@id/returnToCallButton"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:drawableStart="@drawable/ic_call"
|
||||
android:drawablePadding="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:textColor="@color/white"
|
||||
android:textColorLink="@color/white"
|
||||
app:drawableTint="@color/white"
|
||||
tools:text="@string/ongoing_conference_call" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/returnToCallButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/activeConferenceInfo"
|
||||
android:layout_alignBottom="@+id/activeConferenceInfo"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:gravity="center"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/action_close"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</merge>
|
|
@ -12,11 +12,6 @@
|
|||
app:showAsAction="always"
|
||||
tools:visible="true" />
|
||||
|
||||
<item
|
||||
android:id="@+id/open_matrix_apps"
|
||||
android:title="@string/room_add_matrix_apps"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/voice_call"
|
||||
android:icon="@drawable/ic_phone"
|
||||
|
@ -35,6 +30,12 @@
|
|||
app:showAsAction="always"
|
||||
tools:visible="true" />
|
||||
|
||||
<item
|
||||
android:id="@+id/open_matrix_apps"
|
||||
android:title="@string/room_add_matrix_apps"
|
||||
app:actionLayout="@layout/custom_action_item_layout_badge"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/resend_all"
|
||||
android:icon="@drawable/ic_refresh_cw"
|
||||
|
|
|
@ -1210,6 +1210,8 @@
|
|||
<string name="widget_integration_invalid_parameter">A parameter is not valid.</string>
|
||||
<string name="integration_manager_not_configured">No integration manager configured.</string>
|
||||
<string name="room_add_matrix_apps">Add Matrix apps</string>
|
||||
<string name="room_manage_integrations">Manage Integrations</string>
|
||||
<string name="room_no_active_widgets">No active widgets</string>
|
||||
<string name="settings_labs_native_camera">Use native camera</string>
|
||||
<string name="settings_labs_native_camera_summary">Start the system camera instead of the custom camera screen.</string>
|
||||
<string name="settings_labs_keyboard_options_to_send_message">Use keyboard enter key to send message</string>
|
||||
|
|
|
@ -331,6 +331,17 @@
|
|||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
<style name="BottomSheetItemTextSecondary">
|
||||
<item name="android:fontFamily">sans-serif</item>
|
||||
<item name="android:layout_width">0dp</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:ellipsize">end</item>
|
||||
<item name="android:maxLines">2</item>
|
||||
<item name="android:textColor">?riotx_text_secondary</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
</style>
|
||||
|
||||
<style name="BottomSheetItemTime">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
|
|
Loading…
Reference in New Issue