diff --git a/app/build.gradle b/app/build.gradle index 85df74e7b..4a29c1d22 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -60,6 +60,9 @@ dependencies { //100ms.live prebuilt lib implementation "live.100ms:room-kit:$HMS_ROOM_KIT_VERSION" + // TODO update the version when it's ready + def hmsVersion = "2.9.5" + implementation "live.100ms:hms-noise-cancellation-android:$hmsVersion" // Navigation implementation "androidx.navigation:navigation-fragment-ktx:2.4.0" diff --git a/app/src/main/java/live/hms/app2/ui/home/HomeFragment.kt b/app/src/main/java/live/hms/app2/ui/home/HomeFragment.kt index dc1bc1339..660e1ed40 100644 --- a/app/src/main/java/live/hms/app2/ui/home/HomeFragment.kt +++ b/app/src/main/java/live/hms/app2/ui/home/HomeFragment.kt @@ -14,7 +14,6 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.core.content.edit -import androidx.core.os.bundleOf import androidx.core.widget.doOnTextChanged import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController @@ -32,7 +31,6 @@ import live.hms.roomkit.ui.meeting.DeviceStatsBottomSheet import live.hms.roomkit.ui.meeting.LEAVE_INFORMATION_PERSON import live.hms.roomkit.ui.meeting.LEAVE_INFORMATION_REASON import live.hms.roomkit.ui.meeting.LEAVE_INFROMATION_WAS_END_ROOM -import live.hms.roomkit.ui.settings.SettingsMode import live.hms.roomkit.ui.settings.SettingsStore import live.hms.roomkit.util.EmailUtils import live.hms.roomkit.util.NameUtils.isValidUserName @@ -171,7 +169,7 @@ class HomeFragment : Fragment() { if (settings.environment.contains("prod").not()) { put("token", "https://auth-nonprod.100ms.live") put("init", "https://qa-init.100ms.live/init") - put("layout", if (settings.useMockAPi) "https://demo8271564.mockable.io" else "https://api-nonprod.100ms.live") + put("layout", "https://api-nonprod.100ms.live") } }) ) diff --git a/gradle.properties b/gradle.properties index 4dce07438..a73a1bb7a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,5 +22,5 @@ kotlin.code.style=official 100MS_APP_VERSION_CODE=643 100MS_APP_VERSION_NAME=5.8.872 hmsRoomKitGroup=live.100ms -HMS_ROOM_KIT_VERSION=1.1.95 +HMS_ROOM_KIT_VERSION=1.1.96 android.suppressUnsupportedCompileSdk=33 diff --git a/room-kit/build.gradle b/room-kit/build.gradle index f55474e9b..b2508722c 100644 --- a/room-kit/build.gradle +++ b/room-kit/build.gradle @@ -72,12 +72,13 @@ dependencies { implementation 'com.google.android.material:material:1.10.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.percentlayout:percentlayout:1.0.0' - def hmsVersion = "2.9.4" + def hmsVersion = "2.9.5" implementation "com.otaliastudios:zoomlayout:1.9.0" // To add dependencies of specific module implementation "live.100ms:android-sdk:$hmsVersion" implementation "live.100ms:video-view:$hmsVersion" implementation "live.100ms:hls-player:$hmsVersion" + implementation "live.100ms:video-filters:$hmsVersion" // Navigation implementation "androidx.navigation:navigation-fragment-ktx:2.7.4" diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/GridOptionItem.kt b/room-kit/src/main/java/live/hms/roomkit/ui/GridOptionItem.kt index 5f92e522d..e1580282f 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/GridOptionItem.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/GridOptionItem.kt @@ -19,6 +19,8 @@ class GridOptionItem( var isSelected: Boolean = false, var particpantCount: Int? = null, var showProgress: Boolean = false, + val selectedTitle : String? = null, + ) : BindableItem() { private val SELECTION_UPDATE = "SELECTION_UPDATE" @@ -62,6 +64,11 @@ class GridOptionItem( } private fun setSelectedView(isSelected: Boolean, v: ItemGridOptionBinding) { + if(isSelected && selectedTitle != null ) + v.subtitle.text = selectedTitle + else + v.subtitle.text = title + v.rootLayout.background = if (isSelected.not()) { getShape().apply { setTint( diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/filters/FilterBottomSheet.kt b/room-kit/src/main/java/live/hms/roomkit/ui/filters/FilterBottomSheet.kt new file mode 100644 index 000000000..b037f70d1 --- /dev/null +++ b/room-kit/src/main/java/live/hms/roomkit/ui/filters/FilterBottomSheet.kt @@ -0,0 +1,293 @@ +package live.hms.roomkit.ui.filters + + +import android.app.Dialog +import android.content.res.ColorStateList +import android.graphics.Color +import android.graphics.PorterDuff +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.widget.FrameLayout +import android.widget.SeekBar +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.widget.SwitchCompat +import androidx.fragment.app.activityViewModels +import androidx.recyclerview.widget.LinearSnapHelper +import androidx.recyclerview.widget.SnapHelper +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.google.android.material.tabs.TabLayout +import live.hms.roomkit.R +import live.hms.roomkit.databinding.BottomSheetVideoFilterBinding +import live.hms.roomkit.drawableEnd +import live.hms.roomkit.drawableStart +import live.hms.roomkit.ui.meeting.MeetingViewModel +import live.hms.roomkit.ui.meeting.MeetingViewModelFactory +import live.hms.roomkit.ui.theme.HMSPrebuiltTheme +import live.hms.roomkit.ui.theme.getColorOrDefault +import live.hms.roomkit.util.viewLifecycle + + +class FilterBottomSheet( +) : BottomSheetDialogFragment() { + + private var binding by viewLifecycle() + + + private val meetingViewModel: MeetingViewModel by activityViewModels { + MeetingViewModelFactory( + requireActivity().application + ) + } + + + var currentSelectedFilter: VideoFilter? = null + + val padding = 8 + + override fun onStart() { + super.onStart() + dialog?.window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NORMAL, R.style.AppBottomSheetDialogTheme); + + } + + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + binding = BottomSheetVideoFilterBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + + binding.root.background = resources.getDrawable(R.drawable.gray_shape_round_dialog).apply { + val color = getColorOrDefault( + HMSPrebuiltTheme.getColours()?.backgroundDefault, + HMSPrebuiltTheme.getDefaults().background_default + ) + setColorFilter(color, PorterDuff.Mode.ADD); + } + + var btnArray = arrayOf( + binding.audioOt + ) + + val borders = arrayOf( + binding.border5 + ) + + borders.forEach { + it.setBackgroundColor( + getColorOrDefault( + HMSPrebuiltTheme.getColours()?.borderDefault, + HMSPrebuiltTheme.getDefaults().border_bright + ) + ) + } + + + + binding.closeBtn.drawable.setTint( + getColorOrDefault( + HMSPrebuiltTheme.getColours()?.onSurfaceHigh, + HMSPrebuiltTheme.getDefaults().onsurface_high_emp + ) + ) + + binding.closeBtn.setOnClickListener { + dismissAllowingStateLoss() + } + + + + + (binding.pluginSwitch as SwitchCompat).isChecked = true + meetingViewModel.setupFilterVideoPlugin() + (binding.pluginSwitch as SwitchCompat).setTextColor( + getColorOrDefault( + HMSPrebuiltTheme.getColours()?.onSurfaceHigh, + HMSPrebuiltTheme.getDefaults().onsurface_high_emp + ) + ) + (binding.pluginSwitch as SwitchCompat).setOnCheckedChangeListener { buttonView, isChecked -> + if (isChecked) meetingViewModel.setupFilterVideoPlugin() + else meetingViewModel.removeVideoFilterPlugIn() + } + + binding.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + when (currentSelectedFilter) { + is VideoFilter.Brightness -> meetingViewModel.filterPlugin.setBrightness( + progress / 100f + ) + + is VideoFilter.Sharpness -> meetingViewModel.filterPlugin.setSharpness(progress / 100f) + is VideoFilter.Contrast -> meetingViewModel.filterPlugin.setContrast(progress / 100f) + is VideoFilter.Redness -> meetingViewModel.filterPlugin.setRedness(progress / 100f) + is VideoFilter.Smoothness -> meetingViewModel.filterPlugin.setSmoothness(progress / 100f) + null -> {} + else -> {} + } + + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + + } + + }) + + + + + binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab?) { + when (tab?.tag) { + is VideoFilter.Brightness -> { + currentSelectedFilter = VideoFilter.Brightness + binding.seekBar.progress = + (meetingViewModel.filterPlugin.getBrightnessProgress() * 100f).toInt() + } + + is VideoFilter.Sharpness -> { + currentSelectedFilter = VideoFilter.Sharpness + binding.seekBar.progress = + (meetingViewModel.filterPlugin.getSharpnessProgress() * 100f).toInt() + } + + + is VideoFilter.Contrast -> { + currentSelectedFilter = VideoFilter.Contrast + binding.seekBar.progress = + ( meetingViewModel.filterPlugin.getContrastProgress() * 100f).toInt() + } + + is VideoFilter.Redness -> { + currentSelectedFilter = VideoFilter.Redness + binding.seekBar.progress = + (meetingViewModel.filterPlugin.getRednessProgress() * 100f).toInt() + } + + is VideoFilter.Smoothness -> { + currentSelectedFilter = VideoFilter.Smoothness + binding.seekBar.progress = + ( meetingViewModel.filterPlugin.getSmoothnessProgress() * 100f).toInt() + } + + + else -> { + + } + } + } + + override fun onTabUnselected(tab: TabLayout.Tab?) { + + } + + override fun onTabReselected(tab: TabLayout.Tab?) { + + } + + }) + + + + binding.tabLayout.apply { + setTabTextColors( + getColorOrDefault( + HMSPrebuiltTheme.getColours()?.onSurfaceLow, + HMSPrebuiltTheme.getDefaults().onsurface_high_emp + ), getColorOrDefault( + HMSPrebuiltTheme.getColours()?.onSurfaceHigh, + HMSPrebuiltTheme.getDefaults().onsurface_high_emp + ) + + ) + addTab( + this.newTab().setText("Brightness").setTag(VideoFilter.Brightness), true + ) + addTab( + this.newTab().setText("Contrast").setTag(VideoFilter.Contrast) + ) + addTab( + this.newTab().setText("Sharpness").setTag(VideoFilter.Sharpness) + ) + addTab( + this.newTab().setText("Redness").setTag(VideoFilter.Redness) + ) + addTab( + this.newTab().setText("Smoothness").setTag(VideoFilter.Smoothness) + ) + setSelectedTabIndicatorColor(Color.TRANSPARENT) + } + + + + + + + + btnArray.forEach { + it.setTextColor( + getColorOrDefault( + HMSPrebuiltTheme.getColours()?.onSurfaceHigh, + HMSPrebuiltTheme.getDefaults().onsurface_high_emp + ) + ) + + it.drawableEnd?.setTint( + getColorOrDefault( + HMSPrebuiltTheme.getColours()?.onSurfaceHigh, + HMSPrebuiltTheme.getDefaults().onsurface_high_emp + ) + ) + + it.drawableStart?.setTint( + getColorOrDefault( + HMSPrebuiltTheme.getColours()?.onSurfaceHigh, + HMSPrebuiltTheme.getDefaults().onsurface_high_emp + ) + ) + } + + } + + private fun getData(from: Int, to: Int): List { + val data: MutableList = ArrayList() + + + for (i in 0 until padding) { + data.add("") + } + for (i in from until to) { + data.add(i.toString()) + } + + for (i in 0 until padding) { + data.add("") + } + return data + } + + override fun getTheme(): Int { + return R.style.AppBottomSheetDialogTheme + } + +} \ No newline at end of file diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/filters/PickerAdapter.kt b/room-kit/src/main/java/live/hms/roomkit/ui/filters/PickerAdapter.kt new file mode 100644 index 000000000..276fcf415 --- /dev/null +++ b/room-kit/src/main/java/live/hms/roomkit/ui/filters/PickerAdapter.kt @@ -0,0 +1,46 @@ +package live.hms.roomkit.ui.filters + + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import live.hms.roomkit.R + + +class PickerAdapter( + private val context: Context, + private var dataList: List, + private val recyclerView: RecyclerView? +) : RecyclerView.Adapter() { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextVH { + val view: View + val inflater = LayoutInflater.from(context) + view = inflater.inflate(R.layout.layout_picker, parent, false) + return TextVH(view) + } + + override fun onBindViewHolder(holder: TextVH, position: Int) { + holder.pickerTxt.text = dataList[position] + holder.pickerTxt.setOnClickListener { recyclerView?.smoothScrollToPosition(position) } + } + + override fun getItemCount(): Int { + return dataList.size + } + + fun swapData(newData: List) { + dataList = newData + notifyDataSetChanged() + } + + class TextVH(itemView: View) : RecyclerView.ViewHolder(itemView) { + var pickerTxt: TextView + + init { + pickerTxt = itemView.findViewById(R.id.picker_item) as TextView + } + } +} \ No newline at end of file diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/filters/PickerLayoutManager.java b/room-kit/src/main/java/live/hms/roomkit/ui/filters/PickerLayoutManager.java new file mode 100644 index 000000000..9660fc053 --- /dev/null +++ b/room-kit/src/main/java/live/hms/roomkit/ui/filters/PickerLayoutManager.java @@ -0,0 +1,113 @@ +package live.hms.roomkit.ui.filters; + +import android.content.Context; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.view.View; + +/** + * Created by adityagohad on 06/06/17. + */ + +public class PickerLayoutManager extends LinearLayoutManager { + + private float scaleDownBy = 0.66f; + private float scaleDownDistance = 0.9f; + private boolean changeAlpha = true; + + private onScrollStopListener onScrollStopListener; + + public PickerLayoutManager(Context context, int orientation, boolean reverseLayout) { + super(context, orientation, reverseLayout); + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + super.onLayoutChildren(recycler, state); + scaleDownView(); + } + + @Override + public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { + int orientation = getOrientation(); + if (orientation == HORIZONTAL) { + int scrolled = super.scrollHorizontallyBy(dx, recycler, state); + scaleDownView(); + return scrolled; + } else return 0; + } + + private void scaleDownView() { + float mid = getWidth() / 2.0f; + float unitScaleDownDist = scaleDownDistance * mid; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child == null) { + continue; + } + float childMid = (getDecoratedLeft(child) + getDecoratedRight(child)) / 2.0f; + float scale = 1.0f + (-1 * scaleDownBy) * (Math.min(unitScaleDownDist, Math.abs(mid - childMid))) / unitScaleDownDist; + child.setScaleX(scale); + child.setScaleY(scale); + if (changeAlpha) { + child.setAlpha(scale); + } + } + } + + @Override + public void onScrollStateChanged(int state) { + super.onScrollStateChanged(state); + if (state == 0) { + if (onScrollStopListener != null) { + int selected = 0; + float lastHeight = 0f; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child == null) { + continue; + } + if (lastHeight < child.getScaleY()) { + lastHeight = child.getScaleY(); + selected = i; + } + } + onScrollStopListener.selectedView(getChildAt(selected)); + } + } + } + + public float getScaleDownBy() { + return scaleDownBy; + } + + public void setScaleDownBy(float scaleDownBy) { + this.scaleDownBy = scaleDownBy; + } + + public float getScaleDownDistance() { + return scaleDownDistance; + } + + public void setScaleDownDistance(float scaleDownDistance) { + this.scaleDownDistance = scaleDownDistance; + } + + public boolean isChangeAlpha() { + return changeAlpha; + } + + public void setChangeAlpha(boolean changeAlpha) { + this.changeAlpha = changeAlpha; + } + + public void setOnScrollStopListener(onScrollStopListener onScrollStopListener) { + this.onScrollStopListener = onScrollStopListener; + } + + public interface onScrollStopListener { + void selectedView(View view); + } +} diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/filters/VideoFilter.kt b/room-kit/src/main/java/live/hms/roomkit/ui/filters/VideoFilter.kt new file mode 100644 index 000000000..e316ef48e --- /dev/null +++ b/room-kit/src/main/java/live/hms/roomkit/ui/filters/VideoFilter.kt @@ -0,0 +1,12 @@ +package live.hms.roomkit.ui.filters + +sealed class VideoFilter { + object Brightness : VideoFilter() + object Sharpness : VideoFilter() + object Saturation : VideoFilter() + object Redness : VideoFilter() + object Smoothness : VideoFilter() + object Hue : VideoFilter() + object Contrast : VideoFilter() + object Exposure : VideoFilter() +} diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/MeetingFragment.kt b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/MeetingFragment.kt index 1ca11ab31..41766ce95 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/MeetingFragment.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/MeetingFragment.kt @@ -42,6 +42,7 @@ import live.hms.roomkit.R import live.hms.roomkit.databinding.FragmentMeetingBinding import live.hms.roomkit.setGradient import live.hms.roomkit.setOnSingleClickListener +import live.hms.roomkit.ui.filters.FilterBottomSheet import live.hms.roomkit.ui.meeting.activespeaker.ActiveSpeakerFragment import live.hms.roomkit.ui.meeting.activespeaker.HlsFragment import live.hms.roomkit.ui.meeting.audiomode.AudioModeFragment @@ -1170,7 +1171,11 @@ class MeetingFragment : Fragment() { } }, onRaiseHandClicked = { meetingViewModel.toggleRaiseHand()}, - onNameChange = { }, + onNameChange = { FilterBottomSheet().show( + childFragmentManager, + ChangeNameDialogFragment.TAG + ) + }, showPolls = { findNavController().navigate(MeetingFragmentDirections.actionMeetingFragmentToPollsCreationFragment()) }, onRecordingClicked = { val isBrowserRecordingRunning = meetingViewModel.hmsSDK.getRoom()?.browserRecordingState?.state in listOf( @@ -1190,6 +1195,7 @@ class MeetingFragment : Fragment() { ) } }, + onNoiseClicked = meetingViewModel::toggleNoiseCancellation ).show( childFragmentManager, AudioSwitchBottomSheetTAG ) diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/MeetingViewModel.kt b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/MeetingViewModel.kt index a069ec6cf..f520ac85c 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/MeetingViewModel.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/MeetingViewModel.kt @@ -34,6 +34,7 @@ import live.hms.video.error.HMSException import live.hms.video.interactivity.HmsInteractivityCenter import live.hms.video.interactivity.HmsPollUpdateListener import live.hms.video.events.AgentType +import live.hms.video.factories.noisecancellation.AvailabilityStatus import live.hms.video.media.settings.* import live.hms.video.media.tracks.* import live.hms.video.polls.HMSPollBuilder @@ -58,6 +59,7 @@ import live.hms.video.services.LogAlarmManager import live.hms.video.sessionstore.HmsSessionStore import live.hms.video.signal.init.* import live.hms.video.utils.HMSLogger +import live.hms.videofilters.HMSVideoFilter import java.util.* import kotlin.collections.ArrayList import kotlin.properties.Delegates @@ -80,6 +82,7 @@ class MeetingViewModel( private var pendingRoleChange: HMSRoleChangeRequest? = null private var hmsRoomLayout : HMSRoomLayout? = null val prebuiltInfoContainer by lazy { PrebuiltInfoContainer(hmsSDK) } + val toggleNcInPreview : MutableLiveData = MutableLiveData(false) private val settings = SettingsStore(getApplication()) private val hmsLogSettings: HMSLogSettings = @@ -122,6 +125,9 @@ class MeetingViewModel( .setLogSettings(hmsLogSettings) .build() + + val filterPlugin by lazy { HMSVideoFilter(hmsSDK) } + private var lastPollStartedTime : Long = 0 val localHmsInteractivityCenter : HmsInteractivityCenter = hmsSDK.getHmsInteractivityCenter() @@ -145,6 +151,7 @@ class MeetingViewModel( } HMSPollUpdateType.stopped -> viewModelScope.launch { _events.emit(Event.PollEnded(hmsPoll)) + hmsRemoveNotificationEvent.postValue(HMSNotificationType.OpenPollOrQuiz(pollId = hmsPoll.pollId)) } HMSPollUpdateType.resultsupdated -> viewModelScope.launch { _events.emit(Event.PollVotesUpdated(hmsPoll)) @@ -180,6 +187,8 @@ class MeetingViewModel( return } + + hmsSDK.getAuthTokenByRoomCode( TokenRequest(roomCode, hmsPrebuiltOptions?.userId ?: UUID.randomUUID().toString()), TokenRequestOptions(tokenURL), @@ -197,6 +206,43 @@ class MeetingViewModel( }) } + fun showVideoFilterIcon() = settings.enableVideoFilter + + fun setupFilterVideoPlugin() { + + if (hmsSDK.getPlugins().isNullOrEmpty() && hmsSDK.getLocalPeer()?.videoTrack != null ) { + filterPlugin.init() + hmsSDK.addPlugin(filterPlugin, object : HMSActionResultListener { + override fun onError(error: HMSException) { + + } + + override fun onSuccess() { + + } + + }, 30) + } + } + + fun removeVideoFilterPlugIn() { + + if (hmsSDK.getPlugins().isNullOrEmpty().not() ) { + filterPlugin.stop() + hmsSDK.removePlugin(filterPlugin, object : HMSActionResultListener { + override fun onError(error: HMSException) { + + } + + override fun onSuccess() { + + } + + }) + } + + } + fun joinRoomUsingToken(token: String, hmsPrebuiltOptions: HMSPrebuiltOptions?, onHMSActionResultListener: HMSActionResultListener?) { @@ -311,7 +357,7 @@ class MeetingViewModel( private val previewErrorData: MutableLiveData = MutableLiveData() private val previewUpdateData: MutableLiveData>> = MutableLiveData() - val statsToggleData: MutableLiveData = MutableLiveData(false) + val statsToggleData: MutableLiveData = MutableLiveData(settings.showStats) val peerCount = MutableLiveData(0) val previewRoomStateLiveData: LiveData> = roomState @@ -334,7 +380,7 @@ class MeetingViewModel( fun isAutoSimulcastEnabled() = settings.disableAutoSimulcast - fun isGoLiveInPreBuiltEnabled() = settings.useMockAPi + fun isGoLiveInPreBuiltEnabled() = settings.enableVideoFilter var showAudioMuted = MutableLiveData(false) private set @@ -427,7 +473,7 @@ class MeetingViewModel( // Add all tracks as they come in. addSource(tracks) { meetTracks: List -> //if remote peer and local peer is present inset mode - synchronized(tracks) { + synchronized(_tracks) { val excludeLocalTrackIfRemotePeerIsPreset = //Don't inset when local peer and local screen share track is found if (meetTracks.size == 2 && meetTracks.filter { it.isLocal }.size == 2 && hasInsetEnabled( @@ -517,6 +563,7 @@ class MeetingViewModel( Log.d("Pratim", "onPreview called") unMuteAllTracks(localTracks) previewUpdateData.postValue(Pair(room, localTracks)) + } override fun onRoomUpdate(type: HMSRoomUpdate, hmsRoom: HMSRoom) { @@ -762,6 +809,9 @@ class MeetingViewModel( val runningStreamingStates = listOf(HMSStreamingState.STARTED, HMSStreamingState.STARTING) val runningRecordingStates = listOf(HMSRecordingState.STARTING, HMSRecordingState.STARTED, HMSRecordingState.PAUSED, HMSRecordingState.RESUMED) + if(toggleNcInPreview.value == true) { + hmsSDK.setNoiseCancellationEnabled(true) + } if (room.hlsStreamingState.state in runningStreamingStates) streamingState.postValue(room.hlsStreamingState.state) if (room.rtmpHMSRtmpStreamingState.state in runningStreamingStates) @@ -2420,5 +2470,13 @@ class MeetingViewModel( return prebuiltInfoContainer.getLiveStreamingHeaderTitle() } //fun getHeader() = getHmsRoomLayout()?.data?.getOrNull(0)?.screens?.conferencing?.hlsLiveStreaming?.elements?.participantList + fun toggleNoiseCancellation() : Boolean { + hmsSDK.setNoiseCancellationEnabled(!hmsSDK.getNoiseCancellationEnabled()) + return hmsSDK.getNoiseCancellationEnabled() + } + + fun isNoiseCancellationEnabled() : Boolean = hmsSDK.getNoiseCancellationEnabled() + // Show the NC button if it's a webrtc peer with noise cancellation available + fun displayNoiseCancellationButton() : Boolean = hmsSDK.isNoiseCancellationAvailable() == AvailabilityStatus.Available && ( hmsSDK.getLocalPeer()?.let { !isHlsPeer(it.hmsRole) } ?: false ) } diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/PreviewFragment.kt b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/PreviewFragment.kt index b2df99e16..076ca8afa 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/PreviewFragment.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/PreviewFragment.kt @@ -380,8 +380,12 @@ class PreviewFragment : Fragment() { updateActionVolumeMenuIcon(it) }) - binding.iconOutputDevice.apply { - setOnSingleClickListener(200L) { + binding.iconNoiseCancellation.setOnSingleClickListener(200L) { + meetingViewModel.toggleNcInPreview.value = meetingViewModel.toggleNcInPreview.value!!.not() + updateNoiseCancellationIcon() + } + + binding.iconOutputDevice.setOnSingleClickListener(200L) { Log.v(TAG, "iconOutputDevice.onClick()") AudioOutputSwitchBottomSheet { audioDevice, isMuted -> @@ -391,7 +395,6 @@ class PreviewFragment : Fragment() { childFragmentManager, MeetingFragment.AudioSwitchBottomSheetTAG ) } - } binding.buttonSwitchCamera.setOnSingleClickListener(200L) { if (it.isEnabled) track?.video.switchCamera() @@ -514,6 +517,22 @@ class PreviewFragment : Fragment() { } } + private fun updateNoiseCancellationIcon() { + with(binding.iconNoiseCancellation) { + if(meetingViewModel.toggleNcInPreview.value == true) { + setIconDisabled(R.drawable.reduce_noise_session_option) + } else + { + setIconEnabled(R.drawable.reduce_noise_session_option) + } + + val existingVisibility = visibility + visibility = if(meetingViewModel.displayNoiseCancellationButton()) View.VISIBLE else View.GONE + if(existingVisibility == View.GONE && visibility == View.VISIBLE) { + startBounceAnimationUpwards() + } + } + } private fun updateActionVolumeMenuIcon() { binding.iconOutputDevice.visibility = View.VISIBLE binding.iconOutputDevice.apply { @@ -678,6 +697,7 @@ class PreviewFragment : Fragment() { } } + updateNoiseCancellationIcon() if (settings.lastUsedMeetingUrl.contains("/streaming/").not()) { updateJoinButtonTextIfHlsIsEnabled(room.localPeer?.hmsRole?.name) @@ -709,6 +729,7 @@ class PreviewFragment : Fragment() { if (publishParams.allowed.contains("audio")) { binding.buttonToggleAudio.visibility = View.VISIBLE + updateNoiseCancellationIcon() binding.buttonToggleAudio.startBounceAnimationUpwards() binding.iconOutputDevice.startBounceAnimationUpwards() } else { @@ -728,6 +749,7 @@ class PreviewFragment : Fragment() { binding.buttonToggleVideo.visibility = View.GONE binding.buttonSwitchCamera.visibility = View.GONE binding.videoCardContainer.visibility = View.GONE + binding.iconNoiseCancellation.visibility = View.GONE } } diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/SessionOptionBottomSheet.kt b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/SessionOptionBottomSheet.kt index e17e26f91..d4e23d9ab 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/SessionOptionBottomSheet.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/SessionOptionBottomSheet.kt @@ -8,6 +8,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.activityViewModels +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog @@ -15,9 +16,12 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.xwray.groupie.Group import com.xwray.groupie.GroupieAdapter import com.xwray.groupie.Section +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import live.hms.roomkit.R import live.hms.roomkit.databinding.BottomSheetOptionBinding import live.hms.roomkit.ui.GridOptionItem +import live.hms.roomkit.ui.filters.FilterBottomSheet import live.hms.roomkit.ui.theme.HMSPrebuiltTheme import live.hms.roomkit.ui.theme.getColorOrDefault import live.hms.roomkit.ui.theme.getShape @@ -32,7 +36,8 @@ class SessionOptionBottomSheet( private val onRaiseHandClicked: () -> Unit, private val onNameChange: () -> Unit, private val showPolls: () -> Unit, - private val disableHandRaiseDisplay : Boolean = false + private val disableHandRaiseDisplay : Boolean = false, + private val onNoiseClicked : (() -> Unit)? = null ) : BottomSheetDialogFragment() { private var binding by viewLifecycle() @@ -114,6 +119,12 @@ class SessionOptionBottomSheet( }, isSelected = false ) + val noiseButton = GridOptionItem("Reduce Noise", R.drawable.reduce_noise_session_option, { + onNoiseClicked?.invoke() + dismiss() + }, isSelected = meetingViewModel.isNoiseCancellationEnabled(), + selectedTitle = "Noise Reduced") + val peerListOption = GridOptionItem( resources.getString(R.string.peer_list), R.drawable.ic_icon_people, { onPeerListClicked.invoke() @@ -140,6 +151,15 @@ class SessionOptionBottomSheet( }, isSelected = false ) + val videoFilter = GridOptionItem( + "Video Filter", R.drawable.emoji_icon, { + onNameChange.invoke() + dismissAllowingStateLoss() + + }, isSelected = false + ) + + val group: Group = Section().apply { @@ -149,6 +169,9 @@ class SessionOptionBottomSheet( add(brbOption) if (meetingViewModel.isAllowedToShareScreen()) add(screenShareOption) + if (meetingViewModel.displayNoiseCancellationButton()) { + add(noiseButton) + } if(!disableHandRaiseDisplay) { add(raiseHandOption) } @@ -166,6 +189,9 @@ class SessionOptionBottomSheet( ) ) } + if (meetingViewModel.isLocalVideoEnabled() == true && meetingViewModel.showVideoFilterIcon()) { + add(videoFilter) + } } gridOptionAdapter.update(listOf(group)) diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/activespeaker/HlsFragment.kt b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/activespeaker/HlsFragment.kt index 2c3ba870e..0430990e4 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/activespeaker/HlsFragment.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/activespeaker/HlsFragment.kt @@ -256,6 +256,9 @@ private const val MILLI_SECONDS_FROM_LIVE = 10_000 val isHandRaised by meetingViewModel.isHandRaised.observeAsState(false) val showDvrControls by meetingViewModel.showDvrControls.observeAsState(false) // Turn off controls 3 seconds after they become visible + LaunchedEffect(key1 = viewMode) { + hlsViewModel.restarted() + } LaunchedEffect(controlsVisible, interacted) { if(controlsVisible) { delay(3.seconds) diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/activespeaker/HlsViewModel.kt b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/activespeaker/HlsViewModel.kt index 715eb6039..fdaff8d68 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/activespeaker/HlsViewModel.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/activespeaker/HlsViewModel.kt @@ -23,7 +23,7 @@ import live.hms.video.sdk.HMSSDK @UnstableApi class HlsViewModel( application: Application, - hlsStreamUrl : String, + private val hlsStreamUrl : String, private val hmsSdk: HMSSDK, private val hlsPlayerBeganToPlay : () -> Unit, private val displayHlsCuesUseCase : () -> DisplayHlsCuesUseCase @@ -36,11 +36,18 @@ import live.hms.video.sdk.HMSSDK val behindLiveByLiveData = MutableLiveData("0:0") val streamEndedEvent = SingleLiveEvent() val currentSubtitles = MutableLiveData() + private var failed = false val player = HmsHlsPlayer(application, hmsSdk).apply { setListeners(this) play(hlsStreamUrl) } + fun restarted() { + if(failed) { + player.play(hlsStreamUrl) + failed = false + } + } private fun setListeners(player: HmsHlsPlayer) { // binding.hlsView.player = player.getNativePlayer() player.getNativePlayer().addListener(@UnstableApi object : Player.Listener { @@ -71,6 +78,7 @@ import live.hms.video.sdk.HMSSDK override fun onPlaybackFailure(error: HmsHlsException) { Log.d("HMSHLSPLAYER", "From App, error: $error") + failed = true } @SuppressLint("UnsafeOptInUsageError") diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/chat/ChatUseCase.kt b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/chat/ChatUseCase.kt index f0a911e46..dac8f977c 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/chat/ChatUseCase.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/chat/ChatUseCase.kt @@ -1,11 +1,15 @@ package live.hms.roomkit.ui.meeting.chat +import android.text.Editable +import android.text.TextWatcher import android.view.View import android.widget.EditText import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.widget.LinearLayoutCompat +import androidx.core.widget.addTextChangedListener +import androidx.core.widget.doAfterTextChanged import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -16,6 +20,8 @@ import live.hms.roomkit.R import live.hms.roomkit.ui.meeting.AllowedToMessageParticipants import live.hms.roomkit.ui.meeting.ChatPauseState import live.hms.roomkit.ui.meeting.MeetingViewModel +import live.hms.roomkit.ui.theme.HMSPrebuiltTheme +import live.hms.roomkit.ui.theme.getColorOrDefault import live.hms.video.sdk.models.HMSPeer @@ -90,6 +96,21 @@ class ChatUseCase { // canShowIndicator : () -> Boolean = {true} ) { + editText.doAfterTextChanged { editable -> + val colour = if ((editable?.length ?: 0) > 0) { + getColorOrDefault( + HMSPrebuiltTheme.getColours()?.onSurfaceHigh, + HMSPrebuiltTheme.getDefaults().onsurface_high_emp + ) + + } else { + getColorOrDefault( + HMSPrebuiltTheme.getColours()?.onSurfaceLow, + HMSPrebuiltTheme.getDefaults().onsurface_low_emp + ) + } + sendButton.drawable.setTint(colour) + } fun updateState(externalChatPauseState: ChatPauseState? = null) { val overallChatState = getOverallChatState( diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/videogrid/ScreenShareFragement.kt b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/videogrid/ScreenShareFragement.kt index f8df93fb9..c5c2f73b1 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/videogrid/ScreenShareFragement.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/videogrid/ScreenShareFragement.kt @@ -136,7 +136,7 @@ class ScreenShareFragement(val screenShareTrackId: String) : BottomSheetDialogFr override fun onDismiss(dialog: DialogInterface) { super.onDismiss(dialog) contextSafe { context, activity -> - binding.localVideoView.removeTrack() + activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/videogrid/VideoGridFragment.kt b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/videogrid/VideoGridFragment.kt index 47ff9e7ff..887b526a9 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/meeting/videogrid/VideoGridFragment.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/meeting/videogrid/VideoGridFragment.kt @@ -286,7 +286,6 @@ class VideoGridFragment : Fragment() { insetPillMaximised.forEachIndexed { index, view -> if (view is HMSVideoView) { - view.removeTrack() insetPillMaximised.removeViewAt(index) } } diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/polls/PollsCreationFragment.kt b/room-kit/src/main/java/live/hms/roomkit/ui/polls/PollsCreationFragment.kt index 767e1df30..207f9b4b0 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/polls/PollsCreationFragment.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/polls/PollsCreationFragment.kt @@ -1,12 +1,14 @@ package live.hms.roomkit.ui.polls import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.OnBackPressedCallback import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager @@ -47,6 +49,12 @@ class PollsCreationFragment : Fragment(){ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + meetingViewModel.roomLayoutLiveData.observe(viewLifecycleOwner, Observer { + if (savedInstanceState != null) { + //re created fragment start setup + closeFragment() + } + }) initOnBackPress() binding.creationFlowUi.visibility = if (meetingViewModel.isAllowedToCreatePolls()) View.VISIBLE else View.GONE with(binding) { diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/polls/leaderboard/TimeConversionUtilities.kt b/room-kit/src/main/java/live/hms/roomkit/ui/polls/leaderboard/TimeConversionUtilities.kt index ede3f3e56..e4bf1ed27 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/polls/leaderboard/TimeConversionUtilities.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/polls/leaderboard/TimeConversionUtilities.kt @@ -1,5 +1,7 @@ package live.hms.roomkit.ui.polls.leaderboard +import java.math.RoundingMode + fun millisecondsToDisplayTime(milliseconds: Long): String { val minutes = milliseconds / 1000 / 60 val seconds = milliseconds / 1000 % 60 @@ -23,7 +25,7 @@ fun millisToText(milliseconds : Long?, val hours = milliseconds / 1000 / (60*60) val minutes = (milliseconds / 1000 / 60) % 60 - val seconds = (milliseconds / 1000) % 60 + val seconds = (milliseconds % 60000 )/ 1000f val prefix = if (hasHours) { "$hours" + 'h' + " $minutes" + "m" @@ -35,7 +37,7 @@ fun millisToText(milliseconds : Long?, val suffix = if(hasHours || hasMinutes) // if it has hours then don't show seconds "" - else String.format("%d$secondsText", seconds) + else " ${seconds.toBigDecimal().setScale(2, RoundingMode.FLOOR).toDouble()} seconds" "$prefix$suffix" } } \ No newline at end of file diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/role/RolePreviewFragment.kt b/room-kit/src/main/java/live/hms/roomkit/ui/role/RolePreviewFragment.kt index b24158db3..6307ad602 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/role/RolePreviewFragment.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/role/RolePreviewFragment.kt @@ -101,7 +101,6 @@ class RolePreviewFragment : BottomSheetDialogFragment() { meetingViewModel.changeRoleAccept(onSuccess = { contextSafe { context, activity -> activity.runOnUiThread { - binding.previewView.removeTrack() meetingViewModel.lowerLocalPeerHand() findNavController().navigate( RolePreviewFragmentDirections.actionRolePreviewFragmentToMeetingFragment( @@ -119,7 +118,6 @@ class RolePreviewFragment : BottomSheetDialogFragment() { meetingViewModel.lowerLocalPeerHand() localVideoTrack?.setMute(true) localAudioTrack?.setMute(true) - binding.previewView.removeTrack() findNavController().navigate( RolePreviewFragmentDirections.actionRolePreviewFragmentToMeetingFragment( false @@ -206,9 +204,7 @@ class RolePreviewFragment : BottomSheetDialogFragment() { override fun handleOnBackPressed() { localVideoTrack?.setMute(true) localAudioTrack?.setMute(true) - binding.previewView.removeTrack() meetingViewModel.setStatetoOngoing() - binding?.previewView?.removeTrack() findNavController().navigate( RolePreviewFragmentDirections.actionRolePreviewFragmentToMeetingFragment( false diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/settings/SettingsFragment.kt b/room-kit/src/main/java/live/hms/roomkit/ui/settings/SettingsFragment.kt index 7b7ed6949..82fc06763 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/settings/SettingsFragment.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/settings/SettingsFragment.kt @@ -497,9 +497,9 @@ class SettingsFragment : Fragment() { initSwitch( EnumSet.of(SettingsMode.HOME), - settings.useMockAPi, + settings.enableVideoFilter, goLiveInPrebuiltDebugEnabled - ) { commitHelper.setGOLiveInPrebuilt(it) } + ) { commitHelper.enableVideoFilter(it) } initSwitch( EnumSet.of(SettingsMode.HOME), diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/settings/SettingsStore.kt b/room-kit/src/main/java/live/hms/roomkit/ui/settings/SettingsStore.kt index fd2a86bf0..cea4a1369 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/settings/SettingsStore.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/settings/SettingsStore.kt @@ -58,7 +58,7 @@ class SettingsStore(context: Context) { const val MUTE_LOCAL_AUDIO_ON_PHONE_RING = "mute-local-audio-on-phone-ring" - const val GO_LIVE_IN_PREBUILT = "go-live-in-prebuilt" + const val ENABLE_VIDEO_FILTER_IN_PREBUILT = "go-live-in-prebuilt" val APPLY_CONSTRAINTS_KEYS = arrayOf( VIDEO_FRAME_RATE, @@ -147,9 +147,9 @@ class SettingsStore(context: Context) { get() = sharedPreferences.getBoolean(MUTE_LOCAL_AUDIO_ON_PHONE_RING, true) set(value) = putBoolean(MUTE_LOCAL_AUDIO_ON_PHONE_RING, value) - var useMockAPi : Boolean - get() = sharedPreferences.getBoolean(GO_LIVE_IN_PREBUILT, false) - set(value) = putBoolean(GO_LIVE_IN_PREBUILT, value) + var enableVideoFilter : Boolean + get() = sharedPreferences.getBoolean(ENABLE_VIDEO_FILTER_IN_PREBUILT, true) + set(value) = putBoolean(ENABLE_VIDEO_FILTER_IN_PREBUILT, value) var inPreBuiltDebugMode : Boolean get() = sharedPreferences.getBoolean(IN_PREBUILT_DEBUG_MODE, false) @@ -353,7 +353,7 @@ class SettingsStore(context: Context) { fun setDisableAutoSimulcast(value: Boolean) = apply { editor.putBoolean(DISABLE_AUTO_SIMULCAST, value) } fun setPrebuiltDebugMode(value: Boolean) = apply { editor.putBoolean(IN_PREBUILT_DEBUG_MODE, value) } - fun setGOLiveInPrebuilt(value: Boolean) = apply { editor.putBoolean(GO_LIVE_IN_PREBUILT, value) } + fun enableVideoFilter(value: Boolean) = apply { editor.putBoolean(ENABLE_VIDEO_FILTER_IN_PREBUILT, value) } fun commit() { diff --git a/room-kit/src/main/java/live/hms/roomkit/ui/theme/ThemeExt.kt b/room-kit/src/main/java/live/hms/roomkit/ui/theme/ThemeExt.kt index 350bd9a76..8cdda0766 100644 --- a/room-kit/src/main/java/live/hms/roomkit/ui/theme/ThemeExt.kt +++ b/room-kit/src/main/java/live/hms/roomkit/ui/theme/ThemeExt.kt @@ -2803,7 +2803,7 @@ fun BottomSheetMessageOptionsBinding.applyTheme() { ) ) - blockFromChatIcon.drawable.setTint( + blockFromChatText.drawableStart?.setTint( getColorOrDefault( HMSPrebuiltTheme.getColours()?.alertErrorDefault, HMSPrebuiltTheme.getDefaults().error_default diff --git a/room-kit/src/main/res/drawable/baseline_noise_aware_24.xml b/room-kit/src/main/res/drawable/baseline_noise_aware_24.xml new file mode 100644 index 000000000..0724a92c3 --- /dev/null +++ b/room-kit/src/main/res/drawable/baseline_noise_aware_24.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/room-kit/src/main/res/drawable/reduce_noise_session_option.xml b/room-kit/src/main/res/drawable/reduce_noise_session_option.xml new file mode 100644 index 000000000..ceb6caf81 --- /dev/null +++ b/room-kit/src/main/res/drawable/reduce_noise_session_option.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/room-kit/src/main/res/layout/bottom_sheet_message_options.xml b/room-kit/src/main/res/layout/bottom_sheet_message_options.xml index 533f9273c..e1edaa5be 100644 --- a/room-kit/src/main/res/layout/bottom_sheet_message_options.xml +++ b/room-kit/src/main/res/layout/bottom_sheet_message_options.xml @@ -127,23 +127,21 @@ android:id="@+id/optionBlockFromChat" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginVertical="@dimen/spacing_d2" + android:orientation="horizontal" > - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/room-kit/src/main/res/layout/fragment_preview.xml b/room-kit/src/main/res/layout/fragment_preview.xml index 14025cad3..b883af468 100644 --- a/room-kit/src/main/res/layout/fragment_preview.xml +++ b/room-kit/src/main/res/layout/fragment_preview.xml @@ -347,6 +347,21 @@ app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> + + + + + + + \ No newline at end of file diff --git a/room-kit/src/main/res/values/strings.xml b/room-kit/src/main/res/values/strings.xml index 06d9033c2..90351bc06 100644 --- a/room-kit/src/main/res/values/strings.xml +++ b/room-kit/src/main/res/values/strings.xml @@ -164,7 +164,7 @@ Mute local audio on phone ring Disable Auto Simulcast Prebuilt (NonDebug/Debug) - Use Mock API + Enable Video Filter Raise Hand Raise Hand Participant(s)