Skip to content

Commit 6d88939

Browse files
authored
Merge pull request #703 from 100mslive/dev
Release :: v2.9.55
2 parents ac66fa7 + c3468a8 commit 6d88939

16 files changed

+187
-52
lines changed

app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ dependencies {
6262
implementation "live.100ms:room-kit:$HMS_ROOM_KIT_VERSION"
6363

6464
//100ms noise cancellation dep
65-
def hmsVersion = "2.9.54"
65+
def hmsVersion = "2.9.55"
6666
implementation "live.100ms:hms-noise-cancellation-android:$hmsVersion"
6767

6868
// Navigation

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ kotlin.code.style=official
2222
100MS_APP_VERSION_CODE=371
2323
100MS_APP_VERSION_NAME=5.0.5
2424
hmsRoomKitGroup=live.100ms
25-
HMS_ROOM_KIT_VERSION=1.2.1
25+
HMS_ROOM_KIT_VERSION=1.2.11
2626
android.suppressUnsupportedCompileSdk=33

room-kit/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ dependencies {
7272
implementation 'com.google.android.material:material:1.10.0'
7373
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
7474
implementation 'androidx.percentlayout:percentlayout:1.0.0'
75-
def hmsVersion = "2.9.54"
75+
def hmsVersion = "2.9.55"
7676
implementation "com.otaliastudios:zoomlayout:1.9.0"
7777
// To add dependencies of specific module
7878
implementation "live.100ms:android-sdk:$hmsVersion"

room-kit/src/main/java/live/hms/roomkit/ui/meeting/MeetingFragment.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ import androidx.compose.runtime.LaunchedEffect
4040
import androidx.compose.runtime.getValue
4141
import androidx.compose.runtime.livedata.observeAsState
4242
import androidx.compose.ui.Modifier
43-
import androidx.compose.ui.draw.clip
4443
import androidx.compose.ui.graphics.toArgb
4544
import androidx.compose.ui.platform.ComposeView
4645
import androidx.compose.ui.platform.ViewCompositionStrategy
@@ -337,8 +336,8 @@ class MeetingFragment : Fragment() {
337336
val subtitles by meetingViewModel.captions.observeAsState()
338337
val topBottom by meetingViewModel.transcriptionsPosition.observeAsState()
339338
if( !subtitles.isNullOrEmpty() && captionsEnabled) {
340-
Column(modifier = Modifier.padding(start = 8.dp, top = 8.dp, end = 8.dp, bottom = 16.dp),
341-
verticalArrangement = if(topBottom == MeetingViewModel.TranscriptionsPosition.TOP) Arrangement.Top else Arrangement.Bottom) {
339+
Column(modifier = Modifier.padding(start = 8.dp, top = if(topBottom == MeetingViewModel.TranscriptionsPosition.SCREENSHARE_TOP) 57.dp else 8.dp, end = 8.dp, bottom = 16.dp),
340+
verticalArrangement = if(topBottom == MeetingViewModel.TranscriptionsPosition.BOTTOM) Arrangement.Bottom else Arrangement.Top) {
342341
Captions(subtitles)
343342
}
344343
}
@@ -394,12 +393,11 @@ class MeetingFragment : Fragment() {
394393
}
395394

396395
private fun chatButtonEnabled(enable : Boolean) {
396+
meetingViewModel.transcriptionsPositionUseCase.chatStateChanged(enable)
397397
if(enable) {
398398
binding.buttonOpenChat.setIconDisabled(R.drawable.ic_chat_message)
399-
meetingViewModel.transcriptionsPosition.postValue(MeetingViewModel.TranscriptionsPosition.TOP)
400399
} else {
401400
binding.buttonOpenChat.setIconEnabled(R.drawable.ic_chat_message)
402-
meetingViewModel.transcriptionsPosition.postValue(MeetingViewModel.TranscriptionsPosition.BOTTOM)
403401
}
404402
}
405403

room-kit/src/main/java/live/hms/roomkit/ui/meeting/MeetingViewModel.kt

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,18 @@ import kotlin.properties.Delegates
7575
class MeetingViewModel(
7676
application: Application
7777
) : AndroidViewModel(application) {
78+
val joined = MutableLiveData(false)
7879
companion object {
7980
private const val TAG = "MeetingViewModel"
8081
}
8182
val transcriptionUseCase = TranscriptionUseCase { hmsSDK.getPeerById(it)?.name }
8283
enum class TranscriptionsPosition {
84+
SCREENSHARE_TOP,
8385
TOP,
8486
BOTTOM
8587
}
86-
val transcriptionsPosition = MutableLiveData(TranscriptionsPosition.BOTTOM)
88+
val transcriptionsPositionUseCase = TranscriptionsPositionUseCase(viewModelScope)
89+
val transcriptionsPosition : LiveData<TranscriptionsPosition> = transcriptionsPositionUseCase.transcriptionsPosition.distinctUntilChanged()
8790
val areCaptionsEnabledByUser : MutableLiveData<Boolean> = MutableLiveData(true)
8891
val captions : LiveData<List<TranscriptViewHolder>> = transcriptionUseCase.captions
8992

@@ -441,7 +444,7 @@ class MeetingViewModel(
441444
}
442445
}
443446

444-
private val _tracks = Collections.synchronizedList(ArrayList<MeetingTrack>())
447+
val _tracks = Collections.synchronizedList(ArrayList<MeetingTrack>())
445448

446449
// When we get stats, a flow will be updated with the saved stats.
447450
private val statsFlow = MutableSharedFlow<Map<String, Any>>()
@@ -530,7 +533,8 @@ class MeetingViewModel(
530533
val tracks: LiveData<List<MeetingTrack>> = _liveDataTracks
531534

532535
// Live data containing the current Speaker in the meeting
533-
val speakers = MutableLiveData<Array<HMSSpeaker>>()
536+
val speakersLiveData = MutableLiveData<Array<HMSSpeaker>>()
537+
534538

535539
private val activeSpeakerHandler = ActiveSpeakerHandler(false) { _tracks }
536540

@@ -545,21 +549,25 @@ class MeetingViewModel(
545549
) { _tracks }
546550

547551
override fun addSpeakerSource() {
548-
addSource(speakers) { speakers : Array<HMSSpeaker> ->
552+
addSource(speakersLiveData) { speakerList : Array<HMSSpeaker> ->
549553

550-
val excludeLocalTrackIfRemotePeerIsPreset : Array<HMSSpeaker> = if (hasInsetEnabled(hmsSDK.getLocalPeer()?.hmsRole)) {
551-
speakers.filter { it.peer?.isLocal == false }.toTypedArray()
552-
} else {
553-
speakers
554-
}
554+
synchronized(speakersLiveData) {
555+
556+
val excludeLocalTrackIfRemotePeerIsPreset: Array<HMSSpeaker> =
557+
if (hasInsetEnabled(hmsSDK.getLocalPeer()?.hmsRole)) {
558+
speakerList.filter { it.peer?.isLocal == false }.toTypedArray()
559+
} else {
560+
speakerList
561+
}
555562

556-
val result = speakerH.speakerUpdate(excludeLocalTrackIfRemotePeerIsPreset)
557-
setValue(result.first)
563+
val result = speakerH.speakerUpdate(excludeLocalTrackIfRemotePeerIsPreset)
564+
setValue(result.first)
565+
}
558566
}
559567
}
560568

561569
override fun removeSpeakerSource() {
562-
removeSource(speakers)
570+
removeSource(speakersLiveData)
563571
}
564572

565573
//TODO can't be null
@@ -618,7 +626,9 @@ class MeetingViewModel(
618626
}
619627

620628
val activeSpeakers: LiveData<Pair<List<MeetingTrack>, Array<HMSSpeaker>>> =
621-
speakers.map(activeSpeakerHandler::speakerUpdate)
629+
speakersLiveData.map(activeSpeakerHandler::speakerUpdate)
630+
631+
622632
val activeSpeakersUpdatedTracks = _liveDataTracks.map(activeSpeakerHandler::trackUpdateTrigger)
623633

624634
// We need all the active speakers, but the very first time it should be filled.
@@ -968,6 +978,7 @@ class MeetingViewModel(
968978
updatePolls()
969979
participantPeerUpdate.postValue(Unit)
970980
setupWhiteBoardListener()
981+
joined.postValue(true)
971982
}
972983

973984
override fun onPeerUpdate(type: HMSPeerUpdate, hmsPeer: HMSPeer) {
@@ -1239,7 +1250,9 @@ class MeetingViewModel(
12391250
TAG,
12401251
"onAudioLevelUpdate: speakers=${speakers.map { Pair(it.peer?.name, it.level) }}"
12411252
)
1242-
this@MeetingViewModel.speakers.postValue(speakers)
1253+
synchronized(speakersLiveData) {
1254+
this@MeetingViewModel.speakersLiveData.postValue(speakers)
1255+
}
12431256
}
12441257
})
12451258
}
@@ -1496,6 +1509,7 @@ class MeetingViewModel(
14961509
}
14971510
cleanup()
14981511
state.postValue(MeetingState.Disconnected(true, details))
1512+
joined.postValue(false)
14991513
}
15001514

15011515
private fun addAudioTrack(track: HMSAudioTrack, peer: HMSPeer) {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package live.hms.roomkit.ui.meeting
2+
3+
import androidx.lifecycle.MutableLiveData
4+
import kotlinx.coroutines.CoroutineScope
5+
import kotlinx.coroutines.launch
6+
import kotlinx.coroutines.sync.Mutex
7+
import kotlinx.coroutines.sync.withLock
8+
9+
class TranscriptionsPositionUseCase(private val scope : CoroutineScope) {
10+
val TAG = "TranscPositionUseCase"
11+
val transcriptionsPosition = MutableLiveData(MeetingViewModel.TranscriptionsPosition.BOTTOM)
12+
13+
14+
private var isScreenShare : Boolean = false
15+
private var isChatEnabled : Boolean = false
16+
private var lock = Mutex()
17+
fun chatStateChanged(enabled: Boolean) {
18+
scope.launch {
19+
lock.withLock {
20+
// Log.d(TAG, "Chatstate: $enabled")
21+
isChatEnabled = enabled
22+
transcriptionsPosition.postValue(recalculate())
23+
}
24+
}
25+
}
26+
27+
fun setScreenShare(enabled : Boolean) {
28+
scope.launch {
29+
lock.withLock {
30+
// Log.d(TAG, "Screenshare: $enabled")
31+
isScreenShare = enabled
32+
33+
transcriptionsPosition.postValue(recalculate())
34+
}
35+
}
36+
}
37+
38+
private fun recalculate() : MeetingViewModel.TranscriptionsPosition {
39+
return if(!isChatEnabled)
40+
MeetingViewModel.TranscriptionsPosition.BOTTOM
41+
else if(isScreenShare)
42+
MeetingViewModel.TranscriptionsPosition.SCREENSHARE_TOP
43+
else
44+
MeetingViewModel.TranscriptionsPosition.TOP
45+
// Log.d(TAG, "recalculate $r")
46+
}
47+
48+
}

room-kit/src/main/java/live/hms/roomkit/ui/meeting/audiomode/AudioModeFragment.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ class AudioModeFragment : Fragment() {
4646
adapter.setItems(meetingViewModel.peers)
4747
}
4848

49-
meetingViewModel.speakers.observe(viewLifecycleOwner) {
50-
adapter.applySpeakerUpdates(it)
49+
meetingViewModel.speakersLiveData.observe(viewLifecycleOwner) {
50+
synchronized(meetingViewModel.speakersLiveData) {
51+
adapter.applySpeakerUpdates(it)
52+
}
53+
5154
}
5255

5356
if (meetingViewModel.isLocalVideoEnabled.value != false) {

room-kit/src/main/java/live/hms/roomkit/ui/meeting/chat/combined/ChatParticipantCombinedFragment.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,24 @@ class ChatOnlyAdapter(val fragment: BottomSheetDialogFragment) : FragmentStateAd
2424
override fun createFragment(position: Int): Fragment {
2525
// Return a NEW fragment instance in createFragment(int).
2626

27-
return CombinedChatFragmentTab(fragment::dismissAllowingStateLoss)
27+
return CombinedChatFragmentTab().apply {
28+
this.dismissAllowingStateLoss = fragment::dismissAllowingStateLoss
29+
}
2830
}
2931
}
3032
class ChatParticipantAdapter(val fragment: BottomSheetDialogFragment) : FragmentStateAdapter(fragment) {
31-
val partFragment = ParticipantsTabFragment(fragment::dismiss)
33+
val partFragment = ParticipantsTabFragment().apply {
34+
this.dismissFragment = fragment::dismiss
35+
}
3236
override fun getItemCount(): Int = 2
3337

3438
override fun createFragment(position: Int): Fragment {
3539
// Return a NEW fragment instance in createFragment(int).
3640

3741
return if (position == 0)
38-
CombinedChatFragmentTab(fragment::dismissAllowingStateLoss)
42+
CombinedChatFragmentTab().apply {
43+
this.dismissAllowingStateLoss = fragment::dismissAllowingStateLoss
44+
}
3945
else
4046
partFragment
4147
}

room-kit/src/main/java/live/hms/roomkit/ui/meeting/chat/combined/CombinedChatFragmentTab.kt

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,37 @@ import androidx.fragment.app.Fragment
88
import androidx.fragment.app.activityViewModels
99
import live.hms.roomkit.databinding.LayoutChatParticipantCombinedTabChatBinding
1010
import live.hms.roomkit.setOnSingleClickListener
11+
import live.hms.roomkit.ui.meeting.ChatViewModelFactory
1112
import live.hms.roomkit.ui.meeting.MeetingViewModel
13+
import live.hms.roomkit.ui.meeting.MeetingViewModelFactory
1214
import live.hms.roomkit.ui.meeting.MessageOptionsBottomSheet
1315
import live.hms.roomkit.ui.meeting.PauseChatUIUseCase
1416
import live.hms.roomkit.ui.meeting.chat.ChatAdapter
1517
import live.hms.roomkit.ui.meeting.chat.ChatUseCase
1618
import live.hms.roomkit.ui.meeting.chat.ChatViewModel
1719
import live.hms.roomkit.ui.meeting.chat.rbac.RoleBasedChatBottomSheet
20+
import live.hms.roomkit.ui.meeting.participants.LoadAfterJoin
1821
import live.hms.roomkit.ui.theme.applyTheme
1922
import live.hms.roomkit.util.viewLifecycle
2023
import kotlin.reflect.KFunction0
2124

22-
class CombinedChatFragmentTab(val dismissAllowingStateLoss: KFunction0<Unit>) : Fragment() {
25+
class CombinedChatFragmentTab : Fragment() {
2326
private var binding by viewLifecycle<LayoutChatParticipantCombinedTabChatBinding>()
24-
val meetingViewModel : MeetingViewModel by activityViewModels()
25-
private val chatViewModel : ChatViewModel by activityViewModels()
27+
val meetingViewModel : MeetingViewModel by activityViewModels {
28+
MeetingViewModelFactory(
29+
requireActivity().application
30+
)
31+
}
32+
private val chatViewModel : ChatViewModel by activityViewModels {
33+
ChatViewModelFactory(meetingViewModel.hmsSDK)
34+
}
2635
private val launchMessageOptionsDialog = LaunchMessageOptionsDialog()
2736
private val chatAdapter by lazy { ChatAdapter({ message ->
2837
launchMessageOptionsDialog.launch(meetingViewModel,
2938
childFragmentManager, message) },{}, { message -> MessageOptionsBottomSheet.showMessageOptions(meetingViewModel, message)})
3039
}
3140
private val pinnedMessageUiUseCase = PinnedMessageUiUseCase()
32-
41+
lateinit var dismissAllowingStateLoss: () -> Unit
3342
override fun onDetach() {
3443
super.onDetach()
3544
meetingViewModel.restoreTempHiddenCaptions()
@@ -56,8 +65,13 @@ class CombinedChatFragmentTab(val dismissAllowingStateLoss: KFunction0<Unit>) :
5665
return binding.root
5766
}
5867

59-
6068
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
69+
LoadAfterJoin(meetingViewModel, viewLifecycleOwner) {
70+
afterViewCreatedAndJoined()
71+
}
72+
}
73+
74+
fun afterViewCreatedAndJoined() {
6175

6276
binding.sendToBackground.setOnSingleClickListener {
6377
RoleBasedChatBottomSheet.launch(childFragmentManager, chatViewModel)

room-kit/src/main/java/live/hms/roomkit/ui/meeting/chat/rbac/RoleBasedChatBottomSheet.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ class RoleBasedChatBottomSheet(
4747
private val recipientSelected: (Recipient) -> Unit
4848
) : BottomSheetDialogFragment() {
4949

50+
private var close = false
51+
constructor() : this({null}, {}) {
52+
// Close the fragment if it's recreated by android after a restart
53+
close = true
54+
}
55+
5056
private var initialRecipients : List<Group> = emptyList()
5157
private var allowedParticipants : AllowedToMessageParticipants? = null
5258
private val chatRecipientSearchUseCase : ChatRecipientSearchUseCase = ChatRecipientSearchUseCase(::updateListWithPeers)
@@ -72,6 +78,8 @@ class RoleBasedChatBottomSheet(
7278
override fun onCreate(savedInstanceState: Bundle?) {
7379
super.onCreate(savedInstanceState)
7480
setStyle(STYLE_NORMAL, R.style.AppBottomSheetDialogTheme)
81+
if(close)
82+
dismissAllowingStateLoss()
7583
}
7684

7785

0 commit comments

Comments
 (0)