├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── de │ │ └── yanneckreiss │ │ └── mlkittutorial │ │ ├── MainActivity.kt │ │ └── ui │ │ ├── MainScreen.kt │ │ ├── camera │ │ ├── CameraScreen.kt │ │ └── TextRecognitionAnalyzer.kt │ │ ├── no_permission │ │ └── NoPermissionScreen.kt │ │ └── theme │ │ ├── Color.kt │ │ ├── Theme.kt │ │ └── Type.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-mdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | local.properties 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jetpack Compose CameraX ML-Kit ShowCase 2 | 3 | This is a sample app for real-time text recognition, based on the device's camera stream. 4 | 5 | It's purpose is to showcase how to use [Google's ML-Kit](https://developers.google.com/ml-kit) with Jetpack Compose. 6 | 7 | If you want to learn more, make sure to check out [my YouTube video on this topic](https://youtu.be/wCADCaeS8-A)! 8 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | } 5 | 6 | android { 7 | namespace 'de.yanneckreiss.cameraxtutorial' 8 | compileSdk 34 9 | 10 | defaultConfig { 11 | applicationId "de.yanneckreiss.cameraxtutorial" 12 | minSdk 28 13 | targetSdk 34 14 | versionCode 1 15 | versionName "1.0.0" 16 | 17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | vectorDrawables { 19 | useSupportLibrary true 20 | } 21 | } 22 | 23 | buildTypes { 24 | release { 25 | minifyEnabled false 26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | compileOptions { 30 | sourceCompatibility JavaVersion.VERSION_17 31 | targetCompatibility JavaVersion.VERSION_17 32 | } 33 | kotlinOptions { 34 | jvmTarget = '17' 35 | } 36 | buildFeatures { 37 | compose true 38 | buildConfig = true 39 | } 40 | composeOptions { 41 | kotlinCompilerExtensionVersion '1.5.1' 42 | } 43 | packagingOptions { 44 | resources { 45 | excludes += '/META-INF/{AL2.0,LGPL2.1}' 46 | } 47 | } 48 | } 49 | 50 | dependencies { 51 | 52 | lintChecks("com.slack.lint.compose:compose-lint-checks:1.2.0") 53 | 54 | implementation 'androidx.core:core-ktx:1.10.1' 55 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' 56 | implementation 'androidx.activity:activity-compose:1.7.2' 57 | 58 | implementation platform('androidx.compose:compose-bom:2023.06.01') 59 | implementation 'androidx.compose.ui:ui' 60 | implementation 'androidx.compose.ui:ui-graphics' 61 | implementation 'androidx.compose.ui:ui-tooling-preview' 62 | implementation 'androidx.compose.material3:material3' 63 | implementation "androidx.compose.material:material-icons-extended" 64 | implementation 'androidx.compose.material:material:1.4.3' 65 | implementation 'androidx.cardview:cardview:1.0.0' 66 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 67 | 68 | debugImplementation 'androidx.compose.ui:ui-tooling' 69 | debugImplementation 'androidx.compose.ui:ui-test-manifest' 70 | 71 | ///// LIFECYCLE ///// 72 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" 73 | implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version" 74 | implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version" 75 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" 76 | implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version" 77 | 78 | //// CAMERA STUFF //// 79 | implementation "androidx.camera:camera-camera2:$camerax_version" 80 | implementation "androidx.camera:camera-lifecycle:$camerax_version" 81 | implementation "androidx.camera:camera-view:$camerax_version" 82 | implementation "androidx.camera:camera-extensions:$camerax_version" 83 | 84 | //// ML-KIT //// 85 | implementation 'com.google.mlkit:text-recognition:16.0.0' 86 | 87 | //// ACCOMPANIST //// 88 | implementation "com.google.accompanist:accompanist-permissions:$accompanist_version" 89 | 90 | testImplementation 'junit:junit:4.13.2' 91 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 92 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 93 | androidTestImplementation platform('androidx.compose:compose-bom:2022.10.00') 94 | androidTestImplementation 'androidx.compose.ui:ui-test-junit4' 95 | debugImplementation 'androidx.compose.ui:ui-tooling' 96 | debugImplementation 'androidx.compose.ui:ui-test-manifest' 97 | } 98 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/java/de/yanneckreiss/mlkittutorial/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package de.yanneckreiss.mlkittutorial 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.foundation.layout.fillMaxSize 7 | import androidx.compose.material3.MaterialTheme 8 | import androidx.compose.material3.Surface 9 | import androidx.compose.ui.Modifier 10 | import de.yanneckreiss.mlkittutorial.ui.MainScreen 11 | import de.yanneckreiss.mlkittutorial.ui.theme.JetpackComposeMLKitTutorialTheme 12 | 13 | class MainActivity : ComponentActivity() { 14 | 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | 18 | setContent { 19 | JetpackComposeMLKitTutorialTheme { 20 | Surface( 21 | modifier = Modifier.fillMaxSize(), 22 | color = MaterialTheme.colorScheme.background 23 | ) { 24 | MainScreen() 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/de/yanneckreiss/mlkittutorial/ui/MainScreen.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(ExperimentalPermissionsApi::class) 2 | 3 | package de.yanneckreiss.mlkittutorial.ui 4 | 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.ui.tooling.preview.Preview 7 | import com.google.accompanist.permissions.ExperimentalPermissionsApi 8 | import com.google.accompanist.permissions.PermissionState 9 | import com.google.accompanist.permissions.isGranted 10 | import com.google.accompanist.permissions.rememberPermissionState 11 | import de.yanneckreiss.mlkittutorial.ui.camera.CameraScreen 12 | import de.yanneckreiss.mlkittutorial.ui.no_permission.NoPermissionScreen 13 | 14 | @Composable 15 | fun MainScreen() { 16 | 17 | val cameraPermissionState: PermissionState = rememberPermissionState(android.Manifest.permission.CAMERA) 18 | 19 | MainContent( 20 | hasPermission = cameraPermissionState.status.isGranted, 21 | onRequestPermission = cameraPermissionState::launchPermissionRequest 22 | ) 23 | } 24 | 25 | @Composable 26 | private fun MainContent( 27 | hasPermission: Boolean, 28 | onRequestPermission: () -> Unit 29 | ) { 30 | 31 | if (hasPermission) { 32 | CameraScreen() 33 | } else { 34 | NoPermissionScreen(onRequestPermission) 35 | } 36 | } 37 | 38 | @Preview 39 | @Composable 40 | private fun Preview_MainContent() { 41 | MainContent( 42 | hasPermission = true, 43 | onRequestPermission = {} 44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/de/yanneckreiss/mlkittutorial/ui/camera/CameraScreen.kt: -------------------------------------------------------------------------------- 1 | package de.yanneckreiss.mlkittutorial.ui.camera 2 | 3 | import android.content.Context 4 | import android.graphics.Color 5 | import android.view.ViewGroup 6 | import android.widget.LinearLayout 7 | import androidx.camera.core.AspectRatio 8 | import androidx.camera.view.CameraController 9 | import androidx.camera.view.LifecycleCameraController 10 | import androidx.camera.view.PreviewView 11 | import androidx.compose.foundation.background 12 | import androidx.compose.foundation.layout.Box 13 | import androidx.compose.foundation.layout.PaddingValues 14 | import androidx.compose.foundation.layout.fillMaxSize 15 | import androidx.compose.foundation.layout.fillMaxWidth 16 | import androidx.compose.foundation.layout.padding 17 | import androidx.compose.material.Scaffold 18 | import androidx.compose.material.Text 19 | import androidx.compose.material.TopAppBar 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.runtime.getValue 22 | import androidx.compose.runtime.mutableStateOf 23 | import androidx.compose.runtime.remember 24 | import androidx.compose.runtime.setValue 25 | import androidx.compose.ui.Modifier 26 | import androidx.compose.ui.platform.LocalContext 27 | import androidx.compose.ui.platform.LocalLifecycleOwner 28 | import androidx.compose.ui.unit.dp 29 | import androidx.compose.ui.viewinterop.AndroidView 30 | import androidx.core.content.ContextCompat 31 | import androidx.lifecycle.LifecycleOwner 32 | 33 | @Composable 34 | fun CameraScreen() { 35 | CameraContent() 36 | } 37 | 38 | @Composable 39 | private fun CameraContent() { 40 | 41 | val context: Context = LocalContext.current 42 | val lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current 43 | val cameraController: LifecycleCameraController = remember { LifecycleCameraController(context) } 44 | var detectedText: String by remember { mutableStateOf("No text detected yet..") } 45 | 46 | fun onTextUpdated(updatedText: String) { 47 | detectedText = updatedText 48 | } 49 | 50 | Scaffold( 51 | modifier = Modifier.fillMaxSize(), 52 | topBar = { TopAppBar(title = { Text("Text Scanner") }) }, 53 | ) { paddingValues: PaddingValues -> 54 | Box( 55 | modifier = Modifier.fillMaxSize(), 56 | contentAlignment = androidx.compose.ui.Alignment.BottomCenter 57 | ) { 58 | 59 | AndroidView( 60 | modifier = Modifier 61 | .fillMaxSize() 62 | .padding(paddingValues), 63 | factory = { context -> 64 | PreviewView(context).apply { 65 | layoutParams = LinearLayout.LayoutParams( 66 | ViewGroup.LayoutParams.MATCH_PARENT, 67 | ViewGroup.LayoutParams.MATCH_PARENT 68 | ) 69 | setBackgroundColor(Color.BLACK) 70 | implementationMode = PreviewView.ImplementationMode.COMPATIBLE 71 | scaleType = PreviewView.ScaleType.FILL_START 72 | }.also { previewView -> 73 | startTextRecognition( 74 | context = context, 75 | cameraController = cameraController, 76 | lifecycleOwner = lifecycleOwner, 77 | previewView = previewView, 78 | onDetectedTextUpdated = ::onTextUpdated 79 | ) 80 | } 81 | } 82 | ) 83 | 84 | Text( 85 | modifier = Modifier 86 | .fillMaxWidth() 87 | .background(androidx.compose.ui.graphics.Color.White) 88 | .padding(16.dp), 89 | text = detectedText, 90 | ) 91 | } 92 | } 93 | } 94 | 95 | private fun startTextRecognition( 96 | context: Context, 97 | cameraController: LifecycleCameraController, 98 | lifecycleOwner: LifecycleOwner, 99 | previewView: PreviewView, 100 | onDetectedTextUpdated: (String) -> Unit 101 | ) { 102 | 103 | cameraController.imageAnalysisTargetSize = CameraController.OutputSize(AspectRatio.RATIO_16_9) 104 | cameraController.setImageAnalysisAnalyzer( 105 | ContextCompat.getMainExecutor(context), 106 | TextRecognitionAnalyzer(onDetectedTextUpdated = onDetectedTextUpdated) 107 | ) 108 | 109 | cameraController.bindToLifecycle(lifecycleOwner) 110 | previewView.controller = cameraController 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/de/yanneckreiss/mlkittutorial/ui/camera/TextRecognitionAnalyzer.kt: -------------------------------------------------------------------------------- 1 | package de.yanneckreiss.mlkittutorial.ui.camera 2 | 3 | import android.media.Image 4 | import androidx.annotation.OptIn 5 | import androidx.camera.core.ExperimentalGetImage 6 | import androidx.camera.core.ImageAnalysis 7 | import androidx.camera.core.ImageProxy 8 | import com.google.mlkit.vision.common.InputImage 9 | import com.google.mlkit.vision.text.Text 10 | import com.google.mlkit.vision.text.TextRecognition 11 | import com.google.mlkit.vision.text.TextRecognizer 12 | import com.google.mlkit.vision.text.latin.TextRecognizerOptions 13 | import kotlinx.coroutines.CoroutineScope 14 | import kotlinx.coroutines.Dispatchers 15 | import kotlinx.coroutines.SupervisorJob 16 | import kotlinx.coroutines.delay 17 | import kotlinx.coroutines.launch 18 | import kotlin.coroutines.resume 19 | import kotlin.coroutines.suspendCoroutine 20 | 21 | class TextRecognitionAnalyzer( 22 | private val onDetectedTextUpdated: (String) -> Unit 23 | ) : ImageAnalysis.Analyzer { 24 | 25 | companion object { 26 | const val THROTTLE_TIMEOUT_MS = 1_000L 27 | } 28 | 29 | private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) 30 | private val textRecognizer: TextRecognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS) 31 | 32 | @OptIn(ExperimentalGetImage::class) 33 | override fun analyze(imageProxy: ImageProxy) { 34 | scope.launch { 35 | val mediaImage: Image = imageProxy.image ?: run { imageProxy.close(); return@launch } 36 | val inputImage: InputImage = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees) 37 | 38 | suspendCoroutine { continuation -> 39 | textRecognizer.process(inputImage) 40 | .addOnSuccessListener { visionText: Text -> 41 | val detectedText: String = visionText.text 42 | if (detectedText.isNotBlank()) { 43 | onDetectedTextUpdated(detectedText) 44 | } 45 | } 46 | .addOnCompleteListener { 47 | continuation.resume(Unit) 48 | } 49 | } 50 | 51 | delay(THROTTLE_TIMEOUT_MS) 52 | }.invokeOnCompletion { exception -> 53 | exception?.printStackTrace() 54 | imageProxy.close() 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/de/yanneckreiss/mlkittutorial/ui/no_permission/NoPermissionScreen.kt: -------------------------------------------------------------------------------- 1 | package de.yanneckreiss.mlkittutorial.ui.no_permission 2 | 3 | import androidx.compose.foundation.layout.Arrangement 4 | import androidx.compose.foundation.layout.Box 5 | import androidx.compose.foundation.layout.Column 6 | import androidx.compose.foundation.layout.fillMaxSize 7 | import androidx.compose.foundation.layout.padding 8 | import androidx.compose.material.icons.Icons 9 | import androidx.compose.material.icons.filled.Camera 10 | import androidx.compose.material3.Button 11 | import androidx.compose.material3.Icon 12 | import androidx.compose.material3.Text 13 | import androidx.compose.runtime.Composable 14 | import androidx.compose.ui.Alignment 15 | import androidx.compose.ui.Modifier 16 | import androidx.compose.ui.text.style.TextAlign 17 | import androidx.compose.ui.tooling.preview.Preview 18 | import androidx.compose.ui.unit.dp 19 | 20 | @Composable 21 | fun NoPermissionScreen( 22 | onRequestPermission: () -> Unit 23 | ) { 24 | 25 | NoPermissionContent( 26 | onRequestPermission = onRequestPermission 27 | ) 28 | } 29 | 30 | @Composable 31 | fun NoPermissionContent( 32 | onRequestPermission: () -> Unit 33 | ) { 34 | Box( 35 | modifier = Modifier.fillMaxSize(), 36 | contentAlignment = Alignment.Center 37 | ) { 38 | Column( 39 | modifier = Modifier 40 | .padding(16.dp) 41 | .fillMaxSize(), 42 | horizontalAlignment = Alignment.CenterHorizontally, 43 | verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterVertically) 44 | ) { 45 | Text( 46 | textAlign = TextAlign.Center, 47 | text = "Please grant the permission to use the camera to use the core functionality of this app." 48 | ) 49 | Button(onClick = onRequestPermission) { 50 | Icon(imageVector = Icons.Default.Camera, contentDescription = "Camera") 51 | Text(text = "Grant permission") 52 | } 53 | } 54 | } 55 | } 56 | 57 | @Preview 58 | @Composable 59 | private fun Preview_NoPermissionContent() { 60 | NoPermissionContent( 61 | onRequestPermission = {} 62 | ) 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/de/yanneckreiss/mlkittutorial/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package de.yanneckreiss.mlkittutorial.ui.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val Purple80 = Color(0xFFD0BCFF) 6 | val PurpleGrey80 = Color(0xFFCCC2DC) 7 | val Pink80 = Color(0xFFEFB8C8) 8 | 9 | val Purple40 = Color(0xFF6650a4) 10 | val PurpleGrey40 = Color(0xFF625b71) 11 | val Pink40 = Color(0xFF7D5260) -------------------------------------------------------------------------------- /app/src/main/java/de/yanneckreiss/mlkittutorial/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package de.yanneckreiss.mlkittutorial.ui.theme 2 | 3 | import android.app.Activity 4 | import android.os.Build 5 | import androidx.compose.foundation.isSystemInDarkTheme 6 | import androidx.compose.material3.MaterialTheme 7 | import androidx.compose.material3.darkColorScheme 8 | import androidx.compose.material3.dynamicDarkColorScheme 9 | import androidx.compose.material3.dynamicLightColorScheme 10 | import androidx.compose.material3.lightColorScheme 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.runtime.SideEffect 13 | import androidx.compose.ui.graphics.toArgb 14 | import androidx.compose.ui.platform.LocalContext 15 | import androidx.compose.ui.platform.LocalView 16 | import androidx.core.view.WindowCompat 17 | 18 | private val DarkColorScheme = darkColorScheme( 19 | primary = Purple80, 20 | secondary = PurpleGrey80, 21 | tertiary = Pink80 22 | ) 23 | 24 | private val LightColorScheme = lightColorScheme( 25 | primary = Purple40, 26 | secondary = PurpleGrey40, 27 | tertiary = Pink40 28 | 29 | /* Other default colors to override 30 | background = Color(0xFFFFFBFE), 31 | surface = Color(0xFFFFFBFE), 32 | onPrimary = Color.White, 33 | onSecondary = Color.White, 34 | onTertiary = Color.White, 35 | onBackground = Color(0xFF1C1B1F), 36 | onSurface = Color(0xFF1C1B1F), 37 | */ 38 | ) 39 | 40 | @Composable 41 | fun JetpackComposeMLKitTutorialTheme( 42 | darkTheme: Boolean = isSystemInDarkTheme(), 43 | // Dynamic color is available on Android 12+ 44 | dynamicColor: Boolean = true, 45 | content: @Composable () -> Unit 46 | ) { 47 | val colorScheme = when { 48 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { 49 | val context = LocalContext.current 50 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) 51 | } 52 | 53 | darkTheme -> DarkColorScheme 54 | else -> LightColorScheme 55 | } 56 | val view = LocalView.current 57 | if (!view.isInEditMode) { 58 | SideEffect { 59 | val window = (view.context as Activity).window 60 | window.statusBarColor = colorScheme.primary.toArgb() 61 | WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme 62 | } 63 | } 64 | 65 | MaterialTheme( 66 | colorScheme = colorScheme, 67 | typography = Typography, 68 | content = content 69 | ) 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/de/yanneckreiss/mlkittutorial/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package de.yanneckreiss.mlkittutorial.ui.theme 2 | 3 | import androidx.compose.material3.Typography 4 | import androidx.compose.ui.text.TextStyle 5 | import androidx.compose.ui.text.font.FontFamily 6 | import androidx.compose.ui.text.font.FontWeight 7 | import androidx.compose.ui.unit.sp 8 | 9 | // Set of Material typography styles to start with 10 | val Typography = Typography( 11 | bodyLarge = TextStyle( 12 | fontFamily = FontFamily.Default, 13 | fontWeight = FontWeight.Normal, 14 | fontSize = 16.sp, 15 | lineHeight = 24.sp, 16 | letterSpacing = 0.5.sp 17 | ) 18 | /* Other default text styles to override 19 | titleLarge = TextStyle( 20 | fontFamily = FontFamily.Default, 21 | fontWeight = FontWeight.Normal, 22 | fontSize = 22.sp, 23 | lineHeight = 28.sp, 24 | letterSpacing = 0.sp 25 | ), 26 | labelSmall = TextStyle( 27 | fontFamily = FontFamily.Default, 28 | fontWeight = FontWeight.Medium, 29 | fontSize = 11.sp, 30 | lineHeight = 16.sp, 31 | letterSpacing = 0.5.sp 32 | ) 33 | */ 34 | ) -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YanneckReiss/JetpackComposeMLKitTutorial/536eb48f4dce2d200b2abdb097c2a0ffb0ff2bb9/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YanneckReiss/JetpackComposeMLKitTutorial/536eb48f4dce2d200b2abdb097c2a0ffb0ff2bb9/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YanneckReiss/JetpackComposeMLKitTutorial/536eb48f4dce2d200b2abdb097c2a0ffb0ff2bb9/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YanneckReiss/JetpackComposeMLKitTutorial/536eb48f4dce2d200b2abdb097c2a0ffb0ff2bb9/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YanneckReiss/JetpackComposeMLKitTutorial/536eb48f4dce2d200b2abdb097c2a0ffb0ff2bb9/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YanneckReiss/JetpackComposeMLKitTutorial/536eb48f4dce2d200b2abdb097c2a0ffb0ff2bb9/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YanneckReiss/JetpackComposeMLKitTutorial/536eb48f4dce2d200b2abdb097c2a0ffb0ff2bb9/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YanneckReiss/JetpackComposeMLKitTutorial/536eb48f4dce2d200b2abdb097c2a0ffb0ff2bb9/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YanneckReiss/JetpackComposeMLKitTutorial/536eb48f4dce2d200b2abdb097c2a0ffb0ff2bb9/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YanneckReiss/JetpackComposeMLKitTutorial/536eb48f4dce2d200b2abdb097c2a0ffb0ff2bb9/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Jetpack Compose ML-Kit Tutorial 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |