Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 69 additions & 44 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.compose.compiler)
id("com.google.gms.google-services")
}

android {
namespace = "com.samuel.inventorymanager"
// Consider checking for the latest stable API levels.
// compileSdk = 36 is fine, but adjust as necessary for future compatibility.
compileSdk = 36
compileSdk = 34

defaultConfig {
applicationId = "com.samuel.inventorymanager"
minSdk = 24
targetSdk = 36
targetSdk = 34
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

packaging {
resources {
excludes += "META-INF/DEPENDENCIES"
excludes += "/META-INF/INDEX.LIST"
excludes += "/META-INF/*.md"
excludes += "/META-INF/DEPENDENCIES"
excludes += "/META-INF/LICENSE"
excludes += "/META-INF/LICENSE.txt"
excludes += "/META-INF/NOTICE"
excludes += "/META-INF/NOTICE.txt"
}
}
// ==
buildTypes {
release {
isMinifyEnabled = false
Expand All @@ -47,55 +50,77 @@ android {
}
}

// Ensure all dependencies are inside this block with curly braces
dependencies {
// --- Google Services ---
// For Google Sign-In and other Google Play services
implementation("com.google.android.gms:play-services-auth:21.0.0")
implementation("com.google.firebase:firebase-auth:22.3.1")
implementation("com.google.firebase:firebase-core:21.1.1")
implementation("com.google.firebase:firebase-analytics")
implementation(platform("com.google.firebase:firebase-bom:34.5.0"))
implementation("com.google.firebase:firebase-auth")
// --- Platforms (BOMs) ---
implementation(platform("androidx.compose:compose-bom:2024.05.00"))
implementation(platform("com.google.firebase:firebase-bom:33.1.0"))

// Use one, consistent version
// --- AndroidX & Jetpack Compose ---
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.3")
implementation("androidx.activity:activity-compose:1.9.0")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.material:material-icons-extended")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.3")
implementation("androidx.navigation:navigation-compose:2.7.7")

// For Google One Tap Sign-In
implementation("androidx.credentials:credentials:1.2.0")
implementation("androidx.credentials:credentials-play-services-auth:1.2.0")
// --- Coroutines ---
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")

// --- Accompanist ---
implementation("com.google.accompanist:accompanist-pager:0.34.0")
implementation("com.google.accompanist:accompanist-pager-indicators:0.34.0")

// --- Firebase, Auth, & Credentials ---
implementation("com.google.firebase:firebase-analytics")
implementation("com.google.firebase:firebase-auth")
implementation("com.google.firebase:firebase-database")
implementation("com.google.android.gms:play-services-auth:21.2.0")
implementation("androidx.credentials:credentials:1.3.0-alpha01")
implementation("androidx.credentials:credentials-play-services-auth:1.3.0-alpha01")
implementation("com.google.android.libraries.identity.googleid:googleid:1.1.0")
implementation("com.google.http-client:google-http-client-android:1.43.3")
implementation("com.google.zxing:core:3.5.3")

// --- Google Drive API ---
// Required for DriveScopes and interacting with the Drive API
implementation("com.google.api-client:google-api-client-android:2.2.0")
implementation("com.google.apis:google-api-services-drive:v3-rev20220815-2.0.0")

// --- AndroidX & Jetpack Compose ---
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4")
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation("androidx.activity:activity-compose:1.9.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3)
implementation("androidx.compose.material:material-icons-extended-android:1.7.8")
// --- **CORRECTED** GOOGLE DRIVE API DEPENDENCIES ---
implementation("com.google.http-client:google-http-client-gson:1.44.1") {
exclude(group = "org.apache.httpcomponents")
}
implementation("com.google.api-client:google-api-client:2.4.0") {
exclude(group = "org.apache.httpcomponents")
}
implementation("com.google.api-client:google-api-client-android:2.4.0") {
exclude(group = "org.apache.httpcomponents")
}
// THIS VERSION EXISTS. MY OLD ONE DID NOT.
implementation("com.google.apis:google-api-services-drive:v3-rev20220815-2.0.0") {
exclude(group = "org.apache.httpcomponents")
}

// --- Utility ---
// Gson for JSON processing
implementation("com.google.code.gson:gson:2.13.2") // Kept one instance
// Coil for image loading
implementation("io.coil-kt:coil-compose:2.7.0")
// --- Image & ML Kit (WITH CORRECT VERSIONS) ---
implementation("com.vanniktech:android-image-cropper:4.5.0")
implementation("io.coil-kt:coil-compose:2.6.0")
implementation("com.google.android.gms:play-services-mlkit-text-recognition:19.0.0")
implementation("com.google.mlkit:text-recognition:16.0.0")
// THIS VERSION EXISTS. MY OLD ONE DID NOT.
implementation("com.google.mlkit:image-labeling:17.0.8")
implementation("com.google.mlkit:object-detection:17.0.1")

// --- JSON Parsing (WITH CORRECT VERSION) ---
implementation("com.google.code.gson:gson:2.10.1")

// --- Testing ---
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(platform("androidx.compose:compose-bom:2024.05.00"))
androidTestImplementation(libs.androidx.compose.ui.test.junit4)

// --- Debug ---
debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation(libs.androidx.compose.ui.test.manifest)
}
28 changes: 18 additions & 10 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,27 @@
android:required="false" />
<uses-permission android:name="android.permission.CAMERA" />

<!-- Internet for web services/APIs -->
<uses-permission android:name="android.permission.INTERNET" />

<!--
Storage Permissions
Warning: MANAGE_EXTERNAL_STORAGE requires Google Play approval for most apps.
Ensure your app's core functionality depends on broad file access.
Storage Permissions (Modern Android Best Practices):
READ/WRITE_EXTERNAL_STORAGE are deprecated starting from API 30.
For API 30+, it's best to rely on Scoped Storage, which the FileProvider
configuration below handles without needing these broad permissions.
MANAGE_EXTERNAL_STORAGE should only be used if absolutely necessary.
-->
<!-- For Android 11 (API 30) and above. THIS IS THE FIX. -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
tools:ignore="AllFilesAccessPolicy,ScopedStorage" />

<!-- Old permissions for older devices (API 29 and below) -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />


<!--
Application Definition
All attributes must be inside this single opening tag.
-->
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
Expand All @@ -34,7 +38,6 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.InventoryManager"
android:requestLegacyExternalStorage="true"
tools:targetApi="31">

<activity
Expand All @@ -47,9 +50,14 @@
</intent-filter>
</activity>

<!--
*** FIX for IllegalArgumentException: Couldn't find meta-data... ***
The authority must exactly match the string used in FileProvider.getUriForFile()
which the log suggests is 'com.samuel.inventorymanager.provider'.
-->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:authorities="com.samuel.inventorymanager.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
Expand Down
Binary file added app/src/main/inventorymanger-playstore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.samuel.inventorymanager.screens

import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Brightness4
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Crop
import androidx.compose.material.icons.filled.RotateRight
import androidx.compose.material3.AssistChip
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import coil.compose.rememberAsyncImagePainter

class ImageEditorActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val uri = Uri.parse(intent.getStringExtra("imageUri"))
setContent {
ImageEditorScreen(
uri = uri,
onSave = {
setResult(Activity.RESULT_OK, Intent().putExtra("editedUri", uri.toString()))
finish()
},
onCancel = { finish() }
)
}
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ImageEditorScreen(
uri: Uri,
onSave: () -> Unit,
onCancel: () -> Unit
) {
Scaffold(
topBar = {
TopAppBar(
title = { Text("Edit Image") },
navigationIcon = {
IconButton(onClick = onCancel) {
Icon(Icons.Default.Close, null)
}
},
actions = {
TextButton(onClick = onSave) {
Text("Save")
}
}
)
}
) { padding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(padding)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = rememberAsyncImagePainter(uri),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp)),
contentScale = ContentScale.Fit
)

Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
AssistChip(onClick = { }, label = { Text("Crop" ) }, leadingIcon = { Icon(Icons.Default.Crop, null) })
AssistChip(onClick = { }, label = { Text("Rotate") }, leadingIcon = { Icon(Icons.Default.RotateRight, null) })
AssistChip(onClick = { }, label = { Text("Brightness") }, leadingIcon = { Icon(Icons.Default.Brightness4, null) })
}
}
}
}
Loading