diff --git a/.gitignore b/.gitignore index aa724b7..10cfdbf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,7 @@ *.iml .gradle /local.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml +/.idea .DS_Store /build /captures diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9c1fa87..4dc815f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,7 +16,7 @@ android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" + android:roundIcon="@mipmap/ic_launcher" android:supportsRtl="true" android:theme="@style/Theme.Scanely" tools:targetApi="36"> diff --git a/app/src/main/java/com/skeler/scanely/navigation/LocalNavController.kt b/app/src/main/java/com/skeler/scanely/navigation/LocalNavController.kt new file mode 100644 index 0000000..a4266b5 --- /dev/null +++ b/app/src/main/java/com/skeler/scanely/navigation/LocalNavController.kt @@ -0,0 +1,7 @@ +package com.skeler.scanely.navigation + +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.navigation.NavHostController + +val LocalNavController = + staticCompositionLocalOf { error("No LocalNavController provided") } \ No newline at end of file diff --git a/app/src/main/java/com/skeler/scanely/navigation/Navigation.kt b/app/src/main/java/com/skeler/scanely/navigation/Navigation.kt index 7898525..e63fc46 100644 --- a/app/src/main/java/com/skeler/scanely/navigation/Navigation.kt +++ b/app/src/main/java/com/skeler/scanely/navigation/Navigation.kt @@ -2,28 +2,36 @@ package com.skeler.scanely.navigation import android.graphics.Bitmap import android.net.Uri +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.core.tween import androidx.compose.runtime.Composable -import kotlinx.coroutines.launch -import com.skeler.scanely.ocr.OcrMode +import androidx.compose.runtime.CompositionLocalProvider 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.platform.LocalContext +import androidx.core.net.toUri import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.skeler.scanely.ocr.OcrHelper import com.skeler.scanely.ocr.OcrResult +import com.skeler.scanely.ocr.PdfProcessor import com.skeler.scanely.ui.components.GalleryPicker +import com.skeler.scanely.ui.screens.BarcodeScannerScreen import com.skeler.scanely.ui.screens.CameraScreen +import com.skeler.scanely.ui.screens.HistoryScreen import com.skeler.scanely.ui.screens.HomeScreen import com.skeler.scanely.ui.screens.ResultsScreen import com.skeler.scanely.ui.theme.ThemeMode +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch object Routes { @@ -43,16 +51,16 @@ fun ScanelyNavigation( onOcrLanguagesChanged: (Set) -> Unit = {} ) { val context = LocalContext.current - + // Shared OCR state var selectedImageUri by remember { mutableStateOf(null) } var ocrResult by remember { mutableStateOf(null) } var isProcessing by remember { mutableStateOf(false) } var progressMessage by remember { mutableStateOf("") } - + val ocrHelper = remember { OcrHelper(context) } val historyManager = remember { com.skeler.scanely.data.HistoryManager(context) } - + // Auto-initialize on Language change // Auto-initialize on Language change LaunchedEffect(ocrLanguages) { @@ -62,13 +70,13 @@ fun ScanelyNavigation( } } } - + // PDF Picker var isPdfProcessing by remember { mutableStateOf(false) } var pdfThumbnail by remember { mutableStateOf(null) } - - val pdfLauncher = androidx.activity.compose.rememberLauncherForActivityResult( - contract = androidx.activity.result.contract.ActivityResultContracts.OpenDocument(), + + val pdfLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.OpenDocument(), onResult = { uri -> if (uri != null) { isPdfProcessing = true @@ -77,8 +85,8 @@ fun ScanelyNavigation( selectedImageUri = uri ocrResult = null navController.navigate(Routes.RESULTS) - - kotlinx.coroutines.CoroutineScope(kotlinx.coroutines.Dispatchers.IO).launch { + + CoroutineScope(Dispatchers.IO).launch { try { // Ensure OCR is initialized if (!ocrHelper.isReady()) { @@ -90,41 +98,39 @@ fun ScanelyNavigation( return@launch } } - + val startTime = System.currentTimeMillis() - - val pdfResult = com.skeler.scanely.ocr.PdfProcessor.extractTextFromPdf( + + val pdfResult = PdfProcessor.extractTextFromPdf( context = context, pdfUri = uri, ocrHelper = ocrHelper, enabledLanguages = ocrLanguages.toList(), onProgress = { update -> - progressMessage = if (update.statusMessage.isNotEmpty()) { - update.statusMessage - } else { + progressMessage = update.statusMessage.ifEmpty { "Processing page ${update.currentPage} of ${update.totalPages}..." } } ) - + val totalTime = System.currentTimeMillis() - startTime - + // Set thumbnail for preview pdfThumbnail = pdfResult.thumbnail - + val finalResult = OcrResult( text = pdfResult.text, confidence = 100, languages = listOf(pdfResult.detectedLanguage), processingTimeMs = totalTime ) - + ocrResult = finalResult - + if (pdfResult.text.isNotEmpty() && !pdfResult.text.startsWith("Error")) { historyManager.saveItem(pdfResult.text, uri.toString()) } - + } catch (e: Exception) { e.printStackTrace() } finally { @@ -144,19 +150,19 @@ fun ScanelyNavigation( navController.navigate(Routes.RESULTS) } } - + // Process image when selected (skip if PDF is being processed) LaunchedEffect(selectedImageUri, isPdfProcessing) { if (isPdfProcessing) return@LaunchedEffect // Skip - PDF has its own processing - + selectedImageUri?.let { uri -> // Skip PDFs - they're handled by pdfLauncher val mimeType = context.contentResolver.getType(uri) if (mimeType == "application/pdf") return@let - + isProcessing = true ocrResult = null - + val initialized = ocrHelper.initialize(ocrLanguages.toList()) if (initialized) { val result = ocrHelper.recognizeText(uri) @@ -171,107 +177,106 @@ fun ScanelyNavigation( isProcessing = false } } - - NavHost( - navController = navController, - startDestination = Routes.HOME, - enterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Left, - animationSpec = tween(300) - ) - }, - exitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.Left, - animationSpec = tween(300) - ) - }, - popEnterTransition = { - slideIntoContainer( - AnimatedContentTransitionScope.SlideDirection.Right, - animationSpec = tween(300) - ) - }, - popExitTransition = { - slideOutOfContainer( - AnimatedContentTransitionScope.SlideDirection.Right, - animationSpec = tween(300) - ) - } - ) { - composable(Routes.HOME) { - HomeScreen( - currentTheme = currentTheme, - onThemeChanged = onThemeChanged, - ocrLanguages = ocrLanguages, - onOcrLanguagesChanged = onOcrLanguagesChanged, - onCaptureClick = { navController.navigate(Routes.CAMERA) }, - onGalleryClick = { launchGalleryPicker() }, - onPdfClick = { - pdfLauncher.launch(arrayOf("application/pdf")) - }, - onBarcodeClick = { navController.navigate(Routes.BARCODE_SCANNER) }, - onHistoryClick = { navController.navigate("history") } - ) - } - - composable("history") { - com.skeler.scanely.ui.screens.HistoryScreen( - onNavigateBack = { navController.popBackStack() }, - onItemClick = { item -> - // Re-open result - // Since imageUri is stored as string, parse it. - // Note: If original file is gone (cache cleared), this might fail to load image, - // but we have text. - ocrResult = OcrResult(item.text, 0, emptyList(), 0L) - selectedImageUri = Uri.parse(item.imageUri) - navController.navigate(Routes.RESULTS) - } - ) - } - - composable(Routes.CAMERA) { - CameraScreen( - onImageCaptured = { uri -> - selectedImageUri = uri - ocrResult = null - navController.navigate(Routes.RESULTS) { - popUpTo(Routes.HOME) + + CompositionLocalProvider(LocalNavController provides navController) { + NavHost( + navController = navController, + startDestination = Routes.HOME, + enterTransition = { + slideIntoContainer( + AnimatedContentTransitionScope.SlideDirection.Left, + animationSpec = tween(300) + ) + }, + exitTransition = { + slideOutOfContainer( + AnimatedContentTransitionScope.SlideDirection.Left, + animationSpec = tween(300) + ) + }, + popEnterTransition = { + slideIntoContainer( + AnimatedContentTransitionScope.SlideDirection.Right, + animationSpec = tween(300) + ) + }, + popExitTransition = { + slideOutOfContainer( + AnimatedContentTransitionScope.SlideDirection.Right, + animationSpec = tween(300) + ) + } + ) { + composable(Routes.HOME) { + HomeScreen( + currentTheme = currentTheme, + onThemeChanged = onThemeChanged, + ocrLanguages = ocrLanguages, + onOcrLanguagesChanged = onOcrLanguagesChanged, + onCaptureClick = { navController.navigate(Routes.CAMERA) }, + onGalleryClick = { launchGalleryPicker() }, + onPdfClick = { + pdfLauncher.launch(arrayOf("application/pdf")) + }, + onBarcodeClick = { navController.navigate(Routes.BARCODE_SCANNER) }, + onHistoryClick = { navController.navigate("history") } + ) + } + + composable("history") { + HistoryScreen( + onItemClick = { item -> + // Re-open result + // Since imageUri is stored as string, parse it. + // Note: If original file is gone (cache cleared), this might fail to load image, + // but we have text. + ocrResult = OcrResult(item.text, 0, emptyList(), 0L) + selectedImageUri = item.imageUri.toUri() + navController.navigate(Routes.RESULTS) } - }, - onNavigateBack = { navController.popBackStack() } - ) - } - - composable(Routes.RESULTS) { - ResultsScreen( - imageUri = selectedImageUri, - ocrResult = ocrResult, - isProcessing = isProcessing, - progressMessage = progressMessage, - pdfThumbnail = pdfThumbnail, - onNavigateBack = { - selectedImageUri = null - ocrResult = null - pdfThumbnail = null - navController.popBackStack(Routes.HOME, inclusive = false) - }, - onCopyText = { /* Handled */ } - ) - } - - composable(Routes.BARCODE_SCANNER) { - com.skeler.scanely.ui.screens.BarcodeScannerScreen( - onNavigateBack = { navController.popBackStack() }, - onBarcodeScanned = { result -> - // Save barcode result to history - // Use a special prefix for imageUri to indicate it's a barcode or just null - // For now we store a formatted string - val historyContent = "[${result.formatName}] ${result.displayValue}" - historyManager.saveItem(historyContent, "barcode://icon") - } - ) + ) + } + + composable(Routes.CAMERA) { + CameraScreen( + onImageCaptured = { uri -> + selectedImageUri = uri + ocrResult = null + navController.navigate(Routes.RESULTS) { + popUpTo(Routes.HOME) + } + } + ) + } + + composable(Routes.RESULTS) { + ResultsScreen( + imageUri = selectedImageUri, + ocrResult = ocrResult, + isProcessing = isProcessing, + progressMessage = progressMessage, + pdfThumbnail = pdfThumbnail, + onNavigateBack = { + selectedImageUri = null + ocrResult = null + pdfThumbnail = null + navController.popBackStack(Routes.HOME, inclusive = false) + }, + onCopyText = { /* Handled */ } + ) + } + + composable(Routes.BARCODE_SCANNER) { + BarcodeScannerScreen( + onBarcodeScanned = { result -> + // Save barcode result to history + // Use a special prefix for imageUri to indicate it's a barcode or just null + // For now we store a formatted string + val historyContent = "[${result.formatName}] ${result.displayValue}" + historyManager.saveItem(historyContent, "barcode://icon") + } + ) + } } } } diff --git a/app/src/main/java/com/skeler/scanely/ui/screens/BarcodeScannerScreen.kt b/app/src/main/java/com/skeler/scanely/ui/screens/BarcodeScannerScreen.kt index d7ad1ab..90de983 100644 --- a/app/src/main/java/com/skeler/scanely/ui/screens/BarcodeScannerScreen.kt +++ b/app/src/main/java/com/skeler/scanely/ui/screens/BarcodeScannerScreen.kt @@ -1,7 +1,6 @@ package com.skeler.scanely.ui.screens import android.Manifest -import android.graphics.Bitmap import android.util.Log import android.view.ViewGroup import androidx.camera.core.CameraSelector @@ -52,20 +51,19 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.content.ContextCompat import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState +import com.skeler.scanely.navigation.LocalNavController import com.skeler.scanely.scanner.BarcodeResult import com.skeler.scanely.scanner.BarcodeScanner import kotlinx.coroutines.Dispatchers @@ -78,34 +76,34 @@ private const val TAG = "BarcodeScannerScreen" @OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class) @Composable fun BarcodeScannerScreen( - onNavigateBack: () -> Unit = {}, onBarcodeScanned: (BarcodeResult) -> Unit = {} ) { val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current val clipboardManager = LocalClipboardManager.current val scope = rememberCoroutineScope() - + val cameraPermission = rememberPermissionState(Manifest.permission.CAMERA) - + var scannedResults by remember { mutableStateOf>(emptyList()) } var isScanning by remember { mutableStateOf(true) } - + // De-duplication set to avoid saving the same barcode continuously val previouslyScanned = remember { mutableSetOf() } - + val navController = LocalNavController.current + LaunchedEffect(Unit) { if (!cameraPermission.status.isGranted) { cameraPermission.launchPermissionRequest() } } - + Scaffold( topBar = { TopAppBar( title = { Text("Barcode Scanner") }, navigationIcon = { - IconButton(onClick = onNavigateBack) { + IconButton(onClick = { navController.popBackStack() }) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back" @@ -134,7 +132,7 @@ fun BarcodeScannerScreen( onBarcodeDetected = { results -> if (results.isNotEmpty() && isScanning) { scannedResults = results - + // Check for new barcodes to save results.forEach { result -> val key = "${result.formatName}|${result.rawValue}" @@ -147,7 +145,7 @@ fun BarcodeScannerScreen( } } ) - + // Scan Frame Overlay Box( modifier = Modifier.fillMaxSize(), @@ -163,7 +161,7 @@ fun BarcodeScannerScreen( ) ) } - + // Hint text Box( modifier = Modifier @@ -184,7 +182,7 @@ fun BarcodeScannerScreen( ) } } - + // Results Section AnimatedVisibility( visible = scannedResults.isNotEmpty(), @@ -241,15 +239,15 @@ private fun CameraPreviewWithScanner( val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current val scope = rememberCoroutineScope() - + val executor = remember { Executors.newSingleThreadExecutor() } - + DisposableEffect(Unit) { onDispose { executor.shutdown() } } - + AndroidView( factory = { ctx -> PreviewView(ctx).apply { @@ -263,14 +261,14 @@ private fun CameraPreviewWithScanner( modifier = Modifier.fillMaxSize() ) { previewView -> val cameraProviderFuture = ProcessCameraProvider.getInstance(context) - + cameraProviderFuture.addListener({ val cameraProvider = cameraProviderFuture.get() - + val preview = Preview.Builder().build().also { it.surfaceProvider = previewView.surfaceProvider } - + val imageAnalysis = ImageAnalysis.Builder() .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build() @@ -281,9 +279,9 @@ private fun CameraPreviewWithScanner( } } } - + val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA - + try { cameraProvider.unbindAll() cameraProvider.bindToLifecycle( @@ -306,7 +304,7 @@ private suspend fun processImageProxy( try { val bitmap = imageProxy.toBitmap() val results = BarcodeScanner.scanBitmap(bitmap) - + withContext(Dispatchers.Main) { onBarcodeDetected(results) } @@ -349,7 +347,7 @@ private fun BarcodeResultCard( color = MaterialTheme.colorScheme.onPrimaryContainer ) } - + IconButton(onClick = onCopy) { Icon( imageVector = Icons.Default.ContentCopy, diff --git a/app/src/main/java/com/skeler/scanely/ui/screens/CameraScreen.kt b/app/src/main/java/com/skeler/scanely/ui/screens/CameraScreen.kt index fdfc7c1..8ed3b66 100644 --- a/app/src/main/java/com/skeler/scanely/ui/screens/CameraScreen.kt +++ b/app/src/main/java/com/skeler/scanely/ui/screens/CameraScreen.kt @@ -87,8 +87,7 @@ private const val TAG = "CameraScreen" @OptIn(ExperimentalPermissionsApi::class) @Composable fun CameraScreen( - onImageCaptured: (Uri) -> Unit = {}, - onNavigateBack: () -> Unit = {} + onImageCaptured: (Uri) -> Unit = {} ) { val context = LocalContext.current val cameraPermissionState = rememberPermissionState(Manifest.permission.CAMERA) diff --git a/app/src/main/java/com/skeler/scanely/ui/screens/HistoryScreen.kt b/app/src/main/java/com/skeler/scanely/ui/screens/HistoryScreen.kt index 93b8260..85f3e86 100644 --- a/app/src/main/java/com/skeler/scanely/ui/screens/HistoryScreen.kt +++ b/app/src/main/java/com/skeler/scanely/ui/screens/HistoryScreen.kt @@ -1,7 +1,6 @@ package com.skeler.scanely.ui.screens import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -27,15 +26,14 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import com.skeler.scanely.data.HistoryManager import com.skeler.scanely.data.HistoryItem +import com.skeler.scanely.data.HistoryManager +import com.skeler.scanely.navigation.LocalNavController import java.text.SimpleDateFormat import java.util.Date import java.util.Locale @@ -43,13 +41,13 @@ import java.util.Locale @OptIn(ExperimentalMaterial3Api::class) @Composable fun HistoryScreen( - onNavigateBack: () -> Unit, onItemClick: (HistoryItem) -> Unit ) { val context = LocalContext.current val historyManager = remember { HistoryManager(context) } var historyItems by remember { mutableStateOf>(emptyList()) } - + val navController = LocalNavController.current + LaunchedEffect(Unit) { historyItems = historyManager.getHistory() } @@ -59,7 +57,7 @@ fun HistoryScreen( CenterAlignedTopAppBar( title = { Text("History") }, navigationIcon = { - IconButton(onClick = onNavigateBack) { + IconButton(onClick = { navController.popBackStack() }) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back" @@ -140,7 +138,11 @@ private fun HistoryItemCard( ) Spacer(modifier = Modifier.height(8.dp)) Text( - text = SimpleDateFormat("MMM dd, yyyy • HH:mm", Locale.getDefault()).format(Date(item.timestamp)), + text = SimpleDateFormat("MMM dd, yyyy • HH:mm", Locale.getDefault()).format( + Date( + item.timestamp + ) + ), style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurfaceVariant ) diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 73841f9..345888d 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,7 +1,6 @@ - - - - + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index 73841f9..0000000 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..7d53c6e Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp deleted file mode 100644 index c209e78..0000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_background.png b/app/src/main/res/mipmap-hdpi/ic_launcher_background.png new file mode 100644 index 0000000..4563434 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..ab3a7f1 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..0947e9a Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp deleted file mode 100644 index b2dfe3d..0000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..297743b Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp deleted file mode 100644 index 4f0f1d6..0000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_background.png b/app/src/main/res/mipmap-mdpi/ic_launcher_background.png new file mode 100644 index 0000000..253ecb1 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..1fd02c7 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..2889a9b Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp deleted file mode 100644 index 62b611d..0000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..ee31bfd Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp deleted file mode 100644 index 948a307..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png new file mode 100644 index 0000000..0fd4acf Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..5d6a0cf Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..a099b59 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp deleted file mode 100644 index 1b9a695..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..8d7aea0 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp deleted file mode 100644 index 28d4b77..0000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..ea1e08a Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..18334fa Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..53fa857 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp deleted file mode 100644 index 9287f50..0000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..d14e9ab Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp deleted file mode 100644 index aa7d642..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..bbd2ac0 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..9a0b92f Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..1b04609 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp deleted file mode 100644 index 9126ae3..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and /dev/null differ