Skip to content

Commit

Permalink
add video capture
Browse files Browse the repository at this point in the history
  • Loading branch information
lokified committed Sep 4, 2023
1 parent 5b3dd40 commit 79ab382
Show file tree
Hide file tree
Showing 24 changed files with 1,156 additions and 496 deletions.
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
xmlns:tools="http://schemas.android.com/tools">

<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.telephony"/>

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>

<application
Expand Down
41 changes: 38 additions & 3 deletions core/navigation/src/main/java/com/loki/navigation/Navigation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import com.loki.auth.login.LoginScreen
import com.loki.auth.login.LoginViewModel
import com.loki.auth.register.RegisterScreen
import com.loki.auth.register.RegisterViewModel
import com.loki.camera.CameraScreen
import com.loki.camera.camera_screen.CameraScreen
import com.loki.camera.video_screen.VideoPlayerScreen
import com.loki.camera.video_screen.VideoPlayerViewModel
import com.loki.home.home.HomeScreen
import com.loki.home.report_list.ReportListScreen
import com.loki.home.report_list.ReportListViewModel
Expand All @@ -38,6 +40,7 @@ import com.loki.report.ReportViewModel
import com.loki.settings.SettingsScreen
import com.loki.settings.SettingsViewModel
import com.loki.ui.utils.Constants.REPORT_ID
import com.loki.ui.utils.Constants.VIDEO_URI
import kotlinx.coroutines.delay

fun NavGraphBuilder.homeNavGraph(viewModel: NavigationViewModel,onNavigateToLogin: (Screen) -> Unit) {
Expand Down Expand Up @@ -302,7 +305,7 @@ fun NavGraphBuilder.settingsScreen(onNavigateBack: () -> Unit, viewModel: Naviga
}
}

fun NavGraphBuilder.cameraScreen(onNavigateBack: () -> Unit,viewModel: NavigationViewModel) {
fun NavGraphBuilder.cameraScreen(onNavigateBack: () -> Unit, onNavigateTo: (Screen) -> Unit, viewModel: NavigationViewModel) {
composable(
route = Screen.CameraScreen.route,
enterTransition = {
Expand All @@ -324,7 +327,39 @@ fun NavGraphBuilder.cameraScreen(onNavigateBack: () -> Unit,viewModel: Navigatio
val profileViewModel = hiltViewModel<ProfileViewModel>()
CameraScreen(
navigateBack = onNavigateBack,
profileViewModel = profileViewModel
profileViewModel = profileViewModel,
navigateToVideoPlayer = { videoUri ->
onNavigateTo(Screen.VideoPlayerScreen.navWith(videoUri))
}
)
}
}

fun NavGraphBuilder.videoPlayerScreen(viewModel: NavigationViewModel) {
composable(
route = Screen.VideoPlayerScreen.withVideoUri(),
arguments = listOf(
navArgument(VIDEO_URI) {
type = NavType.StringType
}
),
enterTransition = {
slideIntoContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Down,
animationSpec = tween(500)
)
},
exitTransition = {
slideOutOfContainer(
towards = AnimatedContentTransitionScope.SlideDirection.Down,
animationSpec = tween(200)
)
}
) {
LaunchedEffect(key1 = viewModel.isBottomBarVisible.value) {
viewModel.setBottomBarVisible(false)
}
val videoPlayerViewModel = hiltViewModel<VideoPlayerViewModel>()
VideoPlayerScreen(viewModel = videoPlayerViewModel)
}
}
8 changes: 7 additions & 1 deletion core/navigation/src/main/java/com/loki/navigation/Screen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Newspaper
import androidx.compose.ui.graphics.vector.ImageVector
import com.loki.ui.utils.Constants.REPORT_ID
import com.loki.ui.utils.Constants.VIDEO_URI

sealed class Screen(
val route: String,
Expand All @@ -24,17 +25,22 @@ sealed class Screen(
return "${ReportScreen.route}/{$REPORT_ID}"
}

fun withVideoUri(): String {
return "${VideoPlayerScreen.route}/{$VIDEO_URI}"
}

object LoginScreen: Screen("login_screen")
object RegisterScreen: Screen("register_screen")
object ForgotPasswordScreen: Screen("forgot_password_screen")
object HomeScreen: Screen("home_screen")
object ReportListScreen: Screen(route = "report_list_screen", title = "Home", icon = Icons.Filled.Home)
object ReportListScreen: Screen(route = "report_list_screen", title = "Home", icon = Icons.Filled.Home, restoreState = false)
object NewsScreen: Screen(route = "news_screen", title = "News", restoreState = false, icon = Icons.Filled.Newspaper)
object NewReportScreen: Screen("new_report_screen")
object ReportScreen: Screen("report_screen", restoreState = false)
object ProfileScreen: Screen("profile_screen", title = "Profile", icon = Icons.Filled.AccountCircle)
object UsernameChangeScreen: Screen("change_username_screen")
object SettingsScreen: Screen("settings_screen")
object CameraScreen: Screen("camera_screen")
object VideoPlayerScreen: Screen("video_player_screen")

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.loki.navigation.ext.navigateTo
import com.loki.navigation.profileScreen
import com.loki.navigation.settingsScreen
import com.loki.navigation.usernameChangeScreen
import com.loki.navigation.videoPlayerScreen

@Composable
fun AccountNavGraph(
Expand All @@ -28,6 +29,7 @@ fun AccountNavGraph(
profileScreen(onNavigateTo = navController::navigateTo, viewModel = viewModel, onNavigateToLogin = onNavigateToLogin)
usernameChangeScreen(onNavigateBack = navController::navigateUp, viewModel = viewModel)
settingsScreen(onNavigateBack = navController::navigateUp, viewModel = viewModel)
cameraScreen(onNavigateBack = navController::navigateUp, viewModel = viewModel)
cameraScreen(onNavigateBack = navController::navigateUp, onNavigateTo = navController::navigateTo, viewModel = viewModel)
videoPlayerScreen(viewModel = viewModel)
}
}
83 changes: 83 additions & 0 deletions core/ui/src/main/java/com/loki/ui/components/NotificationBubble.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.loki.ui.components

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import com.loki.ui.theme.md_theme_light_primary
import kotlinx.coroutines.delay

@Composable
fun NotificationBubble(
modifier: Modifier = Modifier,
message: String = ""
) {

var isBubbleVisible by remember { mutableStateOf(false) }
var mess by remember { mutableStateOf(message) }

LaunchedEffect(key1 = mess) {

isBubbleVisible = true

delay(3000L)

isBubbleVisible = false
mess = ""
}

AnimatedVisibility(
visible = isBubbleVisible,
enter = slideInVertically { -(it / 2) },
exit = slideOutVertically { 0 }
) {
Box(modifier = Modifier.fillMaxSize()) {
Box(
modifier = modifier
.fillMaxWidth()
.padding(
horizontal = 24.dp,
vertical = 16.dp
)
.clip(RoundedCornerShape(12.dp))
.height(70.dp)
.background(md_theme_light_primary.copy(.5f))
.border(
border = BorderStroke(width = 1.dp, color = md_theme_light_primary),
shape = RoundedCornerShape(12.dp)
)
.alpha(1f)
.align(Alignment.TopCenter),
contentAlignment = Alignment.CenterStart
) {

Text(
text = message,
color = md_theme_light_primary,
modifier = Modifier.padding(horizontal = 16.dp)
)

}
}
}
}
85 changes: 53 additions & 32 deletions core/ui/src/main/java/com/loki/ui/permission/PermissionDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,50 +18,71 @@ import androidx.core.content.ContextCompat
@Composable
fun PermissionDialog(
context: Context,
permission: String,
permissionRationale: String,
permissions: List<String>,
permissionRationale: Map<String, String>,
snackbarHostState: SnackbarHostState,
permissionAction: (PermissionAction) -> Unit
permissionAction: (Map<String,PermissionAction>) -> Unit
) {

val isPermissionGranted = checkIfPermissionGranted(context, permission)
val grantedPermissions = mutableMapOf<String, PermissionAction>()

if (isPermissionGranted) {
permissionAction(PermissionAction.PermissionAlreadyGranted)
return
}
permissions.forEach { permission ->
val isPermissionGranted = checkIfPermissionGranted(context, permission)

val permissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
permissionAction(PermissionAction.PermissionGranted)
if (isPermissionGranted) {
grantedPermissions[permission] = PermissionAction.PermissionAlreadyGranted
}
else {
permissionAction(PermissionAction.PermissionDenied)
}
}

val showPermissionRationale = shouldShowPermissionRationale(context, permission)
val permissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->

if (showPermissionRationale) {
LaunchedEffect(key1 = showPermissionRationale ) {
val snackbarResult = snackbarHostState.showSnackbar(
message = permissionRationale,
actionLabel = "Grant Access",
duration = SnackbarDuration.Long
val action = if (isGranted) {
PermissionAction.PermissionGranted
} else {
PermissionAction.PermissionDenied
}

)
grantedPermissions[permission] = action

when(snackbarResult) {
SnackbarResult.Dismissed -> permissionAction(PermissionAction.PermissionDenied)
SnackbarResult.ActionPerformed -> permissionLauncher.launch(permission)
//checks if we all collected responses for all permission
if (grantedPermissions.size == permissions.size) {
permissionAction(grantedPermissions)
}
}

val showPermissionRationale = shouldShowPermissionRationale(context, permission)

if (showPermissionRationale) {
LaunchedEffect(key1 = showPermissionRationale ) {

val rationale = permissionRationale[permission]
val snackbarResult = snackbarHostState.showSnackbar(
message = rationale ?: "Permission Required",
actionLabel = "Grant Access",
duration = SnackbarDuration.Long

)

when(snackbarResult) {
SnackbarResult.Dismissed -> {
grantedPermissions[permission] = PermissionAction.PermissionDenied

// Check if we have collected responses for all permissions
if (grantedPermissions.size == permissions.size) {
permissionAction(grantedPermissions)
}
}
SnackbarResult.ActionPerformed -> permissionLauncher.launch(permission)
}
}
}
else {
SideEffect {
permissionLauncher.launch(permission)
}
}
}
}
else {
SideEffect {
permissionLauncher.launch(permission)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions core/ui/src/main/java/com/loki/ui/utils/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package com.loki.ui.utils
object Constants {

const val REPORT_ID = "reportId"
const val VIDEO_URI = "videoUri"
}
5 changes: 5 additions & 0 deletions core/ui/src/main/java/com/loki/ui/utils/DateUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ object DateUtil {
return dateFormat.format(date)
}

fun getFileName(): String {
return SimpleDateFormat(FILE_NAME_FORMAT, Locale.ENGLISH).format(System.currentTimeMillis())
}

private const val DATE_FORMAT = "EEE, d MMM yyyy"
private const val TIME_FORMAT = "hh:mm a"
private const val FILE_NAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
}
4 changes: 0 additions & 4 deletions core/ui/src/main/java/com/loki/ui/viewmodel/ReetViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
package com.loki.ui.viewmodel

import android.util.Log
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.firebase.FirebaseException
import com.loki.local.datastore.DataStoreStorage
import com.loki.local.datastore.model.LocalProfile
import com.loki.local.datastore.model.LocalUser
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject


open class ReetViewModel(
private val dataStore: DataStoreStorage
Expand Down
1 change: 1 addition & 0 deletions di/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ dependencies {
implementation(libs.androidx.datastore)

implementation(libs.bundles.retrofit)
implementation(libs.bundles.exoPlayer)

testImplementation(libs.bundles.test.common)
androidTestImplementation(libs.bundles.android.test)
Expand Down
22 changes: 22 additions & 0 deletions di/src/main/java/com/loki/di/VideoPlayerModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.loki.di

import android.app.Application
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
import dagger.hilt.android.scopes.ViewModelScoped

@Module
@InstallIn(ViewModelComponent::class)
object VideoPlayerModule {

@Provides
@ViewModelScoped
fun provideVideoPlayer(app: Application): Player {
return ExoPlayer.Builder(app)
.build()
}
}
Loading

0 comments on commit 79ab382

Please sign in to comment.