Skip to content

Commit

Permalink
feat(calling): request audio and BT permission on start, join or acce…
Browse files Browse the repository at this point in the history
…pt call (WPB-1809) (WPB-3961) (#2160)
  • Loading branch information
ohassine committed Sep 4, 2023
1 parent 2b85927 commit 4a8cabe
Show file tree
Hide file tree
Showing 27 changed files with 438 additions and 112 deletions.
@@ -0,0 +1,62 @@
/*
* Wire
* Copyright (C) 2023 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.calling.common

import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.wire.android.R
import com.wire.android.ui.common.WireDialog
import com.wire.android.ui.common.WireDialogButtonProperties
import com.wire.android.ui.common.WireDialogButtonType
import com.wire.android.ui.common.button.WireButtonState
import com.wire.android.util.ui.PreviewMultipleThemes

@Composable
fun MicrophoneBTPermissionsDeniedDialog(
shouldShow: Boolean,
onDismiss: () -> Unit,
onOpenSettings: () -> Unit
) {
if (shouldShow) {
WireDialog(
title = stringResource(id = R.string.call_permission_dialog_title),
text = stringResource(id = R.string.call_permission_dialog_description),
onDismiss = onDismiss,
dismissButtonProperties = WireDialogButtonProperties(
onClick = onDismiss,
text = stringResource(id = R.string.label_decline),
state = WireButtonState.Default
),
optionButton1Properties = WireDialogButtonProperties(
onClick = onOpenSettings,
text = stringResource(id = R.string.record_audio_permission_denied_dialog_settings_button),
type = WireDialogButtonType.Primary,
state = WireButtonState.Default
)
)
}
}
@PreviewMultipleThemes
@Composable
fun PreviewMicrophoneBTPermissionsDeniedDialog() {
MicrophoneBTPermissionsDeniedDialog(
shouldShow = true,
onDismiss = {},
onOpenSettings = {}
)
}
Expand Up @@ -32,23 +32,27 @@ import androidx.compose.ui.unit.Dp
import com.wire.android.R
import com.wire.android.appLogger
import com.wire.android.ui.common.button.WireButtonState
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.button.WirePrimaryButton
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.permission.rememberCallingRecordAudioBluetoothRequestFlow

@Composable
fun JoinButton(
buttonClick: () -> Unit,
onPermanentPermissionDecline: () -> Unit,
modifier: Modifier = Modifier,
minHeight: Dp = MaterialTheme.wireDimensions.buttonMediumMinSize.height,
minWidth: Dp = MaterialTheme.wireDimensions.buttonMediumMinSize.width
) {
val audioPermissionCheck = AudioBluetoothPermissionCheckFlow { buttonClick() }
val audioBTPermissionCheck = AudioBluetoothPermissionCheckFlow(
onJoinCall = buttonClick,
onPermanentPermissionDecline = onPermanentPermissionDecline
)

WirePrimaryButton(
onClick = audioPermissionCheck::launch,
onClick = audioBTPermissionCheck::launch,
fillMaxWidth = false,
shape = RoundedCornerShape(size = MaterialTheme.wireDimensions.corner12x),
text = stringResource(R.string.calling_button_label_join_call),
Expand All @@ -68,19 +72,22 @@ fun JoinButton(

@Composable
private fun AudioBluetoothPermissionCheckFlow(
onJoinCall: () -> Unit
) = rememberCallingRecordAudioBluetoothRequestFlow(onAudioBluetoothPermissionGranted = {
appLogger.d("Join Call Button - Permissions granted")
onJoinCall()
}) {
appLogger.d("Join Call Button - Permissions denied")
// TODO: Add a message that user needs permission to join call?
}
onJoinCall: () -> Unit,
onPermanentPermissionDecline: () -> Unit
) = rememberCallingRecordAudioBluetoothRequestFlow(
onAudioBluetoothPermissionGranted = {
appLogger.d("IncomingCall - Permissions granted")
onJoinCall()
},
onAudioBluetoothPermissionDenied = { },
onAudioBluetoothPermissionPermanentlyDenied = onPermanentPermissionDecline
)

@Preview
@Composable
fun PreviewJoinButton() {
JoinButton(
buttonClick = {}
buttonClick = {},
onPermanentPermissionDecline = {}
)
}
@@ -0,0 +1,87 @@
/*
* Wire
* Copyright (C) 2023 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.calling.controlbuttons

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.wire.android.R
import com.wire.android.appLogger
import com.wire.android.model.ClickBlockParams
import com.wire.android.ui.common.button.WireButtonState
import com.wire.android.ui.common.button.WireSecondaryButton
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.util.permission.rememberCallingRecordAudioBluetoothRequestFlow
import com.wire.android.util.ui.PreviewMultipleThemes

@Composable
fun StartCallButton(
onPhoneButtonClick: () -> Unit,
onPermanentPermissionDecline: () -> Unit,
isCallingEnabled: Boolean
) {
val audioBTPermissionCheck = AudioBluetoothPermissionCheckFlow(
startCall = onPhoneButtonClick,
onPermanentPermissionDecline = onPermanentPermissionDecline
)

WireSecondaryButton(
onClick = audioBTPermissionCheck::launch,
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.ic_phone),
contentDescription = stringResource(R.string.content_description_conversation_phone_icon),
)
},
state = if (isCallingEnabled) WireButtonState.Default else WireButtonState.Disabled,
fillMaxWidth = false,
minHeight = MaterialTheme.wireDimensions.spacing32x,
minWidth = MaterialTheme.wireDimensions.spacing40x,
clickBlockParams = ClickBlockParams(blockWhenSyncing = true, blockWhenConnecting = true),
shape = RoundedCornerShape(size = MaterialTheme.wireDimensions.corner12x),
contentPadding = PaddingValues(0.dp)
)
}

@Composable
private fun AudioBluetoothPermissionCheckFlow(
startCall: () -> Unit,
onPermanentPermissionDecline: () -> Unit
) = rememberCallingRecordAudioBluetoothRequestFlow(
onAudioBluetoothPermissionGranted = {
appLogger.d("startCall - Permissions granted")
startCall()
},
onAudioBluetoothPermissionDenied = { },
onAudioBluetoothPermissionPermanentlyDenied = onPermanentPermissionDecline
)

@PreviewMultipleThemes
@Composable
fun PreviewStartCallButton() {
StartCallButton(
onPhoneButtonClick = {},
onPermanentPermissionDecline = {},
isCallingEnabled = true
)
}
Expand Up @@ -35,6 +35,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
Expand All @@ -51,6 +52,7 @@ import com.wire.android.ui.calling.CallingNavArgs
import com.wire.android.ui.calling.SharedCallingViewModel
import com.wire.android.ui.calling.common.CallVideoPreview
import com.wire.android.ui.calling.common.CallerDetails
import com.wire.android.ui.calling.common.MicrophoneBTPermissionsDeniedDialog
import com.wire.android.ui.calling.controlbuttons.AcceptButton
import com.wire.android.ui.calling.controlbuttons.CallOptionsControls
import com.wire.android.ui.calling.controlbuttons.HangUpButton
Expand All @@ -60,6 +62,7 @@ import com.wire.android.ui.common.dialogs.calling.JoinAnywayDialog
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.destinations.OngoingCallScreenDestination
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.extension.openAppInfoScreen
import com.wire.android.util.permission.rememberCallingRecordAudioBluetoothRequestFlow
import com.wire.kalium.logic.data.call.ConversationType
import com.wire.kalium.logic.data.id.ConversationId
Expand All @@ -75,9 +78,19 @@ fun IncomingCallScreen(
sharedCallingViewModel: SharedCallingViewModel = hiltViewModel(),
incomingCallViewModel: IncomingCallViewModel = hiltViewModel()
) {
val context = LocalContext.current

val audioPermissionCheck = AudioBluetoothPermissionCheckFlow(
incomingCallViewModel::acceptCall,
incomingCallViewModel::declineCall
incomingCallViewModel::showPermissionDialog
)

MicrophoneBTPermissionsDeniedDialog(
shouldShow = incomingCallViewModel.incomingCallState.shouldShowPermissionDialog,
onDismiss = incomingCallViewModel::dismissPermissionDialog,
onOpenSettings = {
context.openAppInfoScreen()
}
)

with(incomingCallViewModel) {
Expand Down Expand Up @@ -220,16 +233,17 @@ private fun IncomingCallContent(
}

@Composable
private fun AudioBluetoothPermissionCheckFlow(
fun AudioBluetoothPermissionCheckFlow(
onAcceptCall: () -> Unit,
onDeclineCall: () -> Unit
) = rememberCallingRecordAudioBluetoothRequestFlow(onAudioBluetoothPermissionGranted = {
appLogger.d("IncomingCall - Permissions granted")
onAcceptCall()
}) {
appLogger.d("IncomingCall - Permissions denied")
onDeclineCall()
}
onPermanentPermissionDecline: () -> Unit,
) = rememberCallingRecordAudioBluetoothRequestFlow(
onAudioBluetoothPermissionGranted = {
appLogger.d("IncomingCall - Permissions granted")
onAcceptCall()
},
onAudioBluetoothPermissionDenied = { },
onAudioBluetoothPermissionPermanentlyDenied = onPermanentPermissionDecline
)

@Preview
@Composable
Expand Down
Expand Up @@ -22,6 +22,7 @@ import com.wire.kalium.logic.data.id.ConversationId
data class IncomingCallState(
val hasEstablishedCall: Boolean = false,
val shouldShowJoinCallAnywayDialog: Boolean = false,
val shouldShowPermissionDialog: Boolean = false,
val flowState: FlowState = FlowState.Default
) {
sealed interface FlowState {
Expand Down
Expand Up @@ -113,6 +113,14 @@ class IncomingCallViewModel @Inject constructor(
}
}

fun showPermissionDialog() {
incomingCallState = incomingCallState.copy(shouldShowPermissionDialog = true)
}

fun dismissPermissionDialog() {
incomingCallState = incomingCallState.copy(shouldShowPermissionDialog = false)
}

private fun showJoinCallAnywayDialog() {
incomingCallState = incomingCallState.copy(shouldShowJoinCallAnywayDialog = true)
}
Expand Down

0 comments on commit 4a8cabe

Please sign in to comment.