Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
skydoves committed Sep 5, 2023
2 parents 5428fcc + 80da737 commit ebcdea7
Show file tree
Hide file tree
Showing 39 changed files with 829 additions and 242 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Video roadmap and changelog is available [here](https://github.com/GetStream/pro

### 0.3.0 milestone

- [ ] Finish usability testing with design team on chat integration (Jaewoong)
- [X] Finish usability testing with design team on chat integration (Jaewoong)
- [X] Pagination on query members & query call endpoints (Daniel)
- [X] Livestream tutorial (depends on RTMP support) (Thierry)
- [X] local version of audioLevel(s) for lower latency audio visualizations(Daniel)
Expand All @@ -115,6 +115,7 @@ Video roadmap and changelog is available [here](https://github.com/GetStream/pro

### 0.4.0 milestone

- [ ] Complete Livestreaming APIs and Tutorials for hosting & watching
- [ ] Android SDK development.md cleanup (Daniel)
- [ ] Upgrade to more recent versions of webrtc (Kanat)
- [ ] Picture of the video stream at highest resolution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: How to watch a livestream on android with Kotlin
This cookbook tutorial walks you through how to build an advanced UIs for watching a livestream on Android.

:::note
n this cookbook tutorial, we will assume that you already know how to join a livestream call. If you haven't familiarized yourself with the [Livestream Tutorial](../02-tutorials/03-livestream.mdx) yet, we highly recommend doing so before proceeding with this cookbook.
In this cookbook tutorial, we will assume that you already know how to join a livestream call. If you haven't familiarized yourself with the [Livestream Tutorial](../02-tutorials/03-livestream.mdx) yet, we highly recommend doing so before proceeding with this cookbook.
:::

When you build a livestreaming UI, there are a few things to keep in mind:
Expand Down
4 changes: 4 additions & 0 deletions dogfooding/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ dependencies {
implementation(libs.androidx.compose.material.iconsExtended)
implementation(libs.androidx.hilt.navigation)
implementation(libs.landscapist.coil)
implementation(libs.accompanist.permission)

// hilt
implementation(libs.hilt.android)
Expand All @@ -252,6 +253,9 @@ dependencies {
// Play Install Referrer library - used to extract the meeting link from demo flow after install
implementation(libs.play.install.referrer)

// Only used for launching a QR code scanner in demo app
implementation(libs.play.code.scanner)

// memory detection
debugImplementation(libs.leakCanary)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

package io.getstream.video.android.ui.join

import android.net.Uri
import android.widget.Toast
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
Expand All @@ -36,9 +38,12 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.TextField
Expand Down Expand Up @@ -67,7 +72,12 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import com.google.android.gms.tasks.OnSuccessListener
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions
import com.google.mlkit.vision.codescanner.GmsBarcodeScanning
import io.getstream.video.android.BuildConfig
import io.getstream.video.android.DeeplinkingActivity
import io.getstream.video.android.R
import io.getstream.video.android.compose.theme.VideoTheme
import io.getstream.video.android.compose.ui.components.avatar.UserAvatar
Expand All @@ -86,6 +96,8 @@ fun CallJoinScreen(
) {
val uiState by callJoinViewModel.uiState.collectAsState(CallJoinUiState.Nothing)
val isLoggedOut by callJoinViewModel.isLoggedOut.collectAsState(initial = false)
val qrCodeCallback = rememberQrCodeCallback()
val context = LocalContext.current

HandleCallJoinUiState(
callJoinUiState = uiState,
Expand All @@ -111,6 +123,12 @@ fun CallJoinScreen(
.verticalScroll(rememberScrollState())
.weight(1f),
callJoinViewModel = callJoinViewModel,
openCamera = {
val options = GmsBarcodeScannerOptions.Builder()
.setBarcodeFormats(Barcode.FORMAT_QR_CODE, Barcode.FORMAT_AZTEC).build()
val scanner = GmsBarcodeScanning.getClient(context, options)
scanner.startScan().addOnSuccessListener(qrCodeCallback)
},
)
}

Expand Down Expand Up @@ -174,6 +192,7 @@ private fun CallJoinHeader(
@Composable
private fun CallJoinBody(
modifier: Modifier,
openCamera: () -> Unit,
callJoinViewModel: CallJoinViewModel = hiltViewModel(),
) {
val user by if (LocalInspectionMode.current) {
Expand Down Expand Up @@ -217,7 +236,7 @@ private fun CallJoinBody(
color = Colors.description,
textAlign = TextAlign.Center,
fontSize = 18.sp,
modifier = Modifier.widthIn(0.dp, 350.dp),
modifier = Modifier.widthIn(0.dp, 320.dp),
)

Spacer(modifier = Modifier.height(42.dp))
Expand Down Expand Up @@ -258,7 +277,24 @@ private fun CallJoinBody(
),
shape = RoundedCornerShape(6.dp),
value = callId,
singleLine = true,
onValueChange = { callId = it },
trailingIcon = {
IconButton(
onClick = openCamera,
modifier = Modifier.fillMaxHeight(),
content = {
Icon(
painter = painterResource(id = R.drawable.ic_scan_qr),
contentDescription = stringResource(
id = R.string.join_call_by_qr_code,
),
tint = Colors.description,
modifier = Modifier.size(36.dp),
)
},
)
},
colors = TextFieldDefaults.textFieldColors(
textColor = Color.White,
focusedLabelColor = VideoTheme.colors.primaryAccent,
Expand All @@ -275,6 +311,11 @@ private fun CallJoinBody(
color = Color(0xFF5D6168),
)
},
keyboardActions = KeyboardActions(
onDone = {
callJoinViewModel.handleUiEvent(CallJoinEvent.JoinCall(callId = callId))
},
),
)

StreamButton(
Expand Down Expand Up @@ -333,6 +374,37 @@ private fun HandleCallJoinUiState(
}
}

@Composable
private fun rememberQrCodeCallback(): OnSuccessListener<Barcode> {
val context = LocalContext.current

return remember {
OnSuccessListener<Barcode> {
val url = it.url?.url
val callId = if (url != null) {
val id = Uri.parse(url).getQueryParameter("id")
if (!id.isNullOrEmpty()) {
id
} else {
null
}
} else {
null
}

if (!callId.isNullOrEmpty()) {
context.startActivity(DeeplinkingActivity.createIntent(context, callId))
} else {
Toast.makeText(
context,
"Unrecognised meeting QR code format",
Toast.LENGTH_SHORT,
).show()
}
}
}
}

@Preview
@Composable
private fun CallJoinScreenPreview() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,26 +231,20 @@ private fun CallLobbyBody(
isMicrophoneEnabled = isMicrophoneEnabled,
onCallAction = { action ->
when (action) {
is ToggleCamera -> callLobbyViewModel.enableCamera(!isCameraEnabled)
is ToggleMicrophone -> callLobbyViewModel.enableMicrophone(!isMicrophoneEnabled)
is ToggleCamera -> callLobbyViewModel.enableCamera(action.isEnabled)
is ToggleMicrophone -> callLobbyViewModel.enableMicrophone(action.isEnabled)
else -> Unit
}
},
)

LobbyDescription(
callLobbyViewModel = callLobbyViewModel,
cameraEnabled = isCameraEnabled,
microphoneEnabled = isMicrophoneEnabled,
)
LobbyDescription(callLobbyViewModel = callLobbyViewModel)
}
}

@Composable
private fun LobbyDescription(
callLobbyViewModel: CallLobbyViewModel,
cameraEnabled: Boolean,
microphoneEnabled: Boolean,
) {
val session by callLobbyViewModel.call.state.session.collectAsState()

Expand Down Expand Up @@ -280,10 +274,7 @@ private fun LobbyDescription(
text = stringResource(id = R.string.join_call),
onClick = {
callLobbyViewModel.handleUiEvent(
CallLobbyEvent.JoinCall(
cameraEnabled = cameraEnabled,
microphoneEnabled = microphoneEnabled,
),
CallLobbyEvent.JoinCall,
)
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,10 @@ class CallLobbyViewModel @Inject constructor(
is CallLobbyEvent.JoinCall -> {
flowOf(CallLobbyUiState.JoinCompleted)
}

is CallLobbyEvent.JoinFailed -> {
flowOf(CallLobbyUiState.JoinFailed(event.reason))
}
else -> flowOf(CallLobbyUiState.Nothing)
}
}
.onCompletion { _isLoading.value = false }
Expand Down Expand Up @@ -178,17 +178,16 @@ class CallLobbyViewModel @Inject constructor(
}

sealed interface CallLobbyUiState {
object Nothing : CallLobbyUiState
data object Nothing : CallLobbyUiState

object JoinCompleted : CallLobbyUiState
data object JoinCompleted : CallLobbyUiState

data class JoinFailed(val reason: String?) : CallLobbyUiState
}

sealed interface CallLobbyEvent {
object Nothing : CallLobbyEvent

class JoinCall(val cameraEnabled: Boolean, val microphoneEnabled: Boolean) : CallLobbyEvent
data object JoinCall : CallLobbyEvent

data class JoinFailed(val reason: String?) : CallLobbyEvent
}
25 changes: 25 additions & 0 deletions dogfooding/src/main/res/drawable/ic_scan_qr.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2023 Stream.io Inc. All rights reserved.
Licensed under the Stream License;
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/GetStream/stream-video-android/blob/main/LICENSE
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M16.167,6C16.075,6 16,6.075 16,6.167L16,7.833C16,7.925 16.075,8 16.167,8L17.833,8C17.925,8 18,7.925 18,7.833L18,6.167C18,6.075 17.925,6 17.833,6L16.167,6ZM16,18L16,17.5C16,17.224 16.224,17 16.5,17C16.776,17 17,17.224 17,17.5L17,18L18,18L18,17.5C18,17.224 18.224,17 18.5,17C18.776,17 19,17.224 19,17.5L19,18.5C19,18.776 18.776,19 18.5,19L14.5,19C14.224,19 14,18.776 14,18.5L14,17.5C14,17.224 14.224,17 14.5,17C14.776,17 15,17.224 15,17.5L15,18L16,18L16,18ZM13,11L13.5,11C13.776,11 14,11.224 14,11.5C14,11.776 13.776,12 13.5,12L11.5,12C11.224,12 11,11.776 11,11.5C11,11.224 11.224,11 11.5,11L12,11L12,10L10.5,10C10.224,10 10,9.776 10,9.5C10,9.224 10.224,9 10.5,9L13.5,9C13.776,9 14,9.224 14,9.5C14,9.776 13.776,10 13.5,10L13,10L13,11ZM18,12L17.5,12C17.224,12 17,11.776 17,11.5C17,11.224 17.224,11 17.5,11L18,11L18,10.5C18,10.224 18.224,10 18.5,10C18.776,10 19,10.224 19,10.5L19,12.5C19,12.776 18.776,13 18.5,13C18.224,13 18,12.776 18,12.5L18,12ZM13,14L12.5,14C12.224,14 12,13.776 12,13.5C12,13.224 12.224,13 12.5,13L13.5,13C13.776,13 14,13.224 14,13.5L14,15.5C14,15.776 13.776,16 13.5,16L10.5,16C10.224,16 10,15.776 10,15.5C10,15.224 10.224,15 10.5,15L13,15L13,14L13,14ZM16.167,5L17.833,5C18.478,5 19,5.522 19,6.167L19,7.833C19,8.478 18.478,9 17.833,9L16.167,9C15.522,9 15,8.478 15,7.833L15,6.167C15,5.522 15.522,5 16.167,5ZM6.167,5L7.833,5C8.478,5 9,5.522 9,6.167L9,7.833C9,8.478 8.478,9 7.833,9L6.167,9C5.522,9 5,8.478 5,7.833L5,6.167C5,5.522 5.522,5 6.167,5ZM6.167,6C6.075,6 6,6.075 6,6.167L6,7.833C6,7.925 6.075,8 6.167,8L7.833,8C7.925,8 8,7.925 8,7.833L8,6.167C8,6.075 7.925,6 7.833,6L6.167,6ZM6.167,15L7.833,15C8.478,15 9,15.522 9,16.167L9,17.833C9,18.478 8.478,19 7.833,19L6.167,19C5.522,19 5,18.478 5,17.833L5,16.167C5,15.522 5.522,15 6.167,15ZM6.167,16C6.075,16 6,16.075 6,16.167L6,17.833C6,17.925 6.075,18 6.167,18L7.833,18C7.925,18 8,17.925 8,17.833L8,16.167C8,16.075 7.925,16 7.833,16L6.167,16ZM13,6L10.5,6C10.224,6 10,5.776 10,5.5C10,5.224 10.224,5 10.5,5L13.5,5C13.776,5 14,5.224 14,5.5L14,7.5C14,7.776 13.776,8 13.5,8C13.224,8 13,7.776 13,7.5L13,6ZM10.5,8C10.224,8 10,7.776 10,7.5C10,7.224 10.224,7 10.5,7L11.5,7C11.776,7 12,7.224 12,7.5C12,7.776 11.776,8 11.5,8L10.5,8ZM5.5,14C5.224,14 5,13.776 5,13.5C5,13.224 5.224,13 5.5,13L7.5,13C7.776,13 8,13.224 8,13.5C8,13.776 7.776,14 7.5,14L5.5,14ZM9.5,14C9.224,14 9,13.776 9,13.5C9,13.224 9.224,13 9.5,13L10.5,13C10.776,13 11,13.224 11,13.5C11,13.776 10.776,14 10.5,14L9.5,14ZM11,18L11,18.5C11,18.776 10.776,19 10.5,19C10.224,19 10,18.776 10,18.5L10,17.5C10,17.224 10.224,17 10.5,17L12.5,17C12.776,17 13,17.224 13,17.5C13,17.776 12.776,18 12.5,18L11,18ZM9,11L9.5,11C9.776,11 10,11.224 10,11.5C10,11.776 9.776,12 9.5,12L8.5,12C8.224,12 8,11.776 8,11.5L8,11L7.5,11C7.224,11 7,10.776 7,10.5C7,10.224 7.224,10 7.5,10L8.5,10C8.776,10 9,10.224 9,10.5L9,11ZM5,10.5C5,10.224 5.224,10 5.5,10C5.776,10 6,10.224 6,10.5L6,11.5C6,11.776 5.776,12 5.5,12C5.224,12 5,11.776 5,11.5L5,10.5ZM15,10.5C15,10.224 15.224,10 15.5,10C15.776,10 16,10.224 16,10.5L16,12.5C16,12.776 15.776,13 15.5,13C15.224,13 15,12.776 15,12.5L15,10.5ZM17,15L17,14.5C17,14.224 17.224,14 17.5,14L18.5,14C18.776,14 19,14.224 19,14.5C19,14.776 18.776,15 18.5,15L18,15L18,15.5C18,15.776 17.776,16 17.5,16L15.5,16C15.224,16 15,15.776 15,15.5L15,14.5C15,14.224 15.224,14 15.5,14C15.776,14 16,14.224 16,14.5L16,15L17,15ZM3,6.5C3,6.776 2.776,7 2.5,7C2.224,7 2,6.776 2,6.5L2,4.5C2,3.119 3.119,2 4.5,2L6.5,2C6.776,2 7,2.224 7,2.5C7,2.776 6.776,3 6.5,3L4.5,3C3.672,3 3,3.672 3,4.5L3,6.5ZM17.5,3C17.224,3 17,2.776 17,2.5C17,2.224 17.224,2 17.5,2L19.5,2C20.881,2 22,3.119 22,4.5L22,6.5C22,6.776 21.776,7 21.5,7C21.224,7 21,6.776 21,6.5L21,4.5C21,3.672 20.328,3 19.5,3L17.5,3ZM6.5,21C6.776,21 7,21.224 7,21.5C7,21.776 6.776,22 6.5,22L4.5,22C3.119,22 2,20.881 2,19.5L2,17.5C2,17.224 2.224,17 2.5,17C2.776,17 3,17.224 3,17.5L3,19.5C3,20.328 3.672,21 4.5,21L6.5,21ZM21,17.5C21,17.224 21.224,17 21.5,17C21.776,17 22,17.224 22,17.5L22,19.5C22,20.881 20.881,22 19.5,22L17.5,22C17.224,22 17,21.776 17,21.5C17,21.224 17.224,21 17.5,21L19.5,21C20.328,21 21,20.328 21,19.5L21,17.5Z"/>
</vector>
1 change: 1 addition & 0 deletions dogfooding/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<string name="sign_out">Sign out</string>
<string name="join_description">Build reliable video calling, audio rooms, and live streaming with our easy-to-use SDKs and global edge network</string>
<string name="join_call">Join Call</string>
<string name="join_call_by_qr_code">Scan QR meeting code</string>
<string name="join_call_description">You are about to join a call. %d more people are in the call.</string>
<string name="join_call_no_id_hint">Don\'t have a Call ID?</string>
<string name="join_call_call_id_hint">Call ID</string>
Expand Down
18 changes: 10 additions & 8 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[versions]
androidGradlePlugin = "8.1.0"
spotless = "6.20.0"
androidGradlePlugin = "8.1.1"
spotless = "6.21.0"
nexusPlugin = "1.3.0"
kotlin = "1.9.0"
kotlinSerialization = "1.5.1"
kotlin = "1.9.10"
kotlinSerialization = "1.6.0"
kotlinSerializationConverter = "1.0.0"
kotlinxCoroutines = "1.7.3"

Expand All @@ -21,14 +21,14 @@ androidxDataStore = "1.0.0"
googleService = "4.3.14"

androidxComposeBom = "2023.08.00"
androidxComposeCompiler = "1.5.2"
androidxComposeCompiler = "1.5.3"
androidxComposeTracing = "1.0.0-alpha03"
androidxHiltNavigation = "1.0.0"
androidxComposeNavigation = "2.7.0"
composeStableMarker = "1.0.0"

coil = "2.2.2"
landscapist = "2.2.7"
coil = "2.4.0"
landscapist = "2.2.8"
accompanist = "0.30.1"
telephoto = "0.3.0"
audioswitch = "1.1.8"
Expand All @@ -50,7 +50,7 @@ streamPush = "1.1.1"
androidxTest = "1.5.2"
androidxTestCore = "1.5.0"
androidxProfileinstaller = "1.3.1"
androidxMacroBenchmark = "1.2.0-beta03"
androidxMacroBenchmark = "1.2.0-beta05"
androidxUiAutomator = "2.3.0-alpha04"
androidxContraintLayout = "2.1.4"
androidxEspresso = "3.5.1"
Expand All @@ -65,6 +65,7 @@ firebaseBom = "32.1.0"
firebaseCrashlytics = "2.9.5"

installReferrer = "2.2"
playCodeScanner = "16.1.0"

hilt = "2.46.1"
desugar = "2.0.3"
Expand Down Expand Up @@ -178,6 +179,7 @@ firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashly
firebase-analyrics = { group = "com.google.firebase", name = "firebase-analytics-ktx" }

play-install-referrer = { group = "com.android.installreferrer", name = "installreferrer", version.ref = "installReferrer" }
play-code-scanner = { group = "com.google.android.gms", name = "play-services-code-scanner", version.ref = "playCodeScanner" }

robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "robolectric" }
leakCanary = { group = "com.squareup.leakcanary", name = "leakcanary-android", version.ref = "leakCanary" }
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
3 changes: 2 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading

0 comments on commit ebcdea7

Please sign in to comment.