├── .gitignore ├── .idea ├── .gitignore ├── AndroidProjectSystem.xml ├── appInsightsSettings.xml ├── compiler.xml ├── deploymentTargetSelector.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── kotlinc.xml ├── migrations.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── harry │ │ └── sokomart │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ │ └── com │ │ │ └── harry │ │ │ └── sokomart │ │ │ ├── MainActivity.kt │ │ │ ├── data │ │ │ ├── ProductDao.kt │ │ │ ├── ProductDatabase.kt │ │ │ ├── UserDao.kt │ │ │ └── UserDatabase.kt │ │ │ ├── model │ │ │ ├── Product.kt │ │ │ └── User.kt │ │ │ ├── navigation │ │ │ ├── AppNavHost.kt │ │ │ └── Routes.kt │ │ │ ├── repository │ │ │ ├── ProductRepository.kt │ │ │ └── UserRepository.kt │ │ │ ├── ui │ │ │ ├── screens │ │ │ │ ├── about │ │ │ │ │ └── AboutScreen.kt │ │ │ │ ├── auth │ │ │ │ │ ├── LoginScreen.kt │ │ │ │ │ └── RegistrationScreen.kt │ │ │ │ ├── contact │ │ │ │ │ └── ContactScreen.kt │ │ │ │ ├── dashboard │ │ │ │ │ └── DashboardScreen.kt │ │ │ │ ├── form │ │ │ │ │ └── FormScreen.kt │ │ │ │ ├── home │ │ │ │ │ └── HomeScreen.kt │ │ │ │ ├── intent │ │ │ │ │ └── IntentScreen.kt │ │ │ │ ├── item │ │ │ │ │ └── ItemScreen.kt │ │ │ │ ├── more │ │ │ │ │ └── MoreScreen.kt │ │ │ │ ├── newscreen │ │ │ │ │ └── NewScreen.kt │ │ │ │ ├── paylink │ │ │ │ │ ├── createlink.kt │ │ │ │ │ └── linkpreview.kt │ │ │ │ ├── paylinkauthentication │ │ │ │ │ ├── signin.kt │ │ │ │ │ └── signup.kt │ │ │ │ ├── paylinkcommunity │ │ │ │ │ └── communityscreen.kt │ │ │ │ ├── paylinkhome │ │ │ │ │ ├── PHome.kt │ │ │ │ │ ├── scaffold.kt │ │ │ │ │ └── splash.kt │ │ │ │ ├── paylinkprofile │ │ │ │ │ └── Profile.kt │ │ │ │ ├── products │ │ │ │ │ ├── AddProductScreen.kt │ │ │ │ │ ├── EditProductScreen.kt │ │ │ │ │ └── ProductListScreen.kt │ │ │ │ ├── service │ │ │ │ │ └── ServiceScreen.kt │ │ │ │ ├── splash │ │ │ │ │ └── SplashScreen.kt │ │ │ │ └── start │ │ │ │ │ └── StartScreen.kt │ │ │ └── theme │ │ │ │ ├── Color.kt │ │ │ │ ├── Theme.kt │ │ │ │ └── Type.kt │ │ │ └── viewmodel │ │ │ ├── AuthViewModel.kt │ │ │ └── ProductViewModel.kt │ └── res │ │ ├── drawable │ │ ├── download.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── img.png │ │ ├── img_1.png │ │ ├── img_10.png │ │ ├── img_11.png │ │ ├── img_12.png │ │ ├── img_13.png │ │ ├── img_14.png │ │ ├── img_15.png │ │ ├── img_16.png │ │ ├── img_2.png │ │ ├── img_3.png │ │ ├── img_4.png │ │ ├── img_5.png │ │ ├── img_6.png │ │ ├── img_7.png │ │ ├── img_8.png │ │ ├── img_9.png │ │ ├── name.xml │ │ ├── price.xml │ │ ├── product.xml │ │ ├── visibility.xml │ │ └── visibilityoff.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 │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── com │ └── harry │ └── sokomart │ └── ExampleUnitTest.kt ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/AndroidProjectSystem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/appInsightsSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 61 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.application) 3 | alias(libs.plugins.kotlin.android) 4 | alias(libs.plugins.kotlin.compose) 5 | id ("kotlin-kapt") 6 | } 7 | 8 | android { 9 | namespace = "com.harry.sokomart" 10 | compileSdk = 35 11 | 12 | defaultConfig { 13 | applicationId = "com.harry.sokomart" 14 | minSdk = 21 15 | targetSdk = 35 16 | versionCode = 1 17 | versionName = "1.0" 18 | 19 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 20 | } 21 | 22 | buildTypes { 23 | release { 24 | isMinifyEnabled = false 25 | proguardFiles( 26 | getDefaultProguardFile("proguard-android-optimize.txt"), 27 | "proguard-rules.pro" 28 | ) 29 | } 30 | } 31 | compileOptions { 32 | sourceCompatibility = JavaVersion.VERSION_11 33 | targetCompatibility = JavaVersion.VERSION_11 34 | } 35 | kotlinOptions { 36 | jvmTarget = "11" 37 | } 38 | buildFeatures { 39 | compose = true 40 | } 41 | } 42 | 43 | dependencies { 44 | 45 | implementation(libs.androidx.core.ktx) 46 | implementation(libs.androidx.lifecycle.runtime.ktx) 47 | implementation(libs.androidx.activity.compose) 48 | implementation(platform(libs.androidx.compose.bom)) 49 | implementation(libs.androidx.ui) 50 | implementation(libs.androidx.ui.graphics) 51 | implementation(libs.androidx.ui.tooling.preview) 52 | implementation(libs.androidx.material3) 53 | implementation(libs.androidx.navigation.runtime.android) 54 | implementation(libs.androidx.runtime.android) 55 | implementation(libs.androidx.navigation.compose) 56 | testImplementation(libs.junit) 57 | androidTestImplementation(libs.androidx.junit) 58 | androidTestImplementation(libs.androidx.espresso.core) 59 | androidTestImplementation(platform(libs.androidx.compose.bom)) 60 | androidTestImplementation(libs.androidx.ui.test.junit4) 61 | debugImplementation(libs.androidx.ui.tooling) 62 | debugImplementation(libs.androidx.ui.test.manifest) 63 | 64 | // Room 65 | implementation("androidx.room:room-runtime:2.6.1") 66 | kapt("androidx.room:room-compiler:2.6.1") 67 | implementation("androidx.room:room-ktx:2.6.1") 68 | 69 | // Image Loading (Coil for Jetpack Compose) 70 | implementation ("io.coil-kt:coil-compose:2.4.0") 71 | 72 | //livedata 73 | implementation("androidx.compose.runtime:runtime-livedata:1.6.4") 74 | } 75 | 76 | 77 | -------------------------------------------------------------------------------- /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/androidTest/java/com/harry/sokomart/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.harry.sokomart", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.activity.enableEdgeToEdge 7 | import com.harry.sokomart.navigation.AppNavHost 8 | 9 | class MainActivity : ComponentActivity() { 10 | override fun onCreate(savedInstanceState: Bundle?) { 11 | super.onCreate(savedInstanceState) 12 | enableEdgeToEdge() 13 | setContent { 14 | 15 | AppNavHost() 16 | 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/data/ProductDao.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.data 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.room.* 5 | import com.harry.sokomart.model.Product 6 | 7 | @Dao 8 | interface ProductDao { 9 | @Query("SELECT * FROM products") 10 | fun getAllProducts(): LiveData> 11 | 12 | @Insert 13 | suspend fun insertProduct(product: Product) 14 | 15 | @Update 16 | suspend fun updateProduct(product: Product) 17 | 18 | @Delete 19 | suspend fun deleteProduct(product: Product) 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/data/ProductDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.data 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import com.harry.sokomart.model.Product 8 | 9 | @Database(entities = [Product::class], version = 1, exportSchema = false) 10 | abstract class ProductDatabase : RoomDatabase() { 11 | abstract fun productDao(): ProductDao 12 | 13 | companion object { 14 | @Volatile 15 | private var INSTANCE: ProductDatabase? = null 16 | 17 | fun getDatabase(context: Context): ProductDatabase { 18 | return INSTANCE ?: synchronized(this) { 19 | val instance = Room.databaseBuilder( 20 | context.applicationContext, 21 | ProductDatabase::class.java, 22 | "product_db" 23 | ).build() 24 | INSTANCE = instance 25 | instance 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/data/UserDao.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.data 2 | 3 | 4 | import androidx.room.Dao 5 | import androidx.room.Insert 6 | import androidx.room.OnConflictStrategy 7 | import androidx.room.Query 8 | import com.harry.sokomart.model.User 9 | 10 | 11 | @Dao 12 | interface UserDao { 13 | @Insert(onConflict = OnConflictStrategy.REPLACE) 14 | suspend fun registerUser(user: User) 15 | 16 | @Query("SELECT * FROM users WHERE email = :email AND password = :password") 17 | suspend fun loginUser(email: String, password: String): User? 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/data/UserDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.data 2 | 3 | 4 | import android.content.Context 5 | import androidx.room.Database 6 | import androidx.room.Room 7 | import androidx.room.RoomDatabase 8 | import com.harry.sokomart.model.User 9 | 10 | @Database(entities = [User::class], version = 2, exportSchema = false) 11 | abstract class UserDatabase : RoomDatabase() { 12 | abstract fun userDao(): UserDao 13 | 14 | companion object { 15 | @Volatile 16 | private var INSTANCE: UserDatabase? = null 17 | 18 | fun getDatabase(context: Context): UserDatabase { 19 | return INSTANCE ?: synchronized(this) { 20 | val instance = Room.databaseBuilder( 21 | context.applicationContext, 22 | UserDatabase::class.java, 23 | "user_database" 24 | ) 25 | .fallbackToDestructiveMigration() // DANGEROUS IN PRODUCTION, OK FOR NOW 26 | .build() 27 | INSTANCE = instance 28 | instance 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/model/Product.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.model 2 | 3 | 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | 7 | @Entity(tableName = "products") 8 | data class Product( 9 | @PrimaryKey(autoGenerate = true) val id: Int = 0, 10 | val name: String, 11 | val price: Double, 12 | val phone: String, 13 | val imagePath: String 14 | ) 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/model/User.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.model 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | 6 | @Entity(tableName = "users") 7 | data class User( 8 | @PrimaryKey(autoGenerate = true) val id: Int = 0, 9 | val username: String, 10 | val email: String, 11 | val password: String, 12 | val role: String // "admin" or "user" 13 | ) 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/navigation/AppNavHost.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.navigation 2 | 3 | import PHome 4 | import android.os.Build 5 | import androidx.annotation.RequiresApi 6 | import androidx.compose.runtime.Composable 7 | import androidx.compose.ui.Modifier 8 | import androidx.compose.ui.platform.LocalContext 9 | import androidx.lifecycle.viewmodel.compose.viewModel 10 | import androidx.navigation.NavHostController 11 | import androidx.navigation.NavType 12 | import androidx.navigation.compose.NavHost 13 | import androidx.navigation.compose.composable 14 | import androidx.navigation.compose.rememberNavController 15 | import androidx.navigation.navArgument 16 | import com.harry.sokomart.data.UserDatabase 17 | import com.harry.sokomart.repository.UserRepository 18 | import com.harry.sokomart.ui.screens.about.AboutScreen 19 | import com.harry.sokomart.ui.screens.auth.LoginScreen 20 | import com.harry.sokomart.ui.screens.auth.RegisterScreen 21 | import com.harry.sokomart.ui.screens.form.FormScreen 22 | import com.harry.sokomart.ui.screens.home.HomeScreen 23 | import com.harry.sokomart.ui.screens.intent.IntentScreen 24 | import com.harry.sokomart.ui.screens.item.ItemScreen 25 | import com.harry.sokomart.ui.screens.more.MoreScreen 26 | import com.harry.sokomart.ui.screens.paylinkauthentication.SignInScreen 27 | import com.harry.sokomart.ui.screens.paylinkauthentication.SignInScreenPreview 28 | import com.harry.sokomart.ui.screens.products.AddProductScreen 29 | import com.harry.sokomart.ui.screens.products.EditProductScreen 30 | import com.harry.sokomart.ui.screens.products.ProductListScreen 31 | import com.harry.sokomart.ui.screens.service.ServiceScreen 32 | import com.harry.sokomart.ui.screens.splash.SplashScreen 33 | import com.harry.sokomart.ui.screens.start.StartScreen 34 | import com.harry.sokomart.viewmodel.AuthViewModel 35 | import com.harry.sokomart.viewmodel.ProductViewModel 36 | 37 | @RequiresApi(Build.VERSION_CODES.M) 38 | @Composable 39 | fun AppNavHost( 40 | modifier: Modifier = Modifier, 41 | navController: NavHostController = rememberNavController(), 42 | startDestination: String = ROUT_SPLASH, 43 | productViewModel: ProductViewModel = viewModel(), 44 | ) { 45 | val context = LocalContext.current 46 | 47 | NavHost( 48 | navController = navController, 49 | startDestination = startDestination, 50 | modifier = modifier 51 | ) { 52 | composable(ROUT_HOME) { 53 | HomeScreen(navController) 54 | } 55 | composable(ROUT_ABOUT) { 56 | AboutScreen(navController) 57 | } 58 | composable(ROUT_ITEM) { 59 | ItemScreen(navController) 60 | } 61 | composable(ROUT_START) { 62 | StartScreen(navController) 63 | } 64 | composable(ROUT_INTENT) { 65 | IntentScreen(navController) 66 | } 67 | composable(ROUT_MORE) { 68 | MoreScreen(navController) 69 | } 70 | composable(ROUT_DASHBOARD) { 71 | DashboardScreen(navController) 72 | } 73 | composable(ROUT_SERVICE) { 74 | ServiceScreen(navController) 75 | } 76 | composable(ROUT_SPLASHS) { 77 | Splash(navController) 78 | } 79 | composable(ROUT_SPLASH) { 80 | SplashScreen(navController) 81 | } 82 | composable(ROUT_FORM) { 83 | FormScreen(navController) 84 | } 85 | composable(ROUT_PHOME) { 86 | PHome(navController) 87 | } 88 | 89 | //AUTHENTICATION 90 | 91 | // Initialize Room Database and Repository for Authentication 92 | val appDatabase = UserDatabase.getDatabase(context) 93 | val authRepository = UserRepository(appDatabase.userDao()) 94 | val authViewModel: AuthViewModel = AuthViewModel(authRepository) 95 | composable(ROUT_REGISTER) { 96 | RegisterScreen(authViewModel, navController) { 97 | navController.navigate(ROUT_LOGIN) { 98 | popUpTo(ROUT_REGISTER) { inclusive = true } 99 | } 100 | } 101 | } 102 | 103 | composable(ROUT_LOGIN) { 104 | LoginScreen(authViewModel, navController) { 105 | navController.navigate(ROUT_HOME) { 106 | popUpTo(ROUT_LOGIN) { inclusive = true } 107 | } 108 | } 109 | } 110 | 111 | // PRODUCTS 112 | composable(ROUT_ADD_PRODUCT) { 113 | AddProductScreen(navController, productViewModel) 114 | } 115 | 116 | composable(ROUT_PRODUCT_LIST) { 117 | ProductListScreen(navController, productViewModel) 118 | } 119 | 120 | composable( 121 | route = ROUT_EDIT_PRODUCT, 122 | arguments = listOf(navArgument("productId") { type = NavType.IntType }) 123 | ) { backStackEntry -> 124 | val productId = backStackEntry.arguments?.getInt("productId") 125 | if (productId != null) { 126 | EditProductScreen(productId, navController, productViewModel) 127 | } 128 | } 129 | 130 | 131 | 132 | 133 | 134 | } 135 | } 136 | 137 | @Composable 138 | fun Splashscreen(x0: NavHostController) { 139 | TODO("Not yet implemented") 140 | } 141 | 142 | @Composable 143 | fun Splash(x0: NavHostController) { 144 | TODO("Not yet implemented") 145 | } 146 | 147 | @Composable 148 | fun DashboardScreen(x0: NavHostController) { 149 | TODO("Not yet implemented") 150 | } 151 | 152 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/navigation/Routes.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.navigation 2 | 3 | const val ROUT_HOME = "home" 4 | const val ROUT_ABOUT = "about" 5 | const val ROUT_ITEM = "item" 6 | const val ROUT_START = "start" 7 | const val ROUT_INTENT = "intent" 8 | const val ROUT_MORE = "more" 9 | const val ROUT_DASHBOARD = "dashboard" 10 | const val ROUT_SERVICE = "service" 11 | const val ROUT_SPLASH = "splash" 12 | const val ROUT_SPLASHS = "splashs" 13 | const val ROUT_NEWSCREEN = "newscreen" 14 | const val ROUT_FORM = "form" 15 | const val ROUT_PHOME = "phome" 16 | const val ROUT_PROFILE = "profile" 17 | 18 | //auth 19 | const val ROUT_REGISTER = "Register" 20 | const val ROUT_LOGIN = "Login" 21 | const val ROUT_LOGIN = "Login" 22 | 23 | //Products 24 | 25 | const val ROUT_ADD_PRODUCT = "add_product" 26 | const val ROUT_PRODUCT_LIST = "product_list" 27 | const val ROUT_EDIT_PRODUCT = "edit_product/{productId}" -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/repository/ProductRepository.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.repository 2 | 3 | import android.content.Context 4 | import com.harry.sokomart.data.ProductDatabase 5 | import com.harry.sokomart.model.Product 6 | 7 | class ProductRepository(context: Context) { 8 | private val productDao = ProductDatabase.getDatabase(context).productDao() 9 | 10 | suspend fun insertProduct(product: Product) { 11 | productDao.insertProduct(product) 12 | } 13 | 14 | fun getAllProducts() = productDao.getAllProducts() 15 | 16 | suspend fun deleteProduct(product: Product) = productDao.deleteProduct(product) 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/repository/UserRepository.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.repository 2 | 3 | import com.harry.sokomart.data.UserDao 4 | import com.harry.sokomart.model.User 5 | 6 | 7 | class UserRepository(private val userDao: UserDao) { 8 | suspend fun registerUser(user: User) { 9 | userDao.registerUser(user) 10 | } 11 | 12 | suspend fun loginUser(email: String, password: String): User? { 13 | return userDao.loginUser(email, password) 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/about/AboutScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.about 2 | 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.ui.tooling.preview.Preview 5 | import androidx.navigation.NavController 6 | import androidx.navigation.compose.rememberNavController 7 | 8 | @Composable 9 | fun AboutScreen(navController: NavController){ 10 | 11 | 12 | } 13 | 14 | @Preview(showBackground = true) 15 | @Composable 16 | fun AboutScreenPreview(){ 17 | AboutScreen(navController= rememberNavController()) 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/auth/LoginScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.auth 2 | 3 | import android.widget.Toast 4 | import androidx.compose.animation.AnimatedVisibility 5 | import androidx.compose.animation.core.tween 6 | import androidx.compose.animation.fadeIn 7 | import androidx.compose.animation.fadeOut 8 | import androidx.compose.foundation.background 9 | import androidx.compose.foundation.layout.* 10 | import androidx.compose.foundation.shape.RoundedCornerShape 11 | import androidx.compose.foundation.text.KeyboardOptions 12 | import androidx.compose.material.icons.Icons 13 | import androidx.compose.material.icons.filled.Email 14 | import androidx.compose.material.icons.filled.Lock 15 | import androidx.compose.material3.* 16 | import androidx.compose.runtime.Composable 17 | import androidx.compose.runtime.LaunchedEffect 18 | import androidx.compose.runtime.getValue 19 | import androidx.compose.runtime.mutableStateOf 20 | import androidx.compose.runtime.remember 21 | import androidx.compose.runtime.setValue 22 | import androidx.compose.ui.Alignment 23 | import androidx.compose.ui.Modifier 24 | import androidx.compose.ui.graphics.Brush 25 | import androidx.compose.ui.graphics.Color 26 | import androidx.compose.ui.platform.LocalContext 27 | import androidx.compose.ui.res.painterResource 28 | import androidx.compose.ui.text.font.FontFamily 29 | import androidx.compose.ui.text.input.KeyboardType 30 | import androidx.compose.ui.text.input.PasswordVisualTransformation 31 | import androidx.compose.ui.text.input.VisualTransformation 32 | import androidx.compose.ui.unit.dp 33 | import androidx.compose.ui.unit.sp 34 | import androidx.navigation.NavController 35 | import com.harry.sokomart.navigation.ROUT_HOME 36 | import com.harry.sokomart.navigation.ROUT_PROFILE 37 | import com.harry.sokomart.navigation.ROUT_REGISTER 38 | import com.harry.sokomart.viewmodel.AuthViewModel 39 | import com.harry.sokomart.R 40 | 41 | @Composable 42 | fun LoginScreen( 43 | authViewModel: AuthViewModel, 44 | navController: NavController, 45 | onLoginSuccess: () -> Unit 46 | ) { 47 | var email by remember { mutableStateOf("") } 48 | var password by remember { mutableStateOf("") } 49 | var passwordVisible by remember { mutableStateOf(false) } 50 | val context = LocalContext.current 51 | 52 | // Observe login logic 53 | LaunchedEffect(authViewModel) { 54 | authViewModel.loggedInUser = { user -> 55 | if (user == null) { 56 | Toast.makeText(context, "Invalid Credentials", Toast.LENGTH_SHORT).show() 57 | } else { 58 | if (user.role == "admin") { 59 | navController.navigate(ROUT_PROFILE) { 60 | } 61 | } else { 62 | navController.navigate(ROUT_HOME) { 63 | } 64 | } 65 | } 66 | } 67 | } 68 | //End of login logic 69 | 70 | Column( 71 | modifier = Modifier 72 | .fillMaxSize() 73 | .padding(20.dp), 74 | verticalArrangement = Arrangement.Center, 75 | horizontalAlignment = Alignment.CenterHorizontally 76 | ) { 77 | // Animated Welcome Text 78 | AnimatedVisibility( 79 | visible = true, 80 | enter = fadeIn(animationSpec = tween(1000)), 81 | exit = fadeOut(animationSpec = tween(1000)) 82 | ) { 83 | Text( 84 | text = "Welcome Back!", 85 | fontSize = 40.sp, 86 | fontFamily = FontFamily.Cursive 87 | ) 88 | } 89 | 90 | Spacer(modifier = Modifier.height(24.dp)) 91 | 92 | // Email Input 93 | OutlinedTextField( 94 | value = email, 95 | onValueChange = { email = it }, 96 | label = { Text("Email") }, 97 | leadingIcon = { Icon(Icons.Filled.Email, contentDescription = "Email Icon") }, 98 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email), 99 | modifier = Modifier.fillMaxWidth(), 100 | shape = RoundedCornerShape(12.dp) 101 | ) 102 | 103 | Spacer(modifier = Modifier.height(12.dp)) 104 | 105 | // Password Input with Show/Hide Toggle 106 | OutlinedTextField( 107 | value = password, 108 | onValueChange = { password = it }, 109 | label = { Text("Password") }, 110 | leadingIcon = { Icon(Icons.Filled.Lock, contentDescription = "Password Icon") }, 111 | visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), 112 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), 113 | modifier = Modifier.fillMaxWidth(), 114 | shape = RoundedCornerShape(12.dp), 115 | trailingIcon = { 116 | val image = if (passwordVisible) painterResource(R.drawable.visibility) else painterResource(R.drawable.visibilityoff) 117 | IconButton(onClick = { passwordVisible = !passwordVisible }) { 118 | Icon(image, contentDescription = if (passwordVisible) "Hide Password" else "Show Password") 119 | } 120 | } 121 | ) 122 | 123 | Spacer(modifier = Modifier.height(20.dp)) 124 | 125 | // Gradient Login Button 126 | Box( 127 | modifier = Modifier 128 | .fillMaxWidth() 129 | .height(50.dp) 130 | .background( 131 | brush = Brush.horizontalGradient( 132 | colors = listOf(Color(0xFF00C6FF), Color(0xFF0072FF)) 133 | ), 134 | shape = RoundedCornerShape(12.dp) 135 | ), 136 | contentAlignment = Alignment.Center 137 | ) { 138 | Button( 139 | onClick = { 140 | if (email.isBlank() || password.isBlank()) { 141 | Toast.makeText(context, "Please enter email and password", Toast.LENGTH_SHORT).show() 142 | } else { 143 | authViewModel.loginUser(email, password) 144 | } 145 | }, 146 | modifier = Modifier.fillMaxSize(), 147 | colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), 148 | shape = RoundedCornerShape(12.dp) 149 | ) { 150 | Text("Login", color = Color.White) 151 | } 152 | } 153 | 154 | Spacer(modifier = Modifier.height(16.dp)) 155 | 156 | // Register Navigation Button 157 | TextButton(onClick = { navController.navigate(ROUT_REGISTER) }) { 158 | Text("Don't have an account? Register") 159 | } 160 | } 161 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/auth/RegistrationScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.auth 2 | 3 | import android.widget.Toast 4 | import androidx.compose.animation.AnimatedVisibility 5 | import androidx.compose.animation.core.LinearEasing 6 | import androidx.compose.animation.core.animateFloatAsState 7 | import androidx.compose.animation.core.tween 8 | import androidx.compose.animation.fadeIn 9 | import androidx.compose.animation.fadeOut 10 | import androidx.compose.foundation.background 11 | import androidx.compose.foundation.layout.* 12 | import androidx.compose.foundation.text.KeyboardOptions 13 | import androidx.compose.material.icons.Icons 14 | import androidx.compose.material.icons.filled.* 15 | import androidx.compose.material3.* 16 | import androidx.compose.runtime.* 17 | import androidx.compose.ui.Alignment 18 | import androidx.compose.ui.Modifier 19 | import androidx.compose.ui.graphics.Brush 20 | import androidx.compose.ui.graphics.Color 21 | import androidx.compose.ui.platform.LocalContext 22 | import androidx.compose.ui.res.painterResource 23 | import androidx.compose.ui.text.font.FontFamily 24 | import androidx.compose.ui.text.input.* 25 | import androidx.compose.ui.unit.dp 26 | import androidx.compose.ui.unit.sp 27 | import androidx.navigation.NavController 28 | import com.harry.sokomart.model.User 29 | import com.harry.sokomart.navigation.ROUT_LOGIN 30 | import com.harry.sokomart.viewmodel.AuthViewModel 31 | import com.harry.sokomart.R 32 | 33 | @OptIn(ExperimentalMaterial3Api::class) 34 | @Composable 35 | fun RegisterScreen( 36 | authViewModel: AuthViewModel, 37 | navController: NavController, 38 | onRegisterSuccess: () -> Unit 39 | ) { 40 | var username by remember { mutableStateOf("") } 41 | var email by remember { mutableStateOf("") } 42 | var password by remember { mutableStateOf("") } 43 | var confirmPassword by remember { mutableStateOf("") } 44 | var passwordVisible by remember { mutableStateOf(false) } 45 | var confirmPasswordVisible by remember { mutableStateOf(false) } 46 | val context = LocalContext.current 47 | val animatedAlpha by animateFloatAsState( 48 | targetValue = 1f, 49 | animationSpec = tween(durationMillis = 1500, easing = LinearEasing), 50 | label = "Animated Alpha" 51 | ) 52 | 53 | Column( 54 | modifier = Modifier 55 | .fillMaxSize() 56 | .padding(16.dp), 57 | verticalArrangement = Arrangement.Center, 58 | horizontalAlignment = Alignment.CenterHorizontally 59 | ) { 60 | Spacer(modifier = Modifier.height(8.dp)) 61 | AnimatedVisibility(visible = true, enter = fadeIn(), exit = fadeOut()) { 62 | Text( 63 | "Create Your Account", 64 | fontSize = 40.sp, 65 | fontFamily = FontFamily.Cursive 66 | ) 67 | } 68 | 69 | Spacer(modifier = Modifier.height(16.dp)) 70 | 71 | //Username 72 | OutlinedTextField( 73 | value = username, 74 | onValueChange = { username = it }, 75 | label = { Text("Username") }, 76 | leadingIcon = { Icon(Icons.Filled.Person, contentDescription = "Username Icon") }, 77 | modifier = Modifier.fillMaxWidth() 78 | ) 79 | //End of username 80 | 81 | 82 | 83 | Spacer(modifier = Modifier.height(8.dp)) 84 | 85 | //Email 86 | OutlinedTextField( 87 | value = email, 88 | onValueChange = { email = it }, 89 | label = { Text("Email") }, 90 | leadingIcon = { Icon(Icons.Filled.Email, contentDescription = "Email Icon") }, 91 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email), 92 | modifier = Modifier.fillMaxWidth() 93 | ) 94 | //End of email 95 | 96 | Spacer(modifier = Modifier.height(8.dp)) 97 | 98 | 99 | //Role 100 | var role by remember { mutableStateOf("user") } 101 | val roleOptions = listOf("user", "admin") 102 | var expanded by remember { mutableStateOf(false) } 103 | 104 | ExposedDropdownMenuBox( 105 | expanded = expanded, 106 | onExpandedChange = { expanded = !expanded } 107 | ) { 108 | OutlinedTextField( 109 | value = role, 110 | onValueChange = {}, 111 | readOnly = true, 112 | label = { Text("Select Role") }, 113 | trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, 114 | modifier = Modifier.menuAnchor().fillMaxWidth() 115 | ) 116 | ExposedDropdownMenu( 117 | expanded = expanded, 118 | onDismissRequest = { expanded = false } 119 | ) { 120 | roleOptions.forEach { selectionOption -> 121 | DropdownMenuItem( 122 | text = { Text(selectionOption) }, 123 | onClick = { 124 | role = selectionOption 125 | expanded = false 126 | } 127 | ) 128 | } 129 | } 130 | } 131 | //End of role 132 | 133 | 134 | 135 | 136 | 137 | 138 | // Password Input Field with Show/Hide Toggle 139 | OutlinedTextField( 140 | value = password, 141 | onValueChange = { password = it }, 142 | label = { Text("Password") }, 143 | visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), 144 | leadingIcon = { Icon(Icons.Filled.Lock, contentDescription = "Password Icon") }, 145 | trailingIcon = { 146 | val image = if (passwordVisible) painterResource(R.drawable.visibility) else painterResource(R.drawable.visibilityoff) 147 | IconButton(onClick = { passwordVisible = !passwordVisible }) { 148 | Icon(image, contentDescription = if (passwordVisible) "Hide Password" else "Show Password") 149 | } 150 | }, 151 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), 152 | modifier = Modifier.fillMaxWidth() 153 | ) 154 | 155 | Spacer(modifier = Modifier.height(8.dp)) 156 | 157 | // Confirm Password Input Field with Show/Hide Toggle 158 | OutlinedTextField( 159 | value = confirmPassword, 160 | onValueChange = { confirmPassword = it }, 161 | label = { Text("Confirm Password") }, 162 | visualTransformation = if (confirmPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(), 163 | leadingIcon = { Icon(Icons.Filled.Lock, contentDescription = "Confirm Password Icon") }, 164 | trailingIcon = { 165 | val image = if (confirmPasswordVisible) painterResource(R.drawable.visibility) else painterResource(R.drawable.visibilityoff) 166 | IconButton(onClick = { confirmPasswordVisible = !confirmPasswordVisible }) { 167 | Icon(image, contentDescription = if (confirmPasswordVisible) "Hide Password" else "Show Password") 168 | } 169 | }, 170 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), 171 | modifier = Modifier.fillMaxWidth() 172 | ) 173 | 174 | Spacer(modifier = Modifier.height(5.dp)) 175 | 176 | Box( 177 | modifier = Modifier 178 | .fillMaxWidth() 179 | .height(50.dp) 180 | .background( 181 | brush = Brush.horizontalGradient( 182 | colors = listOf(Color(0xFF00C6FF), Color(0xFF0072FF)) 183 | ), 184 | shape = MaterialTheme.shapes.medium 185 | ), 186 | contentAlignment = Alignment.Center 187 | ) { 188 | Button( 189 | onClick = { 190 | if (username.isBlank() || email.isBlank() || password.isBlank() || confirmPassword.isBlank()) { 191 | Toast.makeText(context, "All fields are required", Toast.LENGTH_SHORT).show() 192 | } else if (password != confirmPassword) { 193 | Toast.makeText(context, "Passwords do not match", Toast.LENGTH_SHORT).show() 194 | } else { 195 | authViewModel.registerUser(User(username = username, email = email, role = role, password = password)) 196 | onRegisterSuccess() 197 | } 198 | }, 199 | modifier = Modifier.fillMaxSize(), 200 | colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent) 201 | ) { 202 | Text("Register", color = Color.White) 203 | } 204 | } 205 | 206 | Spacer(modifier = Modifier.height(5.dp)) 207 | 208 | TextButton( 209 | onClick = { navController.navigate(ROUT_LOGIN) } 210 | ) { 211 | Text("Already have an account? Login") 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/contact/ContactScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.contact 2 | 3 | import androidx.compose.foundation.layout.Column 4 | import androidx.compose.foundation.layout.Spacer 5 | import androidx.compose.foundation.layout.fillMaxSize 6 | import androidx.compose.foundation.layout.height 7 | import androidx.compose.foundation.layout.padding 8 | import androidx.compose.material.icons.Icons 9 | import androidx.compose.material.icons.filled.Add 10 | import androidx.compose.material.icons.filled.ArrowBack 11 | import androidx.compose.material.icons.filled.Favorite 12 | import androidx.compose.material.icons.filled.Home 13 | import androidx.compose.material.icons.filled.Person 14 | import androidx.compose.material3.ExperimentalMaterial3Api 15 | import androidx.compose.material3.FloatingActionButton 16 | import androidx.compose.material3.Icon 17 | import androidx.compose.material3.IconButton 18 | import androidx.compose.material3.NavigationBar 19 | import androidx.compose.material3.NavigationBarItem 20 | import androidx.compose.material3.Scaffold 21 | import androidx.compose.material3.Text 22 | import androidx.compose.material3.TopAppBar 23 | import androidx.compose.material3.TopAppBarDefaults 24 | import androidx.compose.runtime.Composable 25 | import androidx.compose.runtime.getValue 26 | import androidx.compose.runtime.mutableStateOf 27 | import androidx.compose.runtime.remember 28 | import androidx.compose.runtime.setValue 29 | import androidx.compose.ui.Modifier 30 | import androidx.compose.ui.graphics.Color 31 | import androidx.navigation.NavController 32 | import androidx.compose.ui.tooling.preview.Preview 33 | import androidx.compose.ui.unit.dp 34 | import androidx.compose.ui.unit.sp 35 | import androidx.navigation.compose.rememberNavController 36 | 37 | @OptIn(ExperimentalMaterial3Api::class) 38 | @Composable 39 | fun ContactScreen(navController: NavController){ 40 | //Scaffold 41 | 42 | var selectedIndex by remember { mutableStateOf(0) } 43 | 44 | Scaffold( 45 | //TopBar 46 | topBar = { 47 | TopAppBar( 48 | title = { Text("Item Screen") }, 49 | navigationIcon = { 50 | IconButton(onClick = { /* Handle back/nav */ }) { 51 | Icon(Icons.Default.ArrowBack, contentDescription = "Back") 52 | } 53 | }, 54 | colors = TopAppBarDefaults.topAppBarColors( 55 | containerColor = Color.LightGray, 56 | titleContentColor = Color.White, 57 | navigationIconContentColor = Color.White 58 | ) 59 | ) 60 | }, 61 | 62 | //BottomBar 63 | bottomBar = { 64 | NavigationBar( 65 | containerColor = Color.LightGray 66 | ){ 67 | NavigationBarItem( 68 | icon = { Icon(Icons.Default.Home, contentDescription = "Home") }, 69 | label = { Text("Home") }, 70 | selected = selectedIndex == 0, 71 | onClick = { selectedIndex = 0 72 | //navController.navigate(ROUT_HOME) 73 | } 74 | ) 75 | NavigationBarItem( 76 | icon = { Icon(Icons.Default.Favorite, contentDescription = "Favorites") }, 77 | label = { Text("Favorites") }, 78 | selected = selectedIndex == 1, 79 | onClick = { selectedIndex = 1 80 | // navController.navigate(ROUT_HOME) 81 | } 82 | ) 83 | NavigationBarItem( 84 | icon = { Icon(Icons.Default.Person, contentDescription = "Profile") }, 85 | label = { Text("Profile") }, 86 | selected = selectedIndex == 2, 87 | onClick = { selectedIndex = 2 88 | // navController.navigate(ROUT_HOME) 89 | } 90 | ) 91 | 92 | } 93 | }, 94 | 95 | //FloatingActionButton 96 | floatingActionButton = { 97 | FloatingActionButton( 98 | onClick = { /* Add action */ }, 99 | containerColor = Color.LightGray 100 | ) { 101 | Icon(Icons.Default.Add, contentDescription = "Add") 102 | } 103 | }, 104 | content = { paddingValues -> 105 | Column( 106 | modifier = Modifier 107 | .padding(paddingValues).fillMaxSize() 108 | ) { 109 | 110 | 111 | //Main Contents of the page 112 | Text(text = "Welcome to Homescreen Screen", fontSize = 20.sp) 113 | Spacer(modifier = Modifier.height(8.dp)) 114 | Text("This is where the main content goes.") 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | } 128 | } 129 | ) 130 | 131 | //End of scaffold 132 | 133 | 134 | 135 | 136 | 137 | } 138 | 139 | 140 | 141 | 142 | @Preview(showBackground = true) 143 | @Composable 144 | fun ContactScreenPreview(){ 145 | ContactScreen(navController= rememberNavController()) 146 | } 147 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/dashboard/DashboardScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.dashboard 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.clickable 5 | import androidx.compose.foundation.layout.Arrangement 6 | import androidx.compose.foundation.layout.Column 7 | import androidx.compose.foundation.layout.Row 8 | import androidx.compose.foundation.layout.Spacer 9 | import androidx.compose.foundation.layout.fillMaxSize 10 | import androidx.compose.foundation.layout.fillMaxWidth 11 | import androidx.compose.foundation.layout.height 12 | import androidx.compose.foundation.layout.padding 13 | import androidx.compose.foundation.layout.size 14 | import androidx.compose.foundation.layout.width 15 | import androidx.compose.foundation.shape.RoundedCornerShape 16 | import androidx.compose.material3.Card 17 | import androidx.compose.material3.CardDefaults 18 | import androidx.compose.material3.Text 19 | import androidx.compose.runtime.Composable 20 | import androidx.compose.ui.Alignment 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.draw.clip 23 | import androidx.compose.ui.res.painterResource 24 | import androidx.compose.ui.tooling.preview.Preview 25 | import androidx.compose.ui.unit.dp 26 | import androidx.compose.ui.unit.sp 27 | import androidx.navigation.NavController 28 | import androidx.navigation.compose.rememberNavController 29 | import com.harry.sokomart.R 30 | import com.harry.sokomart.navigation.ROUT_ITEM 31 | import com.harry.sokomart.navigation.ROUT_START 32 | import com.harry.sokomart.ui.theme.mytheme 33 | 34 | @Composable 35 | fun AboutScreen(navController: NavController){ 36 | Column ( 37 | modifier = Modifier.fillMaxSize(), 38 | ){ 39 | //card start 40 | Card ( 41 | modifier = Modifier.fillMaxWidth().height(300.dp), 42 | shape = RoundedCornerShape(bottomStart = 40.dp, bottomEnd = 40.dp), 43 | colors = CardDefaults.cardColors(mytheme) 44 | ){ 45 | Column ( 46 | modifier = Modifier.fillMaxSize(), 47 | horizontalAlignment = Alignment.CenterHorizontally, 48 | verticalArrangement = Arrangement.Center 49 | ){ 50 | Image( 51 | painter = painterResource(R.drawable.img_14), 52 | contentDescription = "home", 53 | modifier = Modifier.size(200.dp).clip(shape = RoundedCornerShape(10.dp)), 54 | ) 55 | Text( 56 | text = "Kai & Karo", 57 | fontSize = 48.sp, 58 | 59 | ) 60 | 61 | } 62 | } 63 | //end of card 64 | Row ( 65 | modifier = Modifier.padding(20.dp) 66 | ){ 67 | Spacer(modifier = Modifier.width(20.dp)) 68 | Card ( 69 | modifier = Modifier.width(150.dp).height(180.dp).clickable{ 70 | navController.navigate(ROUT_START) 71 | }, 72 | elevation = CardDefaults.cardElevation(10.dp) 73 | ){ 74 | Column ( 75 | modifier = Modifier.fillMaxSize(), 76 | horizontalAlignment = Alignment.CenterHorizontally, 77 | verticalArrangement = Arrangement.Center, 78 | ){ 79 | Image( 80 | painter = painterResource(R.drawable.img_9), 81 | contentDescription = "home", 82 | modifier = Modifier.size(100.dp).clip(shape = RoundedCornerShape(10.dp)), 83 | ) 84 | Text( 85 | text = "Home" 86 | ) 87 | } 88 | } 89 | Spacer(modifier = Modifier.width(20.dp)) 90 | Card ( 91 | modifier = Modifier.width(150.dp).height(180.dp), 92 | elevation = CardDefaults.cardElevation(10.dp) 93 | ){ 94 | Column ( 95 | modifier = Modifier.fillMaxSize(), 96 | horizontalAlignment = Alignment.CenterHorizontally, 97 | verticalArrangement = Arrangement.Center, 98 | ){ 99 | Image( 100 | painter = painterResource(R.drawable.img_10), 101 | contentDescription = "About", 102 | modifier = Modifier.size(100.dp).clip(shape = RoundedCornerShape(10.dp)), 103 | ) 104 | Text( 105 | text = "About" 106 | ) 107 | } 108 | } 109 | Spacer(modifier = Modifier.height(20.dp)) 110 | } 111 | Row ( 112 | modifier = Modifier.padding(20.dp) 113 | ){ 114 | Spacer(modifier = Modifier.width(20.dp)) 115 | Card ( 116 | modifier = Modifier.width(150.dp).height(180.dp), 117 | elevation = CardDefaults.cardElevation(10.dp) 118 | ){ 119 | Column ( 120 | modifier = Modifier.fillMaxSize(), 121 | horizontalAlignment = Alignment.CenterHorizontally, 122 | verticalArrangement = Arrangement.Center, 123 | ){ 124 | Image( 125 | painter = painterResource(R.drawable.img_12), 126 | contentDescription = "home", 127 | modifier = Modifier.size(100.dp).clip(shape = RoundedCornerShape(10.dp)), 128 | ) 129 | Text( 130 | text = "Contact" 131 | ) 132 | } 133 | } 134 | Spacer(modifier = Modifier.width(20.dp)) 135 | Card ( 136 | modifier = Modifier.width(150.dp).height(180.dp).clickable{ 137 | navController.navigate(ROUT_ITEM) 138 | }, 139 | elevation = CardDefaults.cardElevation(10.dp) 140 | ){ 141 | Column ( 142 | modifier = Modifier.fillMaxSize(), 143 | horizontalAlignment = Alignment.CenterHorizontally, 144 | verticalArrangement = Arrangement.Center, 145 | ){ 146 | Image( 147 | painter = painterResource(R.drawable.img_11), 148 | contentDescription = "home", 149 | modifier = Modifier.size(100.dp).clip(shape = RoundedCornerShape(10.dp)), 150 | ) 151 | Text( 152 | text = "Products" 153 | ) 154 | } 155 | } 156 | Spacer(modifier = Modifier.height(20.dp)) 157 | } 158 | } 159 | 160 | } 161 | 162 | @Preview(showBackground = true) 163 | @Composable 164 | fun AboutScreenPreview(){ 165 | AboutScreen(navController= rememberNavController()) 166 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/form/FormScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.form 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.layout.Arrangement 5 | import androidx.compose.foundation.layout.Column 6 | import androidx.compose.foundation.layout.Spacer 7 | import androidx.compose.foundation.layout.fillMaxSize 8 | import androidx.compose.foundation.layout.fillMaxWidth 9 | import androidx.compose.foundation.layout.height 10 | import androidx.compose.foundation.layout.padding 11 | import androidx.compose.foundation.layout.size 12 | import androidx.compose.foundation.shape.RoundedCornerShape 13 | import androidx.compose.foundation.text.KeyboardOptions 14 | import androidx.compose.material.icons.Icons 15 | import androidx.compose.material.icons.filled.Email 16 | import androidx.compose.material.icons.filled.Face 17 | import androidx.compose.material.icons.filled.Lock 18 | import androidx.compose.material.icons.filled.Person 19 | import androidx.compose.material3.Button 20 | import androidx.compose.material3.ButtonDefaults 21 | import androidx.compose.material3.Icon 22 | import androidx.compose.material3.OutlinedTextField 23 | import androidx.compose.material3.OutlinedTextFieldDefaults 24 | import androidx.compose.material3.Text 25 | import androidx.compose.runtime.Composable 26 | import androidx.compose.runtime.getValue 27 | import androidx.compose.runtime.mutableStateOf 28 | import androidx.compose.runtime.remember 29 | import androidx.compose.runtime.setValue 30 | import androidx.compose.ui.Alignment 31 | import androidx.compose.ui.Modifier 32 | import androidx.compose.ui.res.painterResource 33 | import androidx.compose.ui.text.input.KeyboardType 34 | import androidx.compose.ui.text.input.PasswordVisualTransformation 35 | import androidx.compose.ui.tooling.preview.Preview 36 | import androidx.compose.ui.unit.dp 37 | import androidx.compose.ui.unit.sp 38 | import androidx.navigation.NavController 39 | import androidx.navigation.compose.rememberNavController 40 | import com.harry.sokomart.R 41 | import com.harry.sokomart.ui.theme.blue 42 | import com.harry.sokomart.ui.theme.mytheme 43 | 44 | @Composable 45 | fun FormScreen(navController: NavController){ 46 | Column ( 47 | modifier = Modifier.fillMaxSize(), 48 | horizontalAlignment = Alignment.CenterHorizontally, 49 | verticalArrangement = Arrangement.Center 50 | ){ 51 | Image( 52 | painter = painterResource(id = R.drawable.img), 53 | contentDescription = "home", 54 | modifier = Modifier.size(250.dp), 55 | ) 56 | Text( 57 | text = "Sign Up", 58 | fontSize = 50.sp, 59 | color = mytheme 60 | ) 61 | Spacer(modifier = Modifier.height(10.dp)) 62 | 63 | //variables 64 | var fullname by remember { mutableStateOf("") } 65 | var username by remember { mutableStateOf("") } 66 | var email by remember { mutableStateOf("") } 67 | var password by remember { mutableStateOf("") } 68 | 69 | //fullname 70 | OutlinedTextField( 71 | value = fullname, 72 | onValueChange = { fullname = it }, 73 | modifier = Modifier.fillMaxWidth().padding(start = 15.dp, end = 15.dp), 74 | leadingIcon = { 75 | Icon( 76 | imageVector = Icons.Default.Person, 77 | contentDescription = "", 78 | tint = mytheme, 79 | ) 80 | }, 81 | label = { 82 | Text( 83 | text = "Full Name" 84 | ) 85 | }, 86 | colors = OutlinedTextFieldDefaults.colors( 87 | focusedBorderColor = blue, 88 | unfocusedBorderColor = mytheme, 89 | focusedLabelColor = blue, 90 | unfocusedLabelColor = mytheme, 91 | cursorColor = blue 92 | ), 93 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) 94 | 95 | ) 96 | //end of fullname 97 | //username 98 | OutlinedTextField( 99 | value = username, 100 | onValueChange = { username = it }, 101 | modifier = Modifier.fillMaxWidth().padding(start = 15.dp, end = 15.dp), 102 | leadingIcon = { 103 | Icon( 104 | imageVector = Icons.Default.Face, 105 | contentDescription = "", 106 | tint = mytheme, 107 | ) 108 | }, 109 | label = {Text(text = "Username")}, 110 | colors = OutlinedTextFieldDefaults.colors( 111 | focusedBorderColor = blue, 112 | unfocusedBorderColor = mytheme, 113 | focusedLabelColor = blue, 114 | unfocusedLabelColor = mytheme, 115 | cursorColor = blue 116 | ), 117 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) 118 | 119 | ) 120 | //end of username 121 | //email 122 | OutlinedTextField( 123 | value = email, 124 | onValueChange = { email = it }, 125 | modifier = Modifier.fillMaxWidth().padding(start = 15.dp, end = 15.dp), 126 | leadingIcon = { 127 | Icon( 128 | imageVector = Icons.Default.Email, 129 | contentDescription = "", 130 | tint = mytheme, 131 | ) 132 | }, 133 | label = {Text(text = "Email")}, 134 | colors = OutlinedTextFieldDefaults.colors( 135 | focusedBorderColor = blue, 136 | unfocusedBorderColor = mytheme, 137 | focusedLabelColor = blue, 138 | unfocusedLabelColor = mytheme, 139 | cursorColor = blue 140 | ), 141 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email) 142 | 143 | ) 144 | //end of email 145 | //password 146 | OutlinedTextField( 147 | value = password, 148 | onValueChange = { password = it }, 149 | modifier = Modifier.fillMaxWidth().padding(start = 15.dp, end = 15.dp), 150 | leadingIcon = { 151 | Icon( 152 | imageVector = Icons.Default.Lock, 153 | contentDescription = "", 154 | tint = mytheme, 155 | ) 156 | }, 157 | label = {Text(text = "Password")}, 158 | colors = OutlinedTextFieldDefaults.colors( 159 | focusedBorderColor = blue, 160 | unfocusedBorderColor = mytheme, 161 | focusedLabelColor = blue, 162 | unfocusedLabelColor = mytheme, 163 | cursorColor = blue 164 | ), 165 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), 166 | visualTransformation = PasswordVisualTransformation() 167 | 168 | ) 169 | //end of password 170 | Spacer(modifier = Modifier.height(10.dp)) 171 | //buton start 172 | Button( 173 | onClick = {}, 174 | shape = RoundedCornerShape(10.dp), 175 | colors = ButtonDefaults.buttonColors(mytheme), 176 | modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 20.dp) 177 | ) { 178 | Text(text = "Register") 179 | } 180 | //buton end 181 | } 182 | } 183 | 184 | @Preview(showBackground = true) 185 | @Composable 186 | fun FormScreenPreview(){ 187 | FormScreen(navController= rememberNavController()) 188 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/home/HomeScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.home 2 | 3 | import androidx.compose.foundation.layout.Column 4 | import androidx.compose.foundation.layout.fillMaxSize 5 | import androidx.compose.foundation.shape.RoundedCornerShape 6 | import androidx.compose.material3.Button 7 | import androidx.compose.material3.ButtonDefaults 8 | import androidx.compose.material3.Text 9 | import androidx.compose.runtime.Composable 10 | import androidx.compose.ui.Modifier 11 | import androidx.compose.ui.draw.paint 12 | import androidx.compose.ui.layout.ContentScale 13 | import androidx.compose.ui.res.painterResource 14 | import androidx.compose.ui.text.font.FontStyle 15 | import androidx.compose.ui.text.font.FontWeight 16 | import androidx.compose.ui.tooling.preview.Preview 17 | import androidx.compose.ui.unit.dp 18 | import androidx.compose.ui.unit.sp 19 | import androidx.navigation.NavController 20 | import androidx.navigation.compose.rememberNavController 21 | import com.harry.sokomart.R 22 | import com.harry.sokomart.ui.theme.newcyan 23 | 24 | @Composable 25 | fun HomeScreen(navController: NavController){ 26 | Column ( 27 | modifier = Modifier.fillMaxSize().paint(painter = painterResource(R.drawable.img_11), contentScale = ContentScale.FillBounds) 28 | ) { 29 | 30 | Text( 31 | text = "SokoMart", 32 | fontSize = 20.sp, 33 | fontWeight = FontWeight.ExtraBold 34 | ) 35 | Text( 36 | text = "An Ecommerce application", 37 | fontStyle = FontStyle.Italic 38 | ) 39 | Text( 40 | text = "SokoMart is a commerce application that enables the buying and selling of goods and services over the internet, encompassing various functionalities like product browsing, shopping carts, payment processing, and order tracking", 41 | ) 42 | Button( 43 | onClick = {}, 44 | shape = RoundedCornerShape(10.dp), 45 | colors = ButtonDefaults.buttonColors(newcyan) 46 | ) { 47 | Text(text = "See more") 48 | } 49 | } 50 | 51 | } 52 | 53 | 54 | @Preview(showBackground = true) 55 | @Composable 56 | fun HomeScreenPreview(){ 57 | HomeScreen(navController= rememberNavController()) 58 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/intent/IntentScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.intent 2 | 3 | import android.content.Intent 4 | import android.provider.MediaStore 5 | import androidx.compose.foundation.layout.Column 6 | import androidx.compose.foundation.layout.Spacer 7 | import androidx.compose.foundation.layout.fillMaxSize 8 | import androidx.compose.foundation.layout.fillMaxWidth 9 | import androidx.compose.foundation.layout.height 10 | import androidx.compose.foundation.layout.padding 11 | import androidx.compose.foundation.shape.RoundedCornerShape 12 | import androidx.compose.material.icons.Icons 13 | import androidx.compose.material.icons.filled.Menu 14 | import androidx.compose.material.icons.filled.Settings 15 | import androidx.compose.material.icons.filled.Share 16 | import androidx.compose.material3.Button 17 | import androidx.compose.material3.ButtonDefaults 18 | import androidx.compose.material3.ExperimentalMaterial3Api 19 | import androidx.compose.material3.Icon 20 | import androidx.compose.material3.IconButton 21 | import androidx.compose.material3.Text 22 | import androidx.compose.material3.TopAppBar 23 | import androidx.compose.material3.TopAppBarDefaults 24 | import androidx.compose.runtime.Composable 25 | import androidx.compose.ui.Modifier 26 | import androidx.compose.ui.platform.LocalContext 27 | import androidx.compose.ui.tooling.preview.Preview 28 | import androidx.compose.ui.unit.dp 29 | import androidx.core.net.toUri 30 | import androidx.navigation.NavController 31 | import androidx.navigation.compose.rememberNavController 32 | import com.harry.sokomart.ui.theme.mytheme 33 | import com.harry.sokomart.ui.theme.white 34 | 35 | @OptIn(ExperimentalMaterial3Api::class) 36 | @Composable 37 | fun IntentScreen(navController: NavController){ 38 | Column ( 39 | modifier = Modifier.fillMaxSize() 40 | ){ 41 | val mContext = LocalContext.current 42 | //TopAppBar 43 | TopAppBar( 44 | title = { 45 | Text(text = "Kai & Karo | intents") 46 | }, 47 | colors = TopAppBarDefaults.topAppBarColors( 48 | containerColor = mytheme, 49 | titleContentColor = white, 50 | navigationIconContentColor = white, 51 | actionIconContentColor = white 52 | ), 53 | navigationIcon = { 54 | IconButton(onClick = {}) { 55 | Icon(imageVector = Icons.Default.Menu, contentDescription = "") 56 | 57 | } 58 | }, 59 | 60 | actions = { 61 | IconButton(onClick = {}) { 62 | Icon(imageVector = Icons.Default.Share, contentDescription = "") 63 | } 64 | IconButton(onClick = {}) { 65 | Icon(imageVector = Icons.Default.Settings, contentDescription = "") 66 | } 67 | }, 68 | 69 | ) 70 | //End of TopAppBar 71 | Spacer(modifier = Modifier.height(10.dp)) 72 | 73 | 74 | //Mpesa 75 | Button( 76 | onClick = { 77 | val simToolKitLaunchIntent = 78 | mContext.packageManager.getLaunchIntentForPackage("com.android.stk") 79 | simToolKitLaunchIntent?.let { mContext.startActivity(it) } 80 | }, 81 | shape = RoundedCornerShape(10.dp), 82 | colors = ButtonDefaults.buttonColors(mytheme), 83 | modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 20.dp) 84 | ) { 85 | Text(text = "Mpesa") 86 | } 87 | 88 | Spacer(modifier = Modifier.height(10.dp)) 89 | 90 | //sms 91 | Button( 92 | onClick = { 93 | val smsIntent=Intent(Intent.ACTION_SENDTO) 94 | smsIntent.data="smsto:0797752627".toUri() 95 | smsIntent.putExtra("sms_body","Hello Glory,how was your day?") 96 | mContext.startActivity(smsIntent) 97 | }, 98 | shape = RoundedCornerShape(10.dp), 99 | colors = ButtonDefaults.buttonColors(mytheme), 100 | modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 20.dp) 101 | ) { 102 | Text(text = "SMS") 103 | } 104 | 105 | Spacer(modifier = Modifier.height(10.dp)) 106 | 107 | Button( 108 | onClick = { 109 | val callIntent=Intent(Intent.ACTION_DIAL) 110 | callIntent.data="tel:0720245837".toUri() 111 | mContext.startActivity(callIntent) 112 | }, 113 | shape = RoundedCornerShape(10.dp), 114 | colors = ButtonDefaults.buttonColors(mytheme), 115 | modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 20.dp) 116 | ) { 117 | Text(text = "Call") 118 | } 119 | 120 | Spacer(modifier = Modifier.height(10.dp)) 121 | 122 | //camera 123 | Button( 124 | onClick = { 125 | val cameraIntent=Intent(MediaStore.ACTION_IMAGE_CAPTURE) 126 | if (cameraIntent.resolveActivity(mContext.packageManager)!=null){ 127 | mContext.startActivity(cameraIntent) 128 | }else{ 129 | println("Camera app is not available") 130 | } 131 | }, 132 | shape = RoundedCornerShape(10.dp), 133 | colors = ButtonDefaults.buttonColors(mytheme), 134 | modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 20.dp) 135 | ) { 136 | Text(text = "Camera") 137 | } 138 | 139 | Spacer(modifier = Modifier.height(10.dp)) 140 | 141 | //email 142 | Button( 143 | onClick = { 144 | val shareIntent = Intent(Intent.ACTION_SEND) 145 | shareIntent.type = "text/plain" 146 | shareIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf("akinyiglory2@gmail.com")) 147 | shareIntent.putExtra(Intent.EXTRA_SUBJECT, "subject") 148 | shareIntent.putExtra(Intent.EXTRA_TEXT, "Hello, this is the email body") 149 | mContext.startActivity(shareIntent) 150 | }, 151 | shape = RoundedCornerShape(10.dp), 152 | colors = ButtonDefaults.buttonColors(mytheme), 153 | modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 20.dp) 154 | ) { 155 | Text(text = "Email") 156 | } 157 | } 158 | } 159 | 160 | @Preview(showBackground = true) 161 | @Composable 162 | fun IntentScreenPreview(){ 163 | IntentScreen(navController= rememberNavController()) 164 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/more/MoreScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.more 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.horizontalScroll 5 | import androidx.compose.foundation.layout.Box 6 | import androidx.compose.foundation.layout.Column 7 | import androidx.compose.foundation.layout.Row 8 | import androidx.compose.foundation.layout.Spacer 9 | import androidx.compose.foundation.layout.fillMaxSize 10 | import androidx.compose.foundation.layout.fillMaxWidth 11 | import androidx.compose.foundation.layout.height 12 | import androidx.compose.foundation.layout.padding 13 | import androidx.compose.foundation.layout.width 14 | import androidx.compose.foundation.rememberScrollState 15 | import androidx.compose.foundation.shape.RoundedCornerShape 16 | import androidx.compose.material.icons.Icons 17 | import androidx.compose.material.icons.filled.Favorite 18 | import androidx.compose.material.icons.filled.Menu 19 | import androidx.compose.material.icons.filled.Settings 20 | import androidx.compose.material3.Button 21 | import androidx.compose.material3.ButtonDefaults 22 | import androidx.compose.material3.ExperimentalMaterial3Api 23 | import androidx.compose.material3.Icon 24 | import androidx.compose.material3.IconButton 25 | import androidx.compose.material3.Text 26 | import androidx.compose.material3.TopAppBar 27 | import androidx.compose.material3.TopAppBarDefaults 28 | import androidx.compose.runtime.Composable 29 | import androidx.compose.ui.Alignment 30 | import androidx.compose.ui.Modifier 31 | import androidx.compose.ui.platform.LocalContext 32 | import androidx.compose.ui.res.painterResource 33 | import androidx.compose.ui.text.font.FontWeight 34 | import androidx.compose.ui.tooling.preview.Preview 35 | import androidx.compose.ui.unit.dp 36 | import androidx.compose.ui.unit.sp 37 | import androidx.navigation.NavController 38 | import androidx.navigation.compose.rememberNavController 39 | import com.harry.sokomart.R 40 | import com.harry.sokomart.navigation.ROUT_PHOME 41 | import com.harry.sokomart.ui.theme.mytheme 42 | import com.harry.sokomart.ui.theme.white 43 | 44 | @OptIn(ExperimentalMaterial3Api::class) 45 | @Composable 46 | fun MoreScreen(navController: NavController){ 47 | Column ( 48 | modifier = Modifier.fillMaxSize() 49 | ){ 50 | val mContext = LocalContext.current 51 | //TopAppBar 52 | TopAppBar( 53 | title = { 54 | Text(text = "Kai & Karo | Product") 55 | }, 56 | colors = TopAppBarDefaults.topAppBarColors( 57 | containerColor = mytheme, 58 | titleContentColor = white, 59 | navigationIconContentColor = white, 60 | actionIconContentColor = white 61 | ), 62 | navigationIcon = { 63 | IconButton(onClick = {}) { 64 | Icon(imageVector = Icons.Default.Menu, contentDescription = "") 65 | 66 | } 67 | }, 68 | 69 | actions = { 70 | IconButton(onClick = {}) { 71 | Icon(imageVector = Icons.Default.Settings, contentDescription = "") 72 | } 73 | }, 74 | 75 | ) 76 | //End of TopAppBar 77 | Spacer(modifier = Modifier.height(20.dp)) 78 | //box start 79 | Box ( 80 | modifier = Modifier.fillMaxWidth().height(250.dp) 81 | 82 | ){ 83 | Text( 84 | text = "Porsche Cayenne", 85 | fontWeight = FontWeight.Bold, 86 | fontSize = 30.sp 87 | ) 88 | Spacer(modifier = Modifier.height(5.dp)) 89 | Image( 90 | painter = painterResource(id = R.drawable.img), 91 | contentDescription = "home", 92 | modifier = Modifier.fillMaxSize() 93 | ) 94 | Icon( 95 | imageVector = Icons.Default.Favorite, contentDescription = "", 96 | modifier = Modifier.align(alignment = Alignment.TopEnd).padding(8.dp) 97 | ) 98 | 99 | } 100 | //end of box 101 | Spacer(modifier = Modifier.height(20.dp)) 102 | Text( 103 | text = "Porsche Cayenne", 104 | fontWeight = FontWeight.Bold, 105 | fontSize = 30.sp 106 | ) 107 | Spacer(modifier = Modifier.height(20.dp)) 108 | //row start 109 | Row ( 110 | modifier = Modifier.padding(start = 20.dp).horizontalScroll(rememberScrollState()) 111 | ){ 112 | Image( 113 | painter = painterResource(id = R.drawable.img), 114 | contentDescription = "home", 115 | modifier = Modifier.fillMaxWidth(), 116 | ) 117 | Image( 118 | painter = painterResource(id = R.drawable.img_6), 119 | contentDescription = "home", 120 | modifier = Modifier.fillMaxWidth(), 121 | ) 122 | Image( 123 | painter = painterResource(id = R.drawable.img_7), 124 | contentDescription = "home", 125 | modifier = Modifier.fillMaxWidth(), 126 | ) 127 | Image( 128 | painter = painterResource(id = R.drawable.img_8), 129 | contentDescription = "home", 130 | modifier = Modifier.fillMaxWidth(), 131 | ) 132 | } 133 | //row end 134 | Button( 135 | onClick = { 136 | navController.navigate(ROUT_PHOME) 137 | }, 138 | shape = RoundedCornerShape(10.dp), 139 | colors = ButtonDefaults.buttonColors(mytheme), 140 | modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 20.dp) 141 | ) { 142 | Text(text = "Purchase Here") 143 | } 144 | Spacer(modifier = Modifier.width(10.dp)) 145 | Text( 146 | text = "Reviews", 147 | fontWeight = FontWeight.Bold, 148 | fontSize = 30.sp, 149 | modifier = Modifier.padding(start = 10.dp, top = 10.dp) 150 | ) 151 | //Text( 152 | // text = "This mid-size, two-row luxury crossover is unnaturally light on its feet, with chassis tuning derived from over two decades of performance-SUV supremacy.\n" + 153 | // "US86,695.00 · 4.8 · Review by Drew Dorian\n" + 154 | // "\u200ETested: 2024 Porsche... · \u200E2025 Porsche Cayenne Hybrid · \u200EView Photos · \u200E2024", 155 | //fontSize = 18.dp, 156 | // ) 157 | 158 | } 159 | 160 | } 161 | 162 | @Preview(showBackground = true) 163 | @Composable 164 | fun MoreScreenPreview(){ 165 | MoreScreen(navController= rememberNavController()) 166 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/newscreen/NewScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.newscreen 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.horizontalScroll 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.foundation.rememberScrollState 8 | import androidx.compose.foundation.shape.CircleShape 9 | import androidx.compose.foundation.shape.RoundedCornerShape 10 | import androidx.compose.foundation.verticalScroll 11 | import androidx.compose.material.icons.Icons 12 | import androidx.compose.material.icons.filled.* 13 | import androidx.compose.material3.* 14 | import androidx.compose.runtime.* 15 | import androidx.compose.ui.Alignment 16 | import androidx.compose.ui.Modifier 17 | import androidx.compose.ui.draw.clip 18 | import androidx.compose.ui.graphics.Color 19 | import androidx.compose.ui.graphics.vector.ImageVector 20 | import androidx.compose.ui.res.painterResource 21 | import androidx.compose.ui.text.font.FontWeight 22 | import androidx.compose.ui.tooling.preview.Preview 23 | import androidx.compose.ui.unit.dp 24 | import androidx.compose.ui.unit.sp 25 | import androidx.navigation.NavController 26 | import androidx.navigation.compose.rememberNavController 27 | import com.harry.sokomart.ui.theme.blue 28 | import com.harry.sokomart.ui.theme.green 29 | import com.harry.sokomart.ui.theme.orange 30 | import com.harry.sokomart.R 31 | 32 | @OptIn(ExperimentalMaterial3Api::class) 33 | @Composable 34 | fun AboutScreen(navController: NavController) { 35 | var selectedIndex by remember { mutableStateOf(0) } 36 | 37 | Scaffold( 38 | floatingActionButton = { 39 | FloatingActionButton(onClick = { /* TODO: Add action */ }) { 40 | Icon(Icons.Default.Add, contentDescription = "Add") 41 | } 42 | }, 43 | floatingActionButtonPosition = FabPosition.Center, 44 | bottomBar = { 45 | NavigationBar(containerColor = Color.White) { 46 | NavigationBarItem( 47 | icon = { Icon(Icons.Default.Home, contentDescription = "Home") }, 48 | label = { Text("Home") }, 49 | selected = selectedIndex == 0, 50 | onClick = { selectedIndex = 0 } 51 | ) 52 | NavigationBarItem( 53 | icon = { Icon(Icons.Default.Favorite, contentDescription = "Tasks") }, 54 | label = { Text("Tasks") }, 55 | selected = selectedIndex == 1, 56 | onClick = { selectedIndex = 1 } 57 | ) 58 | Spacer(modifier = Modifier.weight(1f, true)) 59 | NavigationBarItem( 60 | icon = { Icon(Icons.Default.Menu, contentDescription = "Tasks") }, 61 | label = { Text("Tasks") }, 62 | selected = selectedIndex == 2, 63 | onClick = { selectedIndex = 2 } 64 | ) 65 | NavigationBarItem( 66 | icon = { Icon(Icons.Default.Person, contentDescription = "Profile") }, 67 | label = { Text("Profile") }, 68 | selected = selectedIndex == 3, 69 | onClick = { selectedIndex = 3 } 70 | ) 71 | 72 | } 73 | }, 74 | content = { padding -> 75 | Column( 76 | modifier = Modifier 77 | .padding(padding) 78 | .padding(16.dp) 79 | .fillMaxSize() 80 | .verticalScroll(rememberScrollState()) 81 | ) { 82 | // Header 83 | Spacer(modifier = Modifier.height(40.dp)) 84 | Row( 85 | modifier = Modifier.fillMaxWidth().padding(start = 20.dp).horizontalScroll(rememberScrollState()), 86 | horizontalArrangement = Arrangement.SpaceBetween, 87 | verticalAlignment = Alignment.CenterVertically 88 | ) { 89 | Column { 90 | Text("Hi Samantha", fontSize = 24.sp, fontWeight = FontWeight.Bold) 91 | Text("Here are your projects", color = Color.Gray) 92 | } 93 | Icon( 94 | imageVector = Icons.Default.Person, 95 | contentDescription = "Avatar", 96 | modifier = Modifier.size(48.dp) 97 | ) 98 | } 99 | 100 | Spacer(modifier = Modifier.height(50.dp)) 101 | Row (){ 102 | Card ( 103 | modifier = Modifier.width(150.dp).height(250.dp), 104 | elevation = CardDefaults.cardElevation(10.dp), 105 | colors = CardDefaults.cardColors(blue) 106 | ){ 107 | Column ( 108 | modifier = Modifier.fillMaxSize(), 109 | horizontalAlignment = Alignment.CenterHorizontally, 110 | verticalArrangement = Arrangement.Center, 111 | ){ 112 | Image( 113 | painter = painterResource(R.drawable.img_15), 114 | contentDescription = "home", 115 | modifier = Modifier.size(100.dp).clip(shape = RoundedCornerShape(10.dp)), 116 | ) 117 | Text( 118 | text = "Contact" 119 | ) 120 | } 121 | } 122 | Spacer(modifier = Modifier.width(19.dp)) 123 | Card ( 124 | modifier = Modifier.width(150.dp).height(250.dp), 125 | elevation = CardDefaults.cardElevation(10.dp), 126 | colors = CardDefaults.cardColors(orange) 127 | ){ 128 | Column ( 129 | modifier = Modifier.fillMaxSize(), 130 | horizontalAlignment = Alignment.CenterHorizontally, 131 | verticalArrangement = Arrangement.Center, 132 | ){ 133 | Image( 134 | painter = painterResource(R.drawable.img_16), 135 | contentDescription = "home", 136 | modifier = Modifier.size(100.dp).clip(shape = RoundedCornerShape(10.dp)), 137 | ) 138 | Text( 139 | text = "Contact" 140 | ) 141 | } 142 | } 143 | Spacer(modifier = Modifier.width(19.dp)) 144 | Card ( 145 | modifier = Modifier.width(150.dp).height(250.dp), 146 | elevation = CardDefaults.cardElevation(10.dp), 147 | colors = CardDefaults.cardColors(green) 148 | ){ 149 | Column ( 150 | modifier = Modifier.fillMaxSize().horizontalScroll(rememberScrollState()), 151 | horizontalAlignment = Alignment.CenterHorizontally, 152 | verticalArrangement = Arrangement.Center, 153 | ){ 154 | Image( 155 | painter = painterResource(R.drawable.img_12), 156 | contentDescription = "home", 157 | modifier = Modifier.size(100.dp).clip(shape = RoundedCornerShape(10.dp)), 158 | ) 159 | Text( 160 | text = "Contact" 161 | ) 162 | } 163 | } 164 | } 165 | 166 | 167 | 168 | Spacer(modifier = Modifier.height(24.dp)) 169 | Text("Personal Tasks", fontSize = 18.sp, fontWeight = FontWeight.SemiBold) 170 | Spacer(modifier = Modifier.height(12.dp)) 171 | 172 | PersonalTaskCard( 173 | title = "NDA Review for website project", 174 | time = "Today • 10pm", 175 | icon = Icons.Default.Done, 176 | iconBg = Color(0xFFFDD835) 177 | ) 178 | Spacer(modifier = Modifier.height(8.dp)) 179 | PersonalTaskCard( 180 | title = "Email Reply for Green Project", 181 | time = "Today • 10pm", 182 | icon = Icons.Default.Email, 183 | iconBg = Color(0xFF29B6F6) 184 | ) 185 | } 186 | } 187 | ) 188 | } 189 | 190 | @Composable 191 | fun ProjectCard(title: String, backgroundColor: Color, icon: ImageVector) { 192 | Card( 193 | modifier = Modifier 194 | .size(width = 180.dp, height = 120.dp), 195 | shape = RoundedCornerShape(16.dp), 196 | colors = CardDefaults.cardColors(containerColor = backgroundColor) 197 | ) { 198 | Column( 199 | modifier = Modifier 200 | .padding(12.dp), 201 | verticalArrangement = Arrangement.SpaceBetween 202 | ) { 203 | Icon(icon, contentDescription = null, tint = Color.White) 204 | Text(title, color = Color.White, fontWeight = FontWeight.Bold) 205 | Text("1.2 tasks", color = Color.White.copy(alpha = 0.7f), fontSize = 12.sp) 206 | } 207 | } 208 | } 209 | 210 | @Composable 211 | fun PersonalTaskCard(title: String, time: String, icon: ImageVector, iconBg: Color) { 212 | Card( 213 | modifier = Modifier.fillMaxWidth(), 214 | shape = RoundedCornerShape(12.dp), 215 | elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) 216 | ) { 217 | Row( 218 | modifier = Modifier 219 | .padding(12.dp), 220 | verticalAlignment = Alignment.CenterVertically 221 | ) { 222 | Box( 223 | modifier = Modifier 224 | .size(36.dp) 225 | .background(iconBg, shape = CircleShape), 226 | contentAlignment = Alignment.Center 227 | ) { 228 | Icon(icon, contentDescription = null, tint = Color.White) 229 | } 230 | Spacer(modifier = Modifier.width(12.dp)) 231 | Column { 232 | Text(title, fontWeight = FontWeight.Bold) 233 | Text(time, fontSize = 12.sp, color = Color.Gray) 234 | } 235 | } 236 | } 237 | } 238 | 239 | @Preview(showBackground = true) 240 | @Composable 241 | fun AboutScreenPreview() { 242 | AboutScreen(navController = rememberNavController()) 243 | } 244 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/paylink/createlink.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.paylink 2 | 3 | import androidx.compose.foundation.layout.* 4 | import androidx.compose.foundation.text.KeyboardOptions 5 | import androidx.compose.material3.* 6 | import androidx.compose.runtime.* 7 | import androidx.compose.ui.Modifier 8 | import androidx.compose.ui.graphics.Color 9 | import androidx.compose.ui.text.input.KeyboardType 10 | import androidx.compose.ui.unit.dp 11 | import androidx.compose.ui.unit.sp 12 | import androidx.navigation.NavController 13 | import androidx.compose.ui.tooling.preview.Preview 14 | 15 | @Composable 16 | fun CreateLinkScreen(navController: NavController? = null) { 17 | var recipient by remember { mutableStateOf("") } 18 | var description by remember { mutableStateOf("") } 19 | var amount by remember { mutableStateOf("") } 20 | 21 | Column( 22 | modifier = Modifier 23 | .fillMaxSize() 24 | .padding(24.dp), 25 | verticalArrangement = Arrangement.spacedBy(20.dp) 26 | ) { 27 | Text( 28 | text = "Create Payment Link", 29 | style = MaterialTheme.typography.headlineSmall, 30 | color = MaterialTheme.colorScheme.primary 31 | ) 32 | 33 | OutlinedTextField( 34 | value = recipient, 35 | onValueChange = { recipient = it }, 36 | label = { Text("Recipient Name") }, 37 | modifier = Modifier.fillMaxWidth() 38 | ) 39 | 40 | OutlinedTextField( 41 | value = description, 42 | onValueChange = { description = it }, 43 | label = { Text("Description") }, 44 | modifier = Modifier.fillMaxWidth() 45 | ) 46 | 47 | OutlinedTextField( 48 | value = amount, 49 | onValueChange = { amount = it }, 50 | label = { Text("Amount") }, 51 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), 52 | modifier = Modifier.fillMaxWidth() 53 | ) 54 | 55 | Button( 56 | onClick = { 57 | // You'd call your backend API here to create the link 58 | // Example: viewModel.createLink(...) 59 | }, 60 | modifier = Modifier.fillMaxWidth(), 61 | colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF00796B)) 62 | ) { 63 | Text("Generate Link", fontSize = 18.sp) 64 | } 65 | } 66 | } 67 | 68 | @Preview(showBackground = true) 69 | @Composable 70 | fun CreateLinkScreenPreview() { 71 | CreateLinkScreen() 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/paylink/linkpreview.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.paylink 2 | 3 | import android.content.Intent 4 | import android.net.Uri 5 | import androidx.compose.foundation.clickable 6 | import androidx.compose.foundation.layout.* 7 | import androidx.compose.material.icons.Icons 8 | import androidx.compose.material.icons.filled.CheckCircle 9 | import androidx.compose.material.icons.filled.Home 10 | import androidx.compose.material.icons.filled.Share 11 | import androidx.compose.material3.* 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.platform.LocalContext 17 | import androidx.compose.ui.text.style.TextDecoration 18 | import androidx.compose.ui.tooling.preview.Preview 19 | import androidx.compose.ui.unit.dp 20 | import androidx.compose.ui.unit.sp 21 | import androidx.navigation.NavController 22 | import androidx.navigation.compose.rememberNavController 23 | 24 | @Composable 25 | fun LinkSuccessScreen( 26 | navController: NavController, 27 | recipientName: String, 28 | description: String, 29 | amount: String, 30 | linkUrl: String 31 | ) { 32 | val context = LocalContext.current 33 | 34 | Column( 35 | modifier = Modifier 36 | .fillMaxSize() 37 | .padding(24.dp), 38 | verticalArrangement = Arrangement.Center, 39 | horizontalAlignment = Alignment.CenterHorizontally 40 | ) { 41 | Icon( 42 | imageVector = Icons.Default.CheckCircle, 43 | contentDescription = "Success", 44 | tint = Color(0xFF4CAF50), 45 | modifier = Modifier.size(80.dp) 46 | ) 47 | 48 | Spacer(modifier = Modifier.height(16.dp)) 49 | 50 | Text( 51 | text = "Link Created Successfully!", 52 | fontSize = 22.sp, 53 | style = MaterialTheme.typography.headlineSmall 54 | ) 55 | 56 | Spacer(modifier = Modifier.height(16.dp)) 57 | 58 | Card( 59 | modifier = Modifier.fillMaxWidth(), 60 | colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primaryContainer) 61 | ) { 62 | Column(modifier = Modifier.padding(16.dp)) { 63 | Text("Recipient: $recipientName", fontSize = 16.sp) 64 | Text("Description: $description", fontSize = 16.sp) 65 | Text("Amount: $amount", fontSize = 16.sp) 66 | 67 | Spacer(modifier = Modifier.height(8.dp)) 68 | 69 | Text( 70 | text = linkUrl, 71 | color = MaterialTheme.colorScheme.primary, 72 | textDecoration = TextDecoration.Underline, 73 | modifier = Modifier.clickable { 74 | val intent = Intent(Intent.ACTION_VIEW, Uri.parse(linkUrl)) 75 | context.startActivity(intent) 76 | } 77 | ) 78 | } 79 | } 80 | 81 | Spacer(modifier = Modifier.height(24.dp)) 82 | 83 | Button( 84 | onClick = { 85 | // TODO: Add share functionality 86 | }, 87 | modifier = Modifier.fillMaxWidth() 88 | ) { 89 | Icon(Icons.Default.Share, contentDescription = null) 90 | Spacer(modifier = Modifier.width(8.dp)) 91 | Text("Share Link") 92 | } 93 | 94 | Spacer(modifier = Modifier.height(12.dp)) 95 | 96 | OutlinedButton( 97 | onClick = { 98 | // navController.navigate("home") or popBackStack 99 | }, 100 | modifier = Modifier.fillMaxWidth() 101 | ) { 102 | Icon(Icons.Default.Home, contentDescription = null) 103 | Spacer(modifier = Modifier.width(8.dp)) 104 | Text("Back to Home") 105 | } 106 | } 107 | } 108 | 109 | @Preview(showBackground = true) 110 | @Composable 111 | fun LinkSuccessScreenPreview() { 112 | MaterialTheme { 113 | LinkSuccessScreen( 114 | navController = rememberNavController(), 115 | recipientName = "John Doe", 116 | description = "For groceries", 117 | amount = "$25.00", 118 | linkUrl = "https://paylink.app/pay/abc123" 119 | ) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/paylinkauthentication/signin.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.paylinkauthentication 2 | 3 | import androidx.compose.foundation.layout.* 4 | import androidx.compose.foundation.text.KeyboardOptions 5 | import androidx.compose.material3.* 6 | import androidx.compose.runtime.* 7 | import androidx.compose.ui.Alignment 8 | import androidx.compose.ui.Modifier 9 | import androidx.compose.ui.text.input.KeyboardType 10 | import androidx.compose.ui.text.input.PasswordVisualTransformation 11 | import androidx.compose.ui.tooling.preview.Preview 12 | import androidx.compose.ui.unit.dp 13 | import androidx.navigation.NavController 14 | import androidx.navigation.compose.rememberNavController 15 | 16 | @Composable 17 | fun SignInScreen( 18 | navController: NavController 19 | ) { 20 | var email by remember { mutableStateOf("") } 21 | var password by remember { mutableStateOf("") } 22 | 23 | Column( 24 | modifier = Modifier 25 | .fillMaxSize() 26 | .padding(24.dp), 27 | verticalArrangement = Arrangement.Center 28 | ) { 29 | Text("Welcome Back!", style = MaterialTheme.typography.headlineSmall) 30 | Spacer(modifier = Modifier.height(24.dp)) 31 | 32 | OutlinedTextField( 33 | value = email, 34 | onValueChange = { email = it }, 35 | label = { Text("Email") }, 36 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email), 37 | modifier = Modifier.fillMaxWidth() 38 | ) 39 | 40 | Spacer(modifier = Modifier.height(12.dp)) 41 | 42 | OutlinedTextField( 43 | value = password, 44 | onValueChange = { password = it }, 45 | label = { Text("Password") }, 46 | visualTransformation = PasswordVisualTransformation(), 47 | modifier = Modifier.fillMaxWidth() 48 | ) 49 | 50 | Spacer(modifier = Modifier.height(24.dp)) 51 | 52 | Button( 53 | onClick = { 54 | // TODO: Call Sign In API 55 | }, 56 | modifier = Modifier.fillMaxWidth() 57 | ) { 58 | Text("Sign In") 59 | } 60 | 61 | Spacer(modifier = Modifier.height(12.dp)) 62 | 63 | TextButton( 64 | onClick = { 65 | // TODO: Navigate to SignUpScreen 66 | }, 67 | modifier = Modifier.align(Alignment.CenterHorizontally) 68 | ) { 69 | Text("Don't have an account? Sign Up") 70 | } 71 | } 72 | } 73 | 74 | @Preview(showBackground = true) 75 | @Composable 76 | fun SignInScreenPreview() { 77 | MaterialTheme { 78 | SignInScreen(navController = rememberNavController()) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/paylinkauthentication/signup.kt: -------------------------------------------------------------------------------- 1 | import androidx.compose.foundation.layout.* 2 | import androidx.compose.foundation.text.KeyboardOptions 3 | import androidx.compose.material3.* 4 | import androidx.compose.runtime.* 5 | import androidx.compose.ui.Alignment 6 | import androidx.compose.ui.Modifier 7 | import androidx.compose.ui.text.input.KeyboardType 8 | import androidx.compose.ui.text.input.PasswordVisualTransformation 9 | import androidx.compose.ui.tooling.preview.Preview 10 | import androidx.compose.ui.unit.dp 11 | import androidx.navigation.NavController 12 | import androidx.navigation.compose.rememberNavController 13 | 14 | @Composable 15 | fun SignUpScreen(navController: NavController) { 16 | var username by remember { mutableStateOf("") } 17 | var email by remember { mutableStateOf("") } 18 | var password by remember { mutableStateOf("") } 19 | var businessName by remember { mutableStateOf("") } 20 | var businessDesc by remember { mutableStateOf("") } 21 | 22 | Column( 23 | modifier = Modifier 24 | .fillMaxSize() 25 | .padding(24.dp), 26 | verticalArrangement = Arrangement.Center 27 | ) { 28 | Text("Create Account", style = MaterialTheme.typography.headlineSmall) 29 | Spacer(modifier = Modifier.height(24.dp)) 30 | 31 | OutlinedTextField( 32 | value = username, 33 | onValueChange = { username = it }, 34 | label = { Text("Username") }, 35 | modifier = Modifier.fillMaxWidth() 36 | ) 37 | 38 | Spacer(modifier = Modifier.height(12.dp)) 39 | 40 | OutlinedTextField( 41 | value = email, 42 | onValueChange = { email = it }, 43 | label = { Text("Email") }, 44 | keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email), 45 | modifier = Modifier.fillMaxWidth() 46 | ) 47 | 48 | Spacer(modifier = Modifier.height(12.dp)) 49 | 50 | OutlinedTextField( 51 | value = password, 52 | onValueChange = { password = it }, 53 | label = { Text("Password") }, 54 | visualTransformation = PasswordVisualTransformation(), 55 | modifier = Modifier.fillMaxWidth() 56 | ) 57 | 58 | Spacer(modifier = Modifier.height(24.dp)) 59 | 60 | Text( 61 | text = "Register Your Business", 62 | style = MaterialTheme.typography.titleMedium, 63 | modifier = Modifier.padding(bottom = 8.dp) 64 | ) 65 | 66 | OutlinedTextField( 67 | value = businessName, 68 | onValueChange = { businessName = it }, 69 | label = { Text("Business Name") }, 70 | modifier = Modifier.fillMaxWidth() 71 | ) 72 | 73 | Spacer(modifier = Modifier.height(12.dp)) 74 | 75 | OutlinedTextField( 76 | value = businessDesc, 77 | onValueChange = { businessDesc = it }, 78 | label = { Text("Business Description") }, 79 | modifier = Modifier.fillMaxWidth() 80 | ) 81 | 82 | Spacer(modifier = Modifier.height(24.dp)) 83 | 84 | Button( 85 | onClick = { 86 | // TODO: Submit all fields to backend 87 | }, 88 | modifier = Modifier.fillMaxWidth() 89 | ) { 90 | Text("Sign Up & Register Business") 91 | } 92 | 93 | Spacer(modifier = Modifier.height(12.dp)) 94 | 95 | TextButton( 96 | onClick = { 97 | // TODO: Navigate to SignInScreen 98 | }, 99 | modifier = Modifier.align(Alignment.CenterHorizontally) 100 | ) { 101 | Text("Already have an account? Sign In") 102 | } 103 | } 104 | } 105 | 106 | @Preview(showBackground = true) 107 | @Composable 108 | fun SignUpScreenPreview() { 109 | MaterialTheme { 110 | SignUpScreen(navController = rememberNavController()) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/paylinkcommunity/communityscreen.kt: -------------------------------------------------------------------------------- 1 | import androidx.compose.foundation.Image 2 | import androidx.compose.foundation.clickable 3 | import androidx.compose.foundation.layout.* 4 | import androidx.compose.foundation.lazy.LazyColumn 5 | import androidx.compose.foundation.lazy.items 6 | import androidx.compose.foundation.shape.CircleShape 7 | import androidx.compose.material.icons.Icons 8 | import androidx.compose.material.icons.filled.Add 9 | import androidx.compose.material.icons.filled.Face 10 | import androidx.compose.material.icons.filled.Home 11 | import androidx.compose.material.icons.filled.Person 12 | import androidx.compose.material.icons.outlined.Share 13 | import androidx.compose.material3.* 14 | import androidx.compose.runtime.Composable 15 | import androidx.compose.runtime.remember 16 | import androidx.compose.ui.Alignment 17 | import androidx.compose.ui.Modifier 18 | import androidx.compose.ui.draw.clip 19 | import androidx.compose.ui.graphics.Color 20 | import androidx.compose.ui.unit.dp 21 | import androidx.compose.ui.unit.sp 22 | import androidx.navigation.NavController 23 | import androidx.navigation.compose.rememberNavController 24 | import androidx.compose.ui.text.font.FontWeight 25 | import androidx.compose.ui.tooling.preview.Preview 26 | 27 | data class Community(val id: String, val name: String) 28 | 29 | @Composable 30 | fun YourCommunitiesScreen(navController: NavController, username: String = "Username", communities: List) { 31 | Scaffold( 32 | bottomBar = { 33 | BottomNavBar() 34 | }, 35 | containerColor = Color(0xFFF8F8F8) 36 | ) { padding -> 37 | Column( 38 | modifier = Modifier 39 | .padding(padding) 40 | .padding(16.dp) 41 | .fillMaxSize() 42 | ) { 43 | // Header 44 | Row( 45 | modifier = Modifier.fillMaxWidth(), 46 | verticalAlignment = Alignment.CenterVertically, 47 | horizontalArrangement = Arrangement.SpaceBetween 48 | ) { 49 | Row(verticalAlignment = Alignment.CenterVertically) { 50 | Surface( 51 | modifier = Modifier 52 | .size(48.dp) 53 | .clip(CircleShape), 54 | color = Color(0xFFDDDDDD) 55 | ) { 56 | // Placeholder for profile picture 57 | Icon( 58 | imageVector = Icons.Default.Person, 59 | contentDescription = "Profile", 60 | modifier = Modifier.padding(8.dp) 61 | ) 62 | } 63 | Spacer(modifier = Modifier.width(12.dp)) 64 | Column { 65 | Text("Hi there", fontSize = 14.sp, color = Color.Gray) 66 | Text(username, fontSize = 18.sp, fontWeight = FontWeight.SemiBold) 67 | } 68 | } 69 | IconButton(onClick = { /* Share action */ }) { 70 | Icon(Icons.Outlined.Share, contentDescription = "Share") 71 | } 72 | } 73 | 74 | Spacer(modifier = Modifier.height(24.dp)) 75 | 76 | // Title 77 | Text("Your Communities", fontSize = 20.sp, fontWeight = FontWeight.Bold) 78 | 79 | Spacer(modifier = Modifier.height(12.dp)) 80 | 81 | // Community List 82 | LazyColumn { 83 | items(communities) { community -> 84 | CommunityCard(community = community) { 85 | // navController.navigate("community/${community.id}") 86 | } 87 | Spacer(modifier = Modifier.height(12.dp)) 88 | } 89 | } 90 | } 91 | } 92 | } 93 | 94 | @Composable 95 | fun CommunityCard(community: Community, onClick: () -> Unit) { 96 | Card( 97 | modifier = Modifier 98 | .fillMaxWidth() 99 | .clickable { onClick() }, 100 | colors = CardDefaults.cardColors(containerColor = Color.White), 101 | elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) 102 | ) { 103 | Row( 104 | verticalAlignment = Alignment.CenterVertically, 105 | modifier = Modifier.padding(16.dp) 106 | ) { 107 | Surface( 108 | modifier = Modifier 109 | .size(40.dp) 110 | .clip(CircleShape), 111 | color = Color(0xFFDDDDDD) 112 | ) { 113 | Icon(Icons.Default.Person, contentDescription = null, modifier = Modifier.padding(8.dp)) 114 | } 115 | Spacer(modifier = Modifier.width(16.dp)) 116 | Text(community.name, fontSize = 16.sp, fontWeight = FontWeight.Medium) 117 | } 118 | } 119 | } 120 | 121 | @Composable 122 | fun BottomNavBar() { 123 | NavigationBar { 124 | NavigationBarItem( 125 | icon = { Icon(Icons.Default.Home, contentDescription = "Home") }, 126 | selected = true, 127 | onClick = { /* Already on Home */ } 128 | ) 129 | NavigationBarItem( 130 | icon = { Icon(Icons.Default.Add, contentDescription = "Add") }, 131 | selected = false, 132 | onClick = { /* Add new link */ } 133 | ) 134 | NavigationBarItem( 135 | icon = { Icon(Icons.Default.Person, contentDescription = "Communities") }, 136 | selected = false, 137 | onClick = { /* Navigate to Communities */ } 138 | ) 139 | NavigationBarItem( 140 | icon = { Icon(Icons.Default.Face, contentDescription = "Profile") }, 141 | selected = false, 142 | onClick = { /* Navigate to Profile */ } 143 | ) 144 | } 145 | } 146 | 147 | @Preview(showBackground = true) 148 | @Composable 149 | fun YourCommunitiesScreenPreview() { 150 | val navController = rememberNavController() 151 | val demoCommunities = listOf( 152 | Community("1", "Community 1"), 153 | Community("2", "Community 2") 154 | ) 155 | YourCommunitiesScreen(navController = navController, communities = demoCommunities) 156 | } 157 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/paylinkhome/PHome.kt: -------------------------------------------------------------------------------- 1 | import androidx.compose.foundation.layout.* 2 | import androidx.compose.foundation.shape.RoundedCornerShape 3 | import androidx.compose.material.icons.Icons 4 | import androidx.compose.material.icons.filled.* 5 | import androidx.compose.material3.* 6 | import androidx.compose.runtime.Composable 7 | import androidx.compose.ui.Alignment 8 | import androidx.compose.ui.Modifier 9 | import androidx.compose.ui.text.font.FontWeight 10 | import androidx.compose.ui.tooling.preview.Preview 11 | import androidx.compose.ui.unit.dp 12 | import androidx.navigation.NavController 13 | import androidx.navigation.compose.rememberNavController 14 | 15 | @Composable 16 | fun PHome(navController: NavController) { 17 | Column(modifier = Modifier.fillMaxSize().padding(30.dp)) { 18 | 19 | // Top bar with profile and share icon 20 | Row( 21 | modifier = Modifier.fillMaxWidth(), 22 | horizontalArrangement = Arrangement.SpaceBetween, 23 | verticalAlignment = Alignment.CenterVertically 24 | ) { 25 | Row(verticalAlignment = Alignment.CenterVertically) { 26 | Icon(Icons.Default.AccountCircle, contentDescription = "Profile", modifier = Modifier.size(40.dp)) 27 | Spacer(modifier = Modifier.width(8.dp)) 28 | Column { 29 | Text("Hi there", style = MaterialTheme.typography.bodyMedium) 30 | Text("", fontWeight = FontWeight.Bold) 31 | } 32 | } 33 | Icon(Icons.Default.Share, contentDescription = "Share") 34 | } 35 | 36 | Spacer(modifier = Modifier.height(16.dp)) 37 | Text("Ready to manage your links today?", style = MaterialTheme.typography.bodyLarge) 38 | 39 | Spacer(modifier = Modifier.height(16.dp)) 40 | 41 | // Navigation buttons 42 | Button( 43 | onClick = { /* nav to Create Link */ }, 44 | modifier = Modifier.fillMaxWidth(), 45 | shape = RoundedCornerShape(8.dp) 46 | ) { 47 | Icon(Icons.Default.Create, contentDescription = null) 48 | Spacer(modifier = Modifier.width(8.dp)) 49 | Text("Create Link") 50 | } 51 | 52 | Spacer(modifier = Modifier.height(8.dp)) 53 | Button( 54 | onClick = { /* nav to Your Communities */ }, 55 | modifier = Modifier.fillMaxWidth(), 56 | shape = RoundedCornerShape(8.dp) 57 | ) { 58 | Icon(Icons.Default.Person, contentDescription = null) 59 | Spacer(modifier = Modifier.width(8.dp)) 60 | Text("Your Communities") 61 | } 62 | 63 | Spacer(modifier = Modifier.height(8.dp)) 64 | Button( 65 | onClick = { /* nav to Payment History */ }, 66 | modifier = Modifier.fillMaxWidth(), 67 | shape = RoundedCornerShape(8.dp) 68 | ) { 69 | Icon(Icons.Default.Menu, contentDescription = null) 70 | Spacer(modifier = Modifier.width(8.dp)) 71 | Text("Payment History") 72 | } 73 | 74 | Spacer(modifier = Modifier.height(8.dp)) 75 | Button( 76 | onClick = { /* nav to User Profile */ }, 77 | modifier = Modifier.fillMaxWidth(), 78 | shape = RoundedCornerShape(8.dp) 79 | ) { 80 | Icon(Icons.Default.Person, contentDescription = null) 81 | Spacer(modifier = Modifier.width(8.dp)) 82 | Text("User Profile") 83 | } 84 | 85 | Spacer(modifier = Modifier.height(24.dp)) 86 | Text("Your Links", style = MaterialTheme.typography.titleMedium) 87 | 88 | // Filter buttons 89 | Row(modifier = Modifier.padding(vertical = 8.dp)) { 90 | Button(onClick = { /* Show All */ }, modifier = Modifier.padding(end = 8.dp)) { 91 | Text("All") 92 | } 93 | Button(onClick = { /* Show Pending */ }, modifier = Modifier.padding(end = 8.dp)) { 94 | Text("Pending") 95 | } 96 | Button(onClick = { /* Show Completed */ }) { 97 | Text("Completed") 98 | } 99 | } 100 | 101 | // List of Link Items 102 | LinkItem("Recipient 1", "Description of Link 1", "$10.00", "Apr 14") 103 | LinkItem("Recipient 2", "Description of Link 2", "$12.50", "Apr 13") 104 | LinkItem("Recipient 3", "Description of Link 3", "$20.00", "Apr 12") 105 | 106 | Spacer(modifier = Modifier.weight(1f)) 107 | 108 | // Bottom navigation 109 | NavigationBar { 110 | NavigationBarItem( 111 | icon = { Icon(Icons.Default.Home, contentDescription = "Home") }, 112 | selected = true, 113 | onClick = { /* Already on Home */ } 114 | ) 115 | NavigationBarItem( 116 | icon = { Icon(Icons.Default.Add, contentDescription = "Add") }, 117 | selected = false, 118 | onClick = { /* Add new link */ } 119 | ) 120 | NavigationBarItem( 121 | icon = { Icon(Icons.Default.Person, contentDescription = "Communities") }, 122 | selected = false, 123 | onClick = { /* Navigate to Communities */ } 124 | ) 125 | NavigationBarItem( 126 | icon = { Icon(Icons.Default.Face, contentDescription = "Profile") }, 127 | selected = false, 128 | onClick = { /* Navigate to Profile */ } 129 | ) 130 | } 131 | } 132 | } 133 | 134 | @Composable 135 | fun LinkItem(name: String, description: String, amount: String, dateCreated: String) { 136 | Card( 137 | modifier = Modifier 138 | .fillMaxWidth() 139 | .padding(vertical = 4.dp), 140 | elevation = CardDefaults.cardElevation(4.dp) 141 | ) { 142 | Column(modifier = Modifier.padding(16.dp)) { 143 | Text("Name of recipient: $name", fontWeight = FontWeight.Bold) 144 | Text("Description: $description") 145 | Text("Amount: $amount") 146 | Text("Date created: $dateCreated", style = MaterialTheme.typography.bodySmall) 147 | } 148 | } 149 | } 150 | 151 | @Preview(showBackground = true) 152 | @Composable 153 | fun PHomePreview() { 154 | MaterialTheme { 155 | PHome(navController = rememberNavController()) 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/paylinkhome/scaffold.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.paylinkhome 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/paylinkhome/splash.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.paylinkhome 2 | 3 | import androidx.compose.foundation.layout.* 4 | import androidx.compose.material.icons.Icons 5 | import androidx.compose.material.icons.filled.ThumbUp 6 | import androidx.compose.material3.* 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.runtime.LaunchedEffect 9 | import androidx.compose.ui.Alignment 10 | import androidx.compose.ui.Modifier 11 | import androidx.compose.ui.graphics.Color 12 | import androidx.compose.ui.tooling.preview.Preview 13 | import androidx.compose.ui.unit.dp 14 | import androidx.compose.ui.unit.sp 15 | import androidx.navigation.NavController 16 | import androidx.navigation.compose.rememberNavController 17 | import kotlinx.coroutines.delay 18 | 19 | @Composable 20 | fun SplashScreen(navController: NavController) { 21 | // Navigate to SignIn after 2 seconds (you can later check auth state here) 22 | LaunchedEffect(Unit) { 23 | delay(2000) 24 | navController.navigate("sign_in") { 25 | popUpTo("splash") { inclusive = true } // clear backstack 26 | } 27 | } 28 | 29 | Surface( 30 | modifier = Modifier.fillMaxSize(), 31 | color = MaterialTheme.colorScheme.primaryContainer 32 | ) { 33 | Column( 34 | modifier = Modifier.fillMaxSize().padding(32.dp), 35 | verticalArrangement = Arrangement.Center, 36 | horizontalAlignment = Alignment.CenterHorizontally 37 | ) { 38 | Icon( 39 | imageVector = Icons.Default.ThumbUp, 40 | contentDescription = "App Logo", 41 | tint = Color(0xFF4CAF50), 42 | modifier = Modifier.size(80.dp) 43 | ) 44 | 45 | Spacer(modifier = Modifier.height(16.dp)) 46 | 47 | Text( 48 | text = "Paylink", 49 | style = MaterialTheme.typography.headlineLarge.copy(fontSize = 32.sp) 50 | ) 51 | } 52 | } 53 | } 54 | 55 | @Preview(showBackground = true) 56 | @Composable 57 | fun SplashScreenPreview() { 58 | MaterialTheme { 59 | SplashScreen(navController = rememberNavController()) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/paylinkprofile/Profile.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.paylinkprofile 2 | 3 | import androidx.compose.foundation.background 4 | import androidx.compose.foundation.layout.Arrangement 5 | import androidx.compose.foundation.layout.Box 6 | import androidx.compose.foundation.layout.Column 7 | import androidx.compose.foundation.layout.Row 8 | import androidx.compose.foundation.layout.Spacer 9 | import androidx.compose.foundation.layout.fillMaxSize 10 | import androidx.compose.foundation.layout.fillMaxWidth 11 | import androidx.compose.foundation.layout.height 12 | import androidx.compose.foundation.layout.padding 13 | import androidx.compose.foundation.layout.size 14 | import androidx.compose.foundation.layout.width 15 | import androidx.compose.foundation.shape.CircleShape 16 | import androidx.compose.foundation.shape.RoundedCornerShape 17 | import androidx.compose.material.icons.Icons 18 | import androidx.compose.material.icons.filled.ArrowBack 19 | import androidx.compose.material.icons.filled.ExitToApp 20 | import androidx.compose.material.icons.filled.Home 21 | import androidx.compose.material.icons.filled.Settings 22 | import androidx.compose.material3.Button 23 | import androidx.compose.material3.ButtonDefaults 24 | import androidx.compose.material3.Icon 25 | import androidx.compose.material3.IconButton 26 | import androidx.compose.material3.MaterialTheme 27 | import androidx.compose.material3.Text 28 | import androidx.compose.runtime.Composable 29 | import androidx.compose.ui.Alignment 30 | import androidx.compose.ui.Modifier 31 | import androidx.compose.ui.text.font.FontWeight 32 | import androidx.compose.ui.text.style.TextAlign 33 | import androidx.compose.ui.tooling.preview.Preview 34 | import androidx.compose.ui.unit.dp 35 | import androidx.compose.ui.unit.sp 36 | import androidx.navigation.NavController 37 | import androidx.navigation.compose.rememberNavController 38 | import com.harry.sokomart.ui.theme.gray 39 | import com.harry.sokomart.ui.theme.white 40 | 41 | @Composable 42 | fun ProfileScreen(navController: NavController) { 43 | Column(modifier = Modifier 44 | .fillMaxSize() 45 | .padding(16.dp)) { 46 | 47 | // Top bar 48 | Row( 49 | modifier = Modifier.fillMaxWidth(), 50 | horizontalArrangement = Arrangement.SpaceBetween, 51 | verticalAlignment = Alignment.CenterVertically 52 | ) { 53 | IconButton(onClick = { navController.popBackStack() }) { 54 | Icon(Icons.Default.ArrowBack, contentDescription = "Back") 55 | } 56 | Text( 57 | "Profile", 58 | ) 59 | IconButton(onClick = { /* Settings */ }) { 60 | Icon(Icons.Default.Settings, contentDescription = "Settings") 61 | } 62 | } 63 | 64 | Spacer(modifier = Modifier.height(16.dp)) 65 | 66 | // Profile image 67 | Box( 68 | modifier = Modifier 69 | .size(100.dp) 70 | .align(Alignment.CenterHorizontally) 71 | .background(gray, CircleShape) 72 | ) 73 | 74 | Spacer(modifier = Modifier.height(16.dp)) 75 | 76 | // User info 77 | Column( 78 | horizontalAlignment = Alignment.CenterHorizontally, 79 | verticalArrangement = Arrangement.Center 80 | ) { 81 | Text("Username", style = MaterialTheme.typography.bodyMedium) 82 | Text("Business Name", style = MaterialTheme.typography.bodyMedium) 83 | Text("email@example.com", style = MaterialTheme.typography.bodyMedium) 84 | Text("+1234567890", style = MaterialTheme.typography.bodyMedium) 85 | } 86 | 87 | Spacer(modifier = Modifier.height(30.dp)) 88 | 89 | // Stats row 90 | Spacer(modifier = Modifier.width(100.dp)) 91 | Row( 92 | modifier = Modifier.fillMaxWidth(), 93 | horizontalArrangement = Arrangement.SpaceEvenly 94 | ) { 95 | StatItem("5", "Links Created") 96 | StatItem("2", "Pending") 97 | StatItem("3", "Completed") 98 | StatItem("2", "Communities\nJoined") 99 | } 100 | 101 | Spacer(modifier = Modifier.height(24.dp)) 102 | 103 | // Navigation buttons 104 | Button( 105 | onClick = { navController.navigate("home") }, 106 | modifier = Modifier.fillMaxWidth() 107 | ) { 108 | Icon(Icons.Default.Home, contentDescription = null) 109 | Spacer(Modifier.width(8.dp)) 110 | Text("Home Screen") 111 | } 112 | 113 | Spacer(modifier = Modifier.height(16.dp)) 114 | 115 | Button( 116 | onClick = { /* Handle logout */ }, 117 | modifier = Modifier.fillMaxWidth(), 118 | colors = ButtonDefaults.buttonColors() 119 | ) { 120 | Icon(Icons.Default.ExitToApp, contentDescription = null) 121 | Spacer(Modifier.width(8.dp)) 122 | Text(text = "Log Out", color = white) 123 | } 124 | } 125 | } 126 | 127 | @Composable 128 | fun StatItem(value: String, label: String) { 129 | Column(horizontalAlignment = Alignment.CenterHorizontally) { 130 | Box( 131 | modifier = Modifier 132 | .size(40.dp) 133 | .background(MaterialTheme.colorScheme.primary, shape = RoundedCornerShape(8.dp)), 134 | contentAlignment = Alignment.Center 135 | ) { 136 | Text(value, color = white, fontWeight = FontWeight.Bold) 137 | } 138 | Spacer(modifier = Modifier.height(4.dp)) 139 | Text(label, textAlign = TextAlign.Center, fontSize = 12.sp) 140 | } 141 | } 142 | 143 | @Preview(showBackground = true) 144 | @Composable 145 | fun ProfilePreview() { 146 | ProfileScreen(navController = rememberNavController()) 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/products/AddProductScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.products 2 | 3 | 4 | import android.net.Uri 5 | import android.util.Log 6 | import androidx.activity.compose.rememberLauncherForActivityResult 7 | import androidx.activity.result.contract.ActivityResultContracts 8 | import androidx.compose.foundation.Image 9 | import androidx.compose.foundation.background 10 | import androidx.compose.foundation.clickable 11 | import androidx.compose.foundation.layout.* 12 | import androidx.compose.foundation.shape.RoundedCornerShape 13 | import androidx.compose.material.icons.Icons 14 | import androidx.compose.material.icons.filled.* 15 | import androidx.compose.material3.* 16 | import androidx.compose.runtime.* 17 | import androidx.compose.ui.Alignment 18 | import androidx.compose.ui.Modifier 19 | import androidx.compose.ui.graphics.Color 20 | import androidx.compose.ui.layout.ContentScale 21 | import androidx.compose.ui.platform.LocalContext 22 | import androidx.compose.ui.text.font.FontWeight 23 | import androidx.compose.ui.unit.dp 24 | import androidx.compose.ui.unit.sp 25 | import androidx.navigation.NavController 26 | import coil.compose.rememberAsyncImagePainter 27 | import com.harry.sokomart.navigation.ROUT_ADD_PRODUCT 28 | import com.harry.sokomart.navigation.ROUT_PRODUCT_LIST 29 | import com.harry.sokomart.viewmodel.ProductViewModel 30 | 31 | @OptIn(ExperimentalMaterial3Api::class) 32 | @Composable 33 | fun AddProductScreen(navController: NavController, viewModel: ProductViewModel) { 34 | var name by remember { mutableStateOf("") } 35 | var price by remember { mutableStateOf("") } 36 | var phone by remember { mutableStateOf("") } 37 | var imageUri by remember { mutableStateOf(null) } 38 | var showMenu by remember { mutableStateOf(false) } 39 | 40 | val context = LocalContext.current 41 | 42 | // Image Picker Launcher 43 | val imagePicker = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> 44 | uri?.let { 45 | imageUri = it 46 | Log.d("ImagePicker", "Selected image URI: $it") 47 | } 48 | } 49 | 50 | Scaffold( 51 | topBar = { 52 | TopAppBar( 53 | title = { Text("Add Product", fontSize = 20.sp, fontWeight = FontWeight.Bold) }, 54 | colors = TopAppBarDefaults.mediumTopAppBarColors(Color.LightGray), 55 | navigationIcon = { 56 | IconButton(onClick = { navController.popBackStack() }) { 57 | Icon(imageVector = Icons.Default.KeyboardArrowLeft, contentDescription = "Back") 58 | } 59 | }, 60 | actions = { 61 | IconButton(onClick = { showMenu = true }) { 62 | Icon(imageVector = Icons.Default.MoreVert, contentDescription = "Menu") 63 | } 64 | DropdownMenu( 65 | expanded = showMenu, 66 | onDismissRequest = { showMenu = false } 67 | ) { 68 | DropdownMenuItem( 69 | text = { Text("Product List") }, 70 | onClick = { 71 | navController.navigate(ROUT_PRODUCT_LIST) 72 | showMenu = false 73 | } 74 | ) 75 | DropdownMenuItem( 76 | text = { Text("Add Product") }, 77 | onClick = { 78 | navController.navigate(ROUT_ADD_PRODUCT) 79 | showMenu = false 80 | } 81 | ) 82 | } 83 | } 84 | ) 85 | }, 86 | bottomBar = { 87 | BottomNavigationBar(navController) 88 | }, 89 | content = { paddingValues -> 90 | Column( 91 | modifier = Modifier 92 | .fillMaxSize() 93 | .padding(paddingValues) 94 | .padding(16.dp), 95 | horizontalAlignment = Alignment.CenterHorizontally 96 | ) { 97 | // Product Name 98 | OutlinedTextField( 99 | value = name, 100 | onValueChange = { name = it }, 101 | label = { Text("Product Name") }, 102 | //leadingIcon = { Icon(painter = painterResource(R.drawable.product), contentDescription = "Name") }, 103 | modifier = Modifier.fillMaxWidth() 104 | ) 105 | 106 | Spacer(modifier = Modifier.height(10.dp)) 107 | 108 | // Product Price 109 | OutlinedTextField( 110 | value = price, 111 | onValueChange = { price = it }, 112 | label = { Text("Product Price") }, 113 | // leadingIcon = { Icon(painter = painterResource(R.drawable.price), contentDescription = "Price") }, 114 | modifier = Modifier.fillMaxWidth() 115 | ) 116 | 117 | 118 | 119 | Spacer(modifier = Modifier.height(10.dp)) 120 | 121 | // Phone Number 122 | OutlinedTextField( 123 | value = phone, 124 | onValueChange = { phone = it }, 125 | label = { Text("Phone Number") }, 126 | //leadingIcon = { Icon(painter = painterResource(R.drawable.phone), contentDescription = "Price") }, 127 | modifier = Modifier.fillMaxWidth() 128 | ) 129 | 130 | 131 | Spacer(modifier = Modifier.height(16.dp)) 132 | 133 | // Image Picker Box 134 | Box( 135 | modifier = Modifier 136 | .size(200.dp) 137 | .background(Color.LightGray, shape = RoundedCornerShape(10.dp)) 138 | .clickable { imagePicker.launch("image/*") }, 139 | contentAlignment = Alignment.Center 140 | ) { 141 | if (imageUri != null) { 142 | Image( 143 | painter = rememberAsyncImagePainter(model = imageUri), 144 | contentDescription = "Selected Image", 145 | modifier = Modifier.fillMaxSize(), 146 | contentScale = ContentScale.Crop 147 | ) 148 | } else { 149 | Column(horizontalAlignment = Alignment.CenterHorizontally) { 150 | //Icon(painter = painterResource(R.drawable.image), contentDescription = "Pick Image") 151 | Text("Tap to pick image", color = Color.DarkGray) 152 | } 153 | } 154 | } 155 | 156 | Spacer(modifier = Modifier.height(20.dp)) 157 | 158 | // Add Product Button 159 | Button( 160 | onClick = { 161 | val priceValue = price.toDoubleOrNull() 162 | if (priceValue != null) { 163 | imageUri?.toString()?.let { viewModel.addProduct(name, priceValue, phone,it) } 164 | navController.popBackStack() 165 | } 166 | }, 167 | modifier = Modifier.fillMaxWidth(), 168 | shape = RoundedCornerShape(8.dp), 169 | colors = ButtonDefaults.buttonColors(Color.LightGray) 170 | ) { 171 | Text("Add Product", fontSize = 18.sp, fontWeight = FontWeight.Bold) 172 | } 173 | } 174 | } 175 | ) 176 | } 177 | 178 | // Bottom Navigation Bar Component 179 | @Composable 180 | fun BottomNavigationBar(navController: NavController) { 181 | NavigationBar( 182 | containerColor = Color(0xFF6F6A72), 183 | contentColor = Color.White 184 | ) { 185 | NavigationBarItem( 186 | selected = false, 187 | onClick = { navController.navigate(ROUT_PRODUCT_LIST) }, 188 | icon = { Icon(Icons.Default.Home, contentDescription = "Product List") }, 189 | label = { Text("Home") } 190 | ) 191 | NavigationBarItem( 192 | selected = false, 193 | onClick = { navController.navigate(ROUT_ADD_PRODUCT) }, 194 | icon = { Icon(Icons.Default.AddCircle, contentDescription = "Add Product") }, 195 | label = { Text("Add") } 196 | ) 197 | 198 | 199 | 200 | } 201 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/products/EditProductScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.products 2 | 3 | import android.net.Uri 4 | import android.widget.Toast 5 | import androidx.activity.compose.rememberLauncherForActivityResult 6 | import androidx.activity.result.contract.ActivityResultContracts 7 | import androidx.compose.foundation.Image 8 | import androidx.compose.foundation.layout.* 9 | import androidx.compose.foundation.text.KeyboardOptions 10 | import androidx.compose.material.icons.Icons 11 | import androidx.compose.material.icons.filled.ArrowBack 12 | import androidx.compose.material.icons.filled.Menu 13 | import androidx.compose.material.icons.filled.MoreVert 14 | import androidx.compose.material3.* 15 | import androidx.compose.runtime.* 16 | import androidx.compose.ui.Alignment 17 | import androidx.compose.ui.Modifier 18 | import androidx.compose.ui.graphics.Color 19 | import androidx.compose.ui.platform.LocalContext 20 | import androidx.compose.ui.text.input.KeyboardType 21 | import androidx.compose.runtime.livedata.observeAsState 22 | import androidx.compose.ui.unit.dp 23 | import androidx.navigation.NavController 24 | import coil.compose.rememberAsyncImagePainter 25 | import com.harry.sokomart.navigation.ROUT_ADD_PRODUCT 26 | import com.harry.sokomart.navigation.ROUT_PRODUCT_LIST 27 | import com.harry.sokomart.viewmodel.ProductViewModel 28 | 29 | @OptIn(ExperimentalMaterial3Api::class) 30 | @Composable 31 | fun EditProductScreen(productId: Int?, navController: NavController, viewModel: ProductViewModel) { 32 | val context = LocalContext.current 33 | val productList by viewModel.allProducts.observeAsState(emptyList()) 34 | 35 | // Ensure productId is valid 36 | val product = remember(productList) { productList.find { it.id == productId } } 37 | 38 | // Track state variables only when product is found 39 | var name by remember { mutableStateOf(product?.name ?: "") } 40 | var price by remember { mutableStateOf(product?.price?.toString() ?: "") } 41 | var imagePath by remember { mutableStateOf(product?.imagePath ?: "") } 42 | var showMenu by remember { mutableStateOf(false) } 43 | 44 | // Image picker 45 | val imagePicker = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> 46 | uri?.let { 47 | imagePath = it.toString() 48 | Toast.makeText(context, "Image Selected!", Toast.LENGTH_SHORT).show() 49 | } 50 | } 51 | 52 | Scaffold( 53 | topBar = { 54 | TopAppBar( 55 | title = { Text("Edit Product") }, 56 | navigationIcon = { 57 | IconButton(onClick = { navController.popBackStack() }) { 58 | Icon(Icons.Default.ArrowBack, contentDescription = "Back") 59 | } 60 | }, 61 | actions = { 62 | IconButton(onClick = { showMenu = true }) { 63 | Icon(Icons.Default.MoreVert, contentDescription = "Menu") 64 | } 65 | DropdownMenu( 66 | expanded = showMenu, 67 | onDismissRequest = { showMenu = false } 68 | ) { 69 | DropdownMenuItem( 70 | text = { Text("Home") }, 71 | onClick = { 72 | navController.navigate(ROUT_PRODUCT_LIST) 73 | showMenu = false 74 | } 75 | ) 76 | DropdownMenuItem( 77 | text = { Text("Add Product") }, 78 | onClick = { 79 | navController.navigate(ROUT_ADD_PRODUCT) 80 | showMenu = false 81 | } 82 | ) 83 | } 84 | } 85 | ) 86 | }, 87 | bottomBar = { BottomNavigationBar2(navController) } 88 | ) { paddingValues -> 89 | Column( 90 | modifier = Modifier 91 | .fillMaxSize() 92 | .padding(paddingValues) 93 | .padding(16.dp), 94 | horizontalAlignment = Alignment.CenterHorizontally 95 | ) { 96 | if (product != null) { 97 | OutlinedTextField( 98 | value = name, 99 | onValueChange = { name = it }, 100 | label = { Text("Product Name") }, 101 | modifier = Modifier.fillMaxWidth() 102 | ) 103 | Spacer(modifier = Modifier.height(8.dp)) 104 | 105 | OutlinedTextField( 106 | value = price, 107 | onValueChange = { price = it }, 108 | label = { Text("Product Price") }, 109 | keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number), 110 | modifier = Modifier.fillMaxWidth() 111 | ) 112 | Spacer(modifier = Modifier.height(8.dp)) 113 | 114 | // Display Image 115 | Image( 116 | painter = rememberAsyncImagePainter(model = Uri.parse(imagePath)), 117 | contentDescription = "Product Image", 118 | modifier = Modifier 119 | .size(150.dp) 120 | .padding(8.dp) 121 | ) 122 | 123 | Button( 124 | onClick = { imagePicker.launch("image/*") }, 125 | modifier = Modifier.fillMaxWidth() 126 | .padding(start = 40.dp, end = 40.dp), 127 | colors = ButtonDefaults.buttonColors(Color.LightGray) 128 | ) { 129 | Text("Change Image") 130 | } 131 | Spacer(modifier = Modifier.height(16.dp)) 132 | 133 | Button( 134 | onClick = { 135 | val updatedPrice = price.toDoubleOrNull() 136 | if (updatedPrice != null) { 137 | viewModel.updateProduct(product.copy(name = name, price = updatedPrice, imagePath = imagePath)) 138 | Toast.makeText(context, "Product Updated!", Toast.LENGTH_SHORT).show() 139 | navController.popBackStack() 140 | } else { 141 | Toast.makeText(context, "Invalid price entered!", Toast.LENGTH_SHORT).show() 142 | } 143 | }, 144 | modifier = Modifier.fillMaxWidth() 145 | .padding(start = 40.dp, end = 40.dp), 146 | colors = ButtonDefaults.buttonColors(Color.Black) 147 | ) { 148 | Text("Update Product") 149 | } 150 | } else { 151 | Text(text = "Product not found", color = MaterialTheme.colorScheme.error) 152 | Button(onClick = { navController.popBackStack() }) { 153 | Text("Go Back") 154 | } 155 | } 156 | } 157 | } 158 | } 159 | 160 | // Bottom Navigation Bar 161 | @Composable 162 | fun BottomNavigationBar2(navController: NavController) { 163 | NavigationBar( 164 | containerColor = Color(0xFF6F6A72), 165 | contentColor = Color.White 166 | ) { 167 | NavigationBarItem( 168 | selected = false, 169 | onClick = { navController.navigate(ROUT_PRODUCT_LIST) }, 170 | icon = { Icon(Icons.Default.Menu, contentDescription = "Product List") }, 171 | label = { Text("Products") } 172 | ) 173 | NavigationBarItem( 174 | selected = false, 175 | onClick = { navController.navigate(ROUT_ADD_PRODUCT) }, 176 | icon = { Icon(Icons.Default.Menu, contentDescription = "Add Product") }, 177 | label = { Text("Add") } 178 | ) 179 | } 180 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/products/ProductListScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.products 2 | 3 | import android.content.ContentValues 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.graphics.Bitmap 7 | import android.graphics.BitmapFactory 8 | import android.graphics.pdf.PdfDocument 9 | import android.net.Uri 10 | import android.os.Build 11 | import android.os.Environment 12 | import android.provider.MediaStore 13 | import android.widget.Toast 14 | import androidx.annotation.RequiresApi 15 | import androidx.compose.foundation.Image 16 | import androidx.compose.foundation.background 17 | import androidx.compose.foundation.clickable 18 | import androidx.compose.foundation.layout.* 19 | import androidx.compose.foundation.lazy.LazyColumn 20 | import androidx.compose.foundation.shape.RoundedCornerShape 21 | import androidx.compose.material.icons.Icons 22 | import androidx.compose.material.icons.filled.* 23 | import androidx.compose.material3.* 24 | import androidx.compose.runtime.* 25 | import androidx.compose.runtime.livedata.observeAsState 26 | import androidx.compose.ui.Alignment 27 | import androidx.compose.ui.Modifier 28 | import androidx.compose.ui.graphics.Color 29 | import androidx.compose.ui.graphics.Brush 30 | import androidx.compose.ui.graphics.painter.Painter 31 | import androidx.compose.ui.layout.ContentScale 32 | import androidx.compose.ui.platform.LocalContext 33 | import androidx.compose.ui.res.painterResource 34 | import androidx.compose.ui.text.font.FontWeight 35 | import androidx.compose.ui.unit.dp 36 | import androidx.compose.ui.unit.sp 37 | import androidx.core.net.toUri 38 | import androidx.navigation.NavController 39 | import coil.compose.rememberAsyncImagePainter 40 | import com.harry.sokomart.model.Product 41 | import com.harry.sokomart.navigation.ROUT_ADD_PRODUCT 42 | import com.harry.sokomart.navigation.ROUT_EDIT_PRODUCT 43 | import com.harry.sokomart.navigation.ROUT_PRODUCT_LIST 44 | import com.harry.sokomart.viewmodel.ProductViewModel 45 | import java.io.IOException 46 | import java.io.OutputStream 47 | import com.harry.sokomart.R 48 | 49 | @RequiresApi(Build.VERSION_CODES.Q) 50 | @OptIn(ExperimentalMaterial3Api::class) 51 | @Composable 52 | fun ProductListScreen(navController: NavController, viewModel: ProductViewModel) { 53 | val productList by viewModel.allProducts.observeAsState(emptyList()) 54 | var showMenu by remember { mutableStateOf(false) } 55 | var searchQuery by remember { mutableStateOf("") } 56 | 57 | val filteredProducts = productList.filter { 58 | it.name.contains(searchQuery, ignoreCase = true) 59 | } 60 | 61 | Scaffold( 62 | topBar = { 63 | Column { 64 | TopAppBar( 65 | title = { Text("Products", fontSize = 20.sp) }, 66 | colors = TopAppBarDefaults.mediumTopAppBarColors(Color.LightGray), 67 | actions = { 68 | IconButton(onClick = { showMenu = true }) { 69 | Icon(imageVector = Icons.Default.MoreVert, contentDescription = "Menu") 70 | } 71 | DropdownMenu( 72 | expanded = showMenu, 73 | onDismissRequest = { showMenu = false } 74 | ) { 75 | DropdownMenuItem( 76 | text = { Text("Product List") }, 77 | onClick = { 78 | navController.navigate(ROUT_PRODUCT_LIST) 79 | showMenu = false 80 | } 81 | ) 82 | DropdownMenuItem( 83 | text = { Text("Add Product") }, 84 | onClick = { 85 | navController.navigate(ROUT_ADD_PRODUCT) 86 | showMenu = false 87 | } 88 | ) 89 | } 90 | } 91 | ) 92 | 93 | 94 | //Search Bar 95 | OutlinedTextField( 96 | value = searchQuery, 97 | onValueChange = { searchQuery = it }, 98 | modifier = Modifier 99 | .fillMaxWidth() 100 | .padding(horizontal = 12.dp, vertical = 8.dp), 101 | placeholder = { Text("Search products...") }, 102 | singleLine = true, 103 | leadingIcon = { 104 | Icon( 105 | imageVector = Icons.Default.Search, 106 | contentDescription = "Search", 107 | tint = Color.Gray 108 | ) 109 | }, 110 | colors = OutlinedTextFieldDefaults.colors( 111 | focusedBorderColor = Color.Black, // Border color when focused 112 | unfocusedBorderColor = Color.Gray, // Border color when not focused 113 | focusedTextColor = Color.Black, 114 | unfocusedTextColor = Color.DarkGray 115 | ) 116 | ) 117 | } 118 | }, 119 | bottomBar = { BottomNavigationBar1(navController) } 120 | ) { paddingValues -> 121 | Column( 122 | modifier = Modifier 123 | .fillMaxSize() 124 | .padding(paddingValues) 125 | .padding(16.dp) 126 | ) { 127 | LazyColumn { 128 | items(filteredProducts.size) { index -> 129 | ProductItem(navController, filteredProducts[index], viewModel) 130 | } 131 | } 132 | } 133 | } 134 | } 135 | 136 | @RequiresApi(Build.VERSION_CODES.Q) 137 | @Composable 138 | fun ProductItem(navController: NavController, product: Product, viewModel: ProductViewModel) { 139 | val painter: Painter = rememberAsyncImagePainter( 140 | model = product.imagePath?.let { Uri.parse(it) } ?: Uri.EMPTY 141 | ) 142 | val context = LocalContext.current 143 | 144 | Card( 145 | modifier = Modifier 146 | .fillMaxWidth() 147 | .padding(vertical = 8.dp) 148 | .clickable { 149 | if (product.id != 0) { 150 | navController.navigate(ROUT_EDIT_PRODUCT) 151 | } 152 | }, 153 | shape = RoundedCornerShape(12.dp), 154 | elevation = CardDefaults.cardElevation(4.dp) 155 | ) { 156 | Box(modifier = Modifier.fillMaxWidth()) { 157 | // Product Image 158 | Image( 159 | painter = painter, 160 | contentDescription = "Product Image", 161 | modifier = Modifier 162 | .fillMaxWidth() 163 | .height(200.dp), 164 | contentScale = ContentScale.Crop 165 | ) 166 | 167 | // Gradient Overlay 168 | Box( 169 | modifier = Modifier 170 | .fillMaxWidth() 171 | .height(120.dp) 172 | .align(Alignment.BottomStart) 173 | .background( 174 | Brush.verticalGradient( 175 | colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.7f)) 176 | ) 177 | ) 178 | ) 179 | 180 | // Product Info 181 | Column( 182 | modifier = Modifier 183 | .align(Alignment.BottomStart) 184 | .padding(start = 12.dp, bottom = 60.dp) 185 | ) { 186 | Text( 187 | text = product.name, 188 | fontSize = 20.sp, 189 | fontWeight = FontWeight.Bold, 190 | color = Color.White 191 | ) 192 | Text( 193 | text = "Price: Ksh${product.price}", 194 | fontSize = 16.sp, 195 | color = Color.White 196 | ) 197 | } 198 | 199 | // Buttons (Message, Edit, Delete, Download PDF) 200 | Box( 201 | modifier = Modifier 202 | .fillMaxWidth() 203 | .padding(8.dp) 204 | .align(Alignment.BottomEnd) 205 | ) { 206 | Row( 207 | horizontalArrangement = Arrangement.spacedBy(8.dp) 208 | ) { 209 | // Message Seller 210 | OutlinedButton( 211 | onClick = { 212 | val smsIntent = Intent(Intent.ACTION_SENDTO) 213 | smsIntent.data = "smsto:${product.phone}".toUri() 214 | smsIntent.putExtra("sms_body", "Hello Seller,...?") 215 | context.startActivity(smsIntent) 216 | }, 217 | shape = RoundedCornerShape(8.dp), 218 | ) { 219 | Row { 220 | Icon( 221 | imageVector = Icons.Default.Send, 222 | contentDescription = "Message Seller" 223 | ) 224 | Spacer(modifier = Modifier.width(3.dp)) 225 | Text(text = "Message Seller") 226 | } 227 | } 228 | 229 | // Edit Product 230 | IconButton( 231 | onClick = { 232 | navController.navigate(ROUT_EDIT_PRODUCT) 233 | } 234 | ) { 235 | Icon( 236 | imageVector = Icons.Default.Edit, 237 | contentDescription = "Edit", 238 | tint = Color.White 239 | ) 240 | } 241 | 242 | // Delete Product 243 | IconButton( 244 | onClick = { viewModel.deleteProduct(product) } 245 | ) { 246 | Icon( 247 | imageVector = Icons.Default.Delete, 248 | contentDescription = "Delete", 249 | tint = Color.White 250 | ) 251 | } 252 | 253 | // Download PDF 254 | IconButton( 255 | onClick = { generateProductPDF(context, product) } 256 | ) { 257 | Icon( 258 | painter = painterResource(R.drawable.download), 259 | contentDescription = "", 260 | tint = Color.White 261 | ) 262 | } 263 | } 264 | } 265 | } 266 | } 267 | } 268 | 269 | @RequiresApi(Build.VERSION_CODES.Q) 270 | fun generateProductPDF(context: Context, product: Product) { 271 | val pdfDocument = PdfDocument() 272 | val pageInfo = PdfDocument.PageInfo.Builder(300, 500, 1).create() 273 | val page = pdfDocument.startPage(pageInfo) 274 | val canvas = page.canvas 275 | val paint = android.graphics.Paint() 276 | 277 | val bitmap: Bitmap? = try { 278 | product.imagePath?.let { 279 | val uri = Uri.parse(it) 280 | context.contentResolver.openInputStream(uri)?.use { inputStream -> 281 | BitmapFactory.decodeStream(inputStream) 282 | } 283 | } 284 | } catch (e: Exception) { 285 | e.printStackTrace() 286 | null 287 | } 288 | 289 | bitmap?.let { 290 | val scaledBitmap = Bitmap.createScaledBitmap(it, 250, 150, false) 291 | canvas.drawBitmap(scaledBitmap, 25f, 20f, paint) 292 | } 293 | 294 | paint.textSize = 16f 295 | paint.isFakeBoldText = true 296 | canvas.drawText("Product Details", 80f, 200f, paint) 297 | 298 | paint.textSize = 12f 299 | paint.isFakeBoldText = false 300 | canvas.drawText("Name: ${product.name}", 50f, 230f, paint) 301 | canvas.drawText("Price: Ksh${product.price}", 50f, 250f, paint) 302 | canvas.drawText("Seller Phone: ${product.phone}", 50f, 270f, paint) 303 | 304 | pdfDocument.finishPage(page) 305 | 306 | // Save PDF using MediaStore (Scoped Storage) 307 | val fileName = "${product.name}_Details.pdf" 308 | val contentValues = ContentValues().apply { 309 | put(MediaStore.MediaColumns.DISPLAY_NAME, fileName) 310 | put(MediaStore.MediaColumns.MIME_TYPE, "application/pdf") 311 | put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS) 312 | } 313 | 314 | val contentResolver = context.contentResolver 315 | val uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues) 316 | 317 | if (uri != null) { 318 | try { 319 | val outputStream: OutputStream? = contentResolver.openOutputStream(uri) 320 | if (outputStream != null) { 321 | pdfDocument.writeTo(outputStream) 322 | Toast.makeText(context, "PDF saved to Downloads!", Toast.LENGTH_LONG).show() 323 | } 324 | outputStream?.close() 325 | } catch (e: IOException) { 326 | e.printStackTrace() 327 | Toast.makeText(context, "Failed to save PDF!", Toast.LENGTH_LONG).show() 328 | } 329 | } else { 330 | Toast.makeText(context, "Failed to create file!", Toast.LENGTH_LONG).show() 331 | } 332 | 333 | pdfDocument.close() 334 | } 335 | 336 | // Bottom Navigation Bar Component 337 | @Composable 338 | fun BottomNavigationBar1(navController: NavController) { 339 | NavigationBar( 340 | containerColor = Color(0xFFA2B9A2), 341 | contentColor = Color.White 342 | ) { 343 | NavigationBarItem( 344 | selected = false, 345 | onClick = { navController.navigate(ROUT_PRODUCT_LIST) }, 346 | icon = { Icon(Icons.Default.Home, contentDescription = "Product List") }, 347 | label = { Text("Home") } 348 | ) 349 | NavigationBarItem( 350 | selected = false, 351 | onClick = { navController.navigate(ROUT_ADD_PRODUCT) }, 352 | icon = { Icon(Icons.Default.AddCircle, contentDescription = "Add Product") }, 353 | label = { Text("Add") } 354 | ) 355 | } 356 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/service/ServiceScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.service 2 | 3 | import androidx.compose.material3.ExperimentalMaterial3Api 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.tooling.preview.Preview 6 | import androidx.navigation.NavController 7 | import androidx.navigation.compose.rememberNavController 8 | 9 | @OptIn(ExperimentalMaterial3Api::class) 10 | @Composable 11 | fun ServiceScreen(navController: NavController) { 12 | 13 | 14 | } 15 | @Preview(showBackground = true) 16 | @Composable 17 | fun ServiceScreenPreview(){ 18 | ServiceScreen(navController= rememberNavController()) 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/splash/SplashScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.splash 2 | 3 | import android.annotation.SuppressLint 4 | import androidx.compose.foundation.Image 5 | import androidx.compose.foundation.background 6 | import androidx.compose.foundation.layout.Arrangement 7 | import androidx.compose.foundation.layout.Column 8 | import androidx.compose.foundation.layout.fillMaxSize 9 | import androidx.compose.foundation.layout.size 10 | import androidx.compose.foundation.shape.RoundedCornerShape 11 | import androidx.compose.material3.Text 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.runtime.rememberCoroutineScope 14 | import androidx.compose.ui.Alignment 15 | import androidx.compose.ui.Modifier 16 | import androidx.compose.ui.draw.clip 17 | import androidx.compose.ui.res.painterResource 18 | import androidx.compose.ui.text.font.FontWeight 19 | import androidx.compose.ui.tooling.preview.Preview 20 | import androidx.compose.ui.unit.dp 21 | import androidx.compose.ui.unit.sp 22 | import androidx.navigation.NavController 23 | import androidx.navigation.compose.rememberNavController 24 | import com.harry.sokomart.R 25 | import com.harry.sokomart.navigation.ROUT_LOGIN 26 | import com.harry.sokomart.ui.theme.mytheme 27 | import kotlinx.coroutines.delay 28 | import kotlinx.coroutines.launch 29 | 30 | @SuppressLint("CoroutineCreationDuringComposition") 31 | @Composable 32 | fun SplashScreen(navController: NavController){ 33 | val coroutine = rememberCoroutineScope() 34 | coroutine.launch { 35 | delay(2000) 36 | navController.navigate(ROUT_LOGIN) 37 | } 38 | Column ( 39 | modifier = Modifier 40 | .fillMaxSize() 41 | .background(mytheme) 42 | , 43 | horizontalAlignment = Alignment.CenterHorizontally, 44 | verticalArrangement = Arrangement.Center 45 | ){ 46 | Image( 47 | painter = painterResource(R.drawable.img_14), 48 | contentDescription = "", 49 | modifier = Modifier.size(300.dp).clip(shape = RoundedCornerShape(10.dp)), 50 | ) 51 | Text( 52 | text = "KAI & KARO", 53 | fontSize = 35.sp, 54 | fontWeight = FontWeight.ExtraBold 55 | ) 56 | } 57 | } 58 | 59 | @Preview(showBackground = true) 60 | @Composable 61 | fun SplashScreenPreview(){ 62 | SplashScreen(navController= rememberNavController()) 63 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/screens/start/StartScreen.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.screens.start 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.layout.Arrangement 5 | import androidx.compose.foundation.layout.Column 6 | import androidx.compose.foundation.layout.Spacer 7 | import androidx.compose.foundation.layout.fillMaxSize 8 | import androidx.compose.foundation.layout.fillMaxWidth 9 | import androidx.compose.foundation.layout.height 10 | import androidx.compose.foundation.layout.padding 11 | import androidx.compose.foundation.layout.size 12 | import androidx.compose.foundation.shape.RoundedCornerShape 13 | import androidx.compose.material3.Button 14 | import androidx.compose.material3.ButtonDefaults 15 | import androidx.compose.material3.Text 16 | import androidx.compose.runtime.Composable 17 | import androidx.compose.ui.Alignment 18 | import androidx.compose.ui.Modifier 19 | import androidx.compose.ui.draw.clip 20 | import androidx.compose.ui.res.painterResource 21 | import androidx.compose.ui.text.font.FontWeight 22 | import androidx.compose.ui.text.style.TextAlign 23 | import androidx.compose.ui.tooling.preview.Preview 24 | import androidx.compose.ui.unit.dp 25 | import androidx.compose.ui.unit.sp 26 | import androidx.navigation.NavController 27 | import androidx.navigation.compose.rememberNavController 28 | import com.harry.sokomart.R 29 | import com.harry.sokomart.navigation.ROUT_ITEM 30 | import com.harry.sokomart.ui.theme.mytheme 31 | 32 | @Composable 33 | fun StartScreen(navController: NavController){ 34 | Column ( 35 | modifier = Modifier.fillMaxSize(), 36 | horizontalAlignment = Alignment.CenterHorizontally, 37 | verticalArrangement = Arrangement.Center 38 | ){ 39 | Text( 40 | text = "Kai & Karo", 41 | fontSize = 40.sp, 42 | color = mytheme, 43 | fontWeight = FontWeight.Bold 44 | ) 45 | 46 | Image( 47 | painter = painterResource(R.drawable.img), 48 | contentDescription = "home", 49 | modifier = Modifier.size(300.dp).clip(shape = RoundedCornerShape(10.dp)) 50 | ) 51 | Spacer(modifier = Modifier.height(20.dp)) 52 | Text( 53 | text = "Buy a Car today", 54 | fontSize = 30.sp, 55 | fontWeight = FontWeight.Bold, 56 | color = mytheme 57 | ) 58 | Text( 59 | text = "commercial activities including the electronic buying or selling products and services which are conducted on online platforms or over the Internet.[1] E-commerce draws on technologies such as mobile commerce, electronic funds transfer, supply chain management, Internet marketing, online transaction processing, electronic data interchange (EDI), inventory management systems, and automated data collection systems. E-commerce is the largest sector of the electronics industry and is in turn driven by the technological advances of the semiconductor industry.", 60 | fontSize = 18.sp, 61 | textAlign = TextAlign.Center 62 | ) 63 | Button( 64 | onClick = { 65 | navController.navigate(ROUT_ITEM) 66 | }, 67 | shape = RoundedCornerShape(10.dp), 68 | colors = ButtonDefaults.buttonColors(mytheme), 69 | modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 20.dp) 70 | ) { 71 | Text(text = "Get started") 72 | } 73 | 74 | } 75 | } 76 | 77 | @Preview(showBackground = true) 78 | @Composable 79 | fun StartScreenPreview(){ 80 | StartScreen(navController= rememberNavController()) 81 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | val Purple80 = Color(0xFFD0BCFF) 5 | val PurpleGrey80 = Color(0xFFCCC2DC) 6 | val Pink80 = Color(0xFFEFB8C8) 7 | 8 | val Purple40 = Color(0xFF6650a4) 9 | val PurpleGrey40 = Color(0xFF625b71) 10 | val Pink40 = Color(0xFF7D5260) 11 | val newcyan = Color(0xFF00BCD4) 12 | val mytheme = Color(0xFF054B6B) 13 | val white = Color(0xFFF8F8F8) 14 | val blue = Color(0xFF071388) 15 | val orange = Color(0xFFF57F17) 16 | val green = Color(0xFF098310) 17 | val gray = Color(0xFF989A98) 18 | val lightteal = Color(0xFF0D524C) -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.ui.theme 2 | 3 | import android.os.Build 4 | import androidx.compose.foundation.isSystemInDarkTheme 5 | import androidx.compose.material3.MaterialTheme 6 | import androidx.compose.material3.darkColorScheme 7 | import androidx.compose.material3.dynamicDarkColorScheme 8 | import androidx.compose.material3.dynamicLightColorScheme 9 | import androidx.compose.material3.lightColorScheme 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.ui.platform.LocalContext 12 | 13 | private val DarkColorScheme = darkColorScheme( 14 | primary = Purple80, 15 | secondary = PurpleGrey80, 16 | tertiary = Pink80 17 | ) 18 | 19 | private val LightColorScheme = lightColorScheme( 20 | primary = Purple40, 21 | secondary = PurpleGrey40, 22 | tertiary = Pink40 23 | 24 | /* Other default colors to override 25 | background = Color(0xFFFFFBFE), 26 | surface = Color(0xFFFFFBFE), 27 | onPrimary = Color.White, 28 | onSecondary = Color.White, 29 | onTertiary = Color.White, 30 | onBackground = Color(0xFF1C1B1F), 31 | onSurface = Color(0xFF1C1B1F), 32 | */ 33 | ) 34 | 35 | @Composable 36 | fun SokoMartTheme( 37 | darkTheme: Boolean = isSystemInDarkTheme(), 38 | // Dynamic color is available on Android 12+ 39 | dynamicColor: Boolean = true, 40 | content: @Composable () -> Unit 41 | ) { 42 | val colorScheme = when { 43 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { 44 | val context = LocalContext.current 45 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) 46 | } 47 | 48 | darkTheme -> DarkColorScheme 49 | else -> LightColorScheme 50 | } 51 | 52 | MaterialTheme( 53 | colorScheme = colorScheme, 54 | typography = Typography, 55 | content = content 56 | ) 57 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.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/java/com/harry/sokomart/viewmodel/AuthViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.viewmodel 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.harry.sokomart.model.User 6 | import com.harry.sokomart.repository.UserRepository 7 | import kotlinx.coroutines.launch 8 | 9 | class AuthViewModel(private val repository: UserRepository) : ViewModel() { 10 | var loggedInUser: ((User?) -> Unit)? = null 11 | 12 | fun registerUser(user: User) { 13 | viewModelScope.launch { 14 | repository.registerUser(user) 15 | } 16 | } 17 | 18 | fun loginUser(email: String, password: String) { 19 | viewModelScope.launch { 20 | val user = repository.loginUser(email, password) 21 | loggedInUser?.invoke(user) 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/harry/sokomart/viewmodel/ProductViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.harry.sokomart.viewmodel 2 | 3 | import android.app.Application 4 | import android.net.Uri 5 | import androidx.lifecycle.AndroidViewModel 6 | import androidx.lifecycle.LiveData 7 | import androidx.lifecycle.viewModelScope 8 | import com.harry.sokomart.data.ProductDatabase 9 | import com.harry.sokomart.model.Product 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.launch 12 | import java.io.File 13 | import java.io.FileOutputStream 14 | import java.io.InputStream 15 | 16 | class ProductViewModel(app: Application) : AndroidViewModel(app) { 17 | 18 | private val context = app.applicationContext 19 | private val productDao = ProductDatabase.getDatabase(app).productDao() 20 | 21 | val allProducts: LiveData> = productDao.getAllProducts() 22 | 23 | fun addProduct(name: String, price: Double, phone: String, imageUri: String) { 24 | viewModelScope.launch(Dispatchers.IO) { 25 | val savedImagePath = saveImageToInternalStorage(Uri.parse(imageUri)) 26 | val newProduct = Product( 27 | name = name, 28 | price = price, 29 | phone = phone, 30 | imagePath = savedImagePath // use saved image path 31 | ) 32 | productDao.insertProduct(newProduct) 33 | } 34 | } 35 | 36 | fun updateProduct(updatedProduct: Product) { 37 | viewModelScope.launch(Dispatchers.IO) { 38 | productDao.updateProduct(updatedProduct) 39 | } 40 | } 41 | 42 | fun deleteProduct(product: Product) { 43 | viewModelScope.launch(Dispatchers.IO) { 44 | // Delete image from storage 45 | deleteImageFromInternalStorage(product.imagePath) 46 | productDao.deleteProduct(product) 47 | } 48 | } 49 | 50 | // Save image permanently to internal storage 51 | private fun saveImageToInternalStorage(uri: Uri): String { 52 | val inputStream: InputStream? = context.contentResolver.openInputStream(uri) 53 | val fileName = "IMG_${System.currentTimeMillis()}.jpg" 54 | val file = File(context.filesDir, fileName) 55 | 56 | inputStream?.use { input -> 57 | FileOutputStream(file).use { output -> 58 | input.copyTo(output) 59 | } 60 | } 61 | 62 | return file.absolutePath 63 | } 64 | 65 | private fun deleteImageFromInternalStorage(path: String) { 66 | try { 67 | val file = File(path) 68 | if (file.exists()) { 69 | file.delete() 70 | } 71 | } catch (e: Exception) { 72 | e.printStackTrace() 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/download.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /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/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | 14 | 16 | 18 | 20 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_10.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_11.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_12.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_13.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_14.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_15.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_16.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_4.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_5.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_6.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_7.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_8.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/drawable/img_9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/name.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/price.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/product.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/visibility.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/visibilityoff.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myusercloud/mypath-android/6bcddd5dc235f6ebbf4f4c98d1c08e7eede3c936/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 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #999494 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SokoMart 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |