mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-10 09:22:21 +00:00
connect localserver
This commit is contained in:
26
.idea/appInsightsSettings.xml
generated
Normal file
26
.idea/appInsightsSettings.xml
generated
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AppInsightsSettings">
|
||||
<option name="tabSettings">
|
||||
<map>
|
||||
<entry key="Firebase Crashlytics">
|
||||
<value>
|
||||
<InsightsFilterSettings>
|
||||
<option name="connection">
|
||||
<ConnectionSetting>
|
||||
<option name="appId" value="PLACEHOLDER" />
|
||||
<option name="mobileSdkAppId" value="" />
|
||||
<option name="projectId" value="" />
|
||||
<option name="projectNumber" value="" />
|
||||
</ConnectionSetting>
|
||||
</option>
|
||||
<option name="signal" value="SIGNAL_UNSPECIFIED" />
|
||||
<option name="timeIntervalDays" value="THIRTY_DAYS" />
|
||||
<option name="visibilityType" value="ALL" />
|
||||
</InsightsFilterSettings>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
68
.idea/other.xml
generated
68
.idea/other.xml
generated
@ -14,6 +14,17 @@
|
||||
<option name="screenX" value="720" />
|
||||
<option name="screenY" value="1280" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="34" />
|
||||
<option name="brand" value="OPPO" />
|
||||
<option name="codename" value="OP573DL1" />
|
||||
<option name="id" value="OP573DL1" />
|
||||
<option name="manufacturer" value="OPPO" />
|
||||
<option name="name" value="CPH2557" />
|
||||
<option name="screenDensity" value="480" />
|
||||
<option name="screenX" value="1080" />
|
||||
<option name="screenY" value="2400" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="28" />
|
||||
<option name="brand" value="DOCOMO" />
|
||||
@ -113,6 +124,17 @@
|
||||
<option name="screenX" value="2220" />
|
||||
<option name="screenY" value="1080" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="34" />
|
||||
<option name="brand" value="samsung" />
|
||||
<option name="codename" value="dm2q" />
|
||||
<option name="id" value="dm2q" />
|
||||
<option name="manufacturer" value="Samsung" />
|
||||
<option name="name" value="S23 Plus" />
|
||||
<option name="screenDensity" value="450" />
|
||||
<option name="screenX" value="1080" />
|
||||
<option name="screenY" value="2340" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="34" />
|
||||
<option name="brand" value="samsung" />
|
||||
@ -135,6 +157,28 @@
|
||||
<option name="screenX" value="1080" />
|
||||
<option name="screenY" value="2340" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="34" />
|
||||
<option name="brand" value="samsung" />
|
||||
<option name="codename" value="e3q" />
|
||||
<option name="id" value="e3q" />
|
||||
<option name="manufacturer" value="Samsung" />
|
||||
<option name="name" value="Galaxy S24 Ultra" />
|
||||
<option name="screenDensity" value="450" />
|
||||
<option name="screenX" value="1440" />
|
||||
<option name="screenY" value="3120" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="33" />
|
||||
<option name="brand" value="google" />
|
||||
<option name="codename" value="eos" />
|
||||
<option name="id" value="eos" />
|
||||
<option name="manufacturer" value="Google" />
|
||||
<option name="name" value="Eos" />
|
||||
<option name="screenDensity" value="320" />
|
||||
<option name="screenX" value="384" />
|
||||
<option name="screenY" value="384" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="33" />
|
||||
<option name="brand" value="google" />
|
||||
@ -168,6 +212,17 @@
|
||||
<option name="screenX" value="2208" />
|
||||
<option name="screenY" value="1840" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="34" />
|
||||
<option name="brand" value="motorola" />
|
||||
<option name="codename" value="fogona" />
|
||||
<option name="id" value="fogona" />
|
||||
<option name="manufacturer" value="Motorola" />
|
||||
<option name="name" value="moto g play - 2024" />
|
||||
<option name="screenDensity" value="280" />
|
||||
<option name="screenX" value="720" />
|
||||
<option name="screenY" value="1600" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="33" />
|
||||
<option name="brand" value="samsung" />
|
||||
@ -223,6 +278,17 @@
|
||||
<option name="screenX" value="1080" />
|
||||
<option name="screenY" value="2400" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="33" />
|
||||
<option name="brand" value="motorola" />
|
||||
<option name="codename" value="maui" />
|
||||
<option name="id" value="maui" />
|
||||
<option name="manufacturer" value="Motorola" />
|
||||
<option name="name" value="moto g play - 2023" />
|
||||
<option name="screenDensity" value="280" />
|
||||
<option name="screenX" value="720" />
|
||||
<option name="screenY" value="1600" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="31" />
|
||||
<option name="brand" value="google" />
|
||||
@ -262,7 +328,7 @@
|
||||
<option name="codename" value="q6q" />
|
||||
<option name="id" value="q6q" />
|
||||
<option name="manufacturer" value="Samsung" />
|
||||
<option name="name" value="SM-F956B" />
|
||||
<option name="name" value="Galaxy Z Fold6" />
|
||||
<option name="screenDensity" value="420" />
|
||||
<option name="screenX" value="1856" />
|
||||
<option name="screenY" value="2160" />
|
||||
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -1,6 +1,10 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.jetbrains.kotlin.android)
|
||||
id("kotlin-kapt")
|
||||
id ("androidx.navigation.safeargs")
|
||||
id("kotlin-parcelize")
|
||||
// id("com.google.dagger.hilt.android")
|
||||
}
|
||||
|
||||
android {
|
||||
@ -9,7 +13,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.alya.ecommerce_serang"
|
||||
minSdk = 24
|
||||
minSdk = 21
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
@ -19,21 +23,26 @@ android {
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
buildConfigField("String", "BASE_URL", "\"http://192.168.1.13:3000/\"")
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
debug {
|
||||
buildConfigField("String", "BASE_URL", "\"http://192.168.1.13:3000/\"")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
jvmTarget = "11"
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
viewBinding = true
|
||||
}
|
||||
}
|
||||
@ -45,7 +54,34 @@ dependencies {
|
||||
implementation(libs.material)
|
||||
implementation(libs.androidx.activity)
|
||||
implementation(libs.androidx.constraintlayout)
|
||||
implementation(libs.androidx.legacy.support.v4)
|
||||
implementation(libs.androidx.lifecycle.livedata.ktx)
|
||||
implementation(libs.androidx.lifecycle.viewmodel.ktx)
|
||||
implementation(libs.androidx.fragment.ktx)
|
||||
implementation(libs.androidx.navigation.fragment.ktx)
|
||||
implementation(libs.androidx.navigation.ui.ktx)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
}
|
||||
|
||||
//retrofit
|
||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
|
||||
|
||||
|
||||
|
||||
// implementation("com.github.zhpanvip:viewpagerindicator:1.2.3")
|
||||
implementation("com.github.bumptech.glide:glide:4.16.0")
|
||||
implementation("androidx.paging:paging-runtime:3.2.1")
|
||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||
|
||||
|
||||
// implementation(libs.hilt.android)
|
||||
// kapt("com.google.dagger:hilt-compiler:2.48")
|
||||
//
|
||||
// // For ViewModel injection (if needed)
|
||||
// implementation(libs.androidx.hilt.lifecycle.viewmodel)
|
||||
// kapt("androidx.hilt:hilt-compiler:1.0.0")
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
@ -11,7 +13,9 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Ecommerce_serang"
|
||||
tools:targetApi="31">
|
||||
tools:targetApi="31"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
android:exported="true">
|
||||
|
7
app/src/main/java/com/alya/ecommerce_serang/app/App.kt
Normal file
7
app/src/main/java/com/alya/ecommerce_serang/app/App.kt
Normal file
@ -0,0 +1,7 @@
|
||||
package com.alya.ecommerce_serang.app
|
||||
|
||||
import android.app.Application
|
||||
|
||||
//@HiltAndroidApp
|
||||
class App : Application(){
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.alya.ecommerce_serang.data.api.dto
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class Category(
|
||||
val id: String,
|
||||
val image: String,
|
||||
val title: String
|
||||
): Parcelable
|
@ -0,0 +1,22 @@
|
||||
package com.alya.ecommerce_serang.data.api.dto
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class DetailProduct(
|
||||
val category: String,
|
||||
val description: String,
|
||||
val discount: Double?,
|
||||
@SerializedName("favorite")
|
||||
val wishlist: Boolean,
|
||||
val id: String,
|
||||
val images: List<String>,
|
||||
@SerializedName("in_stock")
|
||||
val inStock: Int,
|
||||
val price: Double,
|
||||
val rating: Double,
|
||||
val related: List<Product>,
|
||||
val reviews: Int,
|
||||
val title: String,
|
||||
@SerializedName("free_delivery")
|
||||
val freeDelivery:Boolean
|
||||
)
|
@ -0,0 +1,17 @@
|
||||
package com.alya.ecommerce_serang.data.api.dto
|
||||
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class Product (
|
||||
val id: String,
|
||||
val discount: Double?,
|
||||
@SerializedName("favorite")
|
||||
var wishlist: Boolean,
|
||||
val image: String,
|
||||
val price: Double,
|
||||
val rating: Double,
|
||||
@SerializedName("rating_count")
|
||||
val ratingCount: Int,
|
||||
val title: String,
|
||||
)
|
@ -0,0 +1,57 @@
|
||||
package com.alya.ecommerce_serang.data.api.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class AllProductResponse(
|
||||
|
||||
@field:SerializedName("message")
|
||||
val message: String,
|
||||
|
||||
@field:SerializedName("products")
|
||||
val products: List<ProductsItem>
|
||||
)
|
||||
|
||||
data class ProductsItem(
|
||||
|
||||
@field:SerializedName("store_id")
|
||||
val storeId: Int,
|
||||
|
||||
@field:SerializedName("image")
|
||||
val image: String,
|
||||
|
||||
@field:SerializedName("rating")
|
||||
val rating: String,
|
||||
|
||||
@field:SerializedName("description")
|
||||
val description: String,
|
||||
|
||||
@field:SerializedName("weight")
|
||||
val weight: Int,
|
||||
|
||||
@field:SerializedName("is_pre_order")
|
||||
val isPreOrder: Boolean,
|
||||
|
||||
@field:SerializedName("category_id")
|
||||
val categoryId: Int,
|
||||
|
||||
@field:SerializedName("price")
|
||||
val price: String,
|
||||
|
||||
@field:SerializedName("name")
|
||||
val name: String,
|
||||
|
||||
@field:SerializedName("id")
|
||||
val id: Int,
|
||||
|
||||
@field:SerializedName("min_order")
|
||||
val minOrder: Int,
|
||||
|
||||
@field:SerializedName("total_sold")
|
||||
val totalSold: Int,
|
||||
|
||||
@field:SerializedName("stock")
|
||||
val stock: Int,
|
||||
|
||||
@field:SerializedName("status")
|
||||
val status: String
|
||||
)
|
@ -0,0 +1,60 @@
|
||||
package com.alya.ecommerce_serang.data.api.response
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class ProductResponse(
|
||||
|
||||
@field:SerializedName("product")
|
||||
val product: Product,
|
||||
|
||||
@field:SerializedName("message")
|
||||
val message: String
|
||||
)
|
||||
|
||||
data class Product(
|
||||
|
||||
@field:SerializedName("store_id")
|
||||
val storeId: Int,
|
||||
|
||||
@field:SerializedName("image")
|
||||
val image: String,
|
||||
|
||||
@field:SerializedName("rating")
|
||||
val rating: String,
|
||||
|
||||
@field:SerializedName("description")
|
||||
val description: String,
|
||||
|
||||
@field:SerializedName("weight")
|
||||
val weight: Int,
|
||||
|
||||
@field:SerializedName("product_name")
|
||||
val productName: String,
|
||||
|
||||
@field:SerializedName("is_pre_order")
|
||||
val isPreOrder: Boolean,
|
||||
|
||||
@field:SerializedName("duration")
|
||||
val duration: Any,
|
||||
|
||||
@field:SerializedName("category_id")
|
||||
val categoryId: Int,
|
||||
|
||||
@field:SerializedName("price")
|
||||
val price: String,
|
||||
|
||||
@field:SerializedName("product_id")
|
||||
val productId: Int,
|
||||
|
||||
@field:SerializedName("min_order")
|
||||
val minOrder: Int,
|
||||
|
||||
@field:SerializedName("total_sold")
|
||||
val totalSold: Int,
|
||||
|
||||
@field:SerializedName("stock")
|
||||
val stock: Int,
|
||||
|
||||
@field:SerializedName("product_category")
|
||||
val productCategory: String
|
||||
)
|
@ -0,0 +1,25 @@
|
||||
package com.alya.ecommerce_serang.data.api.retrofit
|
||||
|
||||
import com.alya.ecommerce_serang.BuildConfig
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
|
||||
class ApiConfig {
|
||||
companion object{
|
||||
fun getApiService(): ApiService {
|
||||
val loggingInterceptor =
|
||||
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
|
||||
val client = OkHttpClient.Builder()
|
||||
.addInterceptor(loggingInterceptor)
|
||||
.build()
|
||||
val retrofit = Retrofit.Builder()
|
||||
.baseUrl(BuildConfig.BASE_URL)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.client(client)
|
||||
.build()
|
||||
return retrofit.create(ApiService::class.java)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.alya.ecommerce_serang.data.api.retrofit
|
||||
|
||||
import com.alya.ecommerce_serang.data.api.response.AllProductResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.ProductResponse
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.Path
|
||||
|
||||
interface ApiService {
|
||||
@GET("product")
|
||||
fun getAllProduct(
|
||||
@Header("Authorization") token: String = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzEsIm5hbWUiOiJhbHlhIiwiZW1haWwiOiJha3VuYmVsYWphci5hbHlhQGdtYWlsLmNvbSIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzM4NDg0OTc0LCJleHAiOjE3NDEwNzY5NzR9.0JyXJQ_6CKiZEi0gvk1gcn-0ILu3a9lOr3HqjhJXbBE"
|
||||
): Call<AllProductResponse>
|
||||
|
||||
|
||||
@GET("product/detail/{id}")
|
||||
fun getDetailProduct (
|
||||
@Header("Authorization") token: String,
|
||||
@Path("id") productId: Int
|
||||
): Call<ProductResponse>
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.alya.ecommerce_serang.data.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class Product(
|
||||
|
||||
@field:SerializedName("store_id")
|
||||
val storeId: Int,
|
||||
|
||||
@field:SerializedName("image")
|
||||
val image: String,
|
||||
|
||||
@field:SerializedName("rating")
|
||||
val rating: String,
|
||||
|
||||
@field:SerializedName("description")
|
||||
val description: String,
|
||||
|
||||
@field:SerializedName("weight")
|
||||
val weight: Int,
|
||||
|
||||
@field:SerializedName("product_name")
|
||||
val productName: String,
|
||||
|
||||
@field:SerializedName("is_pre_order")
|
||||
val isPreOrder: Boolean,
|
||||
|
||||
@field:SerializedName("duration")
|
||||
val duration: Any,
|
||||
|
||||
@field:SerializedName("category_id")
|
||||
val categoryId: Int,
|
||||
|
||||
@field:SerializedName("price")
|
||||
val price: String,
|
||||
|
||||
@field:SerializedName("product_id")
|
||||
val productId: Int,
|
||||
|
||||
@field:SerializedName("min_order")
|
||||
val minOrder: Int,
|
||||
|
||||
@field:SerializedName("total_sold")
|
||||
val totalSold: Int,
|
||||
|
||||
@field:SerializedName("stock")
|
||||
val stock: Int,
|
||||
|
||||
@field:SerializedName("product_category")
|
||||
val productCategory: String
|
||||
)
|
@ -0,0 +1,9 @@
|
||||
package com.alya.ecommerce_serang.data.model
|
||||
|
||||
data class User(
|
||||
val username: String,
|
||||
val avatar:String?,
|
||||
val email:String,
|
||||
val firstName:String?,
|
||||
val lastName:String?
|
||||
)
|
@ -0,0 +1,35 @@
|
||||
package com.alya.ecommerce_serang.data.repository
|
||||
|
||||
import android.util.Log
|
||||
import com.alya.ecommerce_serang.data.api.response.ProductsItem
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class ProductRepository(private val apiService: ApiService) {
|
||||
suspend fun getAllProducts(): Result<List<ProductsItem>> =
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
Log.d("ProductRepository", "Attempting to fetch products")
|
||||
val response = apiService.getAllProduct().execute()
|
||||
Log.d("ProductRepository", "Response received. Success: ${response.isSuccessful}")
|
||||
Log.d("ProductRepository", "Response code: ${response.code()}")
|
||||
Log.d("ProductRepository", "Response message: ${response.message()}")
|
||||
|
||||
if (response.isSuccessful) {
|
||||
Result.success(response.body()?.products ?: emptyList())
|
||||
} else {
|
||||
Result.failure(Exception("Failed to fetch products"))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
// suspend fun getCategories():List<Category>
|
||||
//
|
||||
// fun getProducts(query: ProductQuery) : Flow<PagingData<Product>>
|
||||
// fun getRecentSearchs(): Flow<List<String>>
|
||||
// suspend fun clearRecents()
|
||||
// suspend fun addRecents(search:String)
|
||||
// suspend fun getProduct(id:String):DetailProduct
|
||||
}
|
@ -1,31 +1,57 @@
|
||||
package com.alya.ecommerce_serang.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.databinding.ActivityMainBinding
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
|
||||
|
||||
//@AndroidEntryPoint
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private val navController by lazy {
|
||||
(supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController
|
||||
}
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
enableEdgeToEdge()
|
||||
setContentView(R.layout.activity_main)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
}
|
||||
|
||||
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_navigation)
|
||||
setupBottomNavigation()
|
||||
observeDestinationChanges()
|
||||
|
||||
}
|
||||
|
||||
private fun setupBottomNavigation() {
|
||||
binding.bottomNavigation.setupWithNavController(navController)
|
||||
|
||||
binding.bottomNavigation.setOnItemSelectedListener { menuItem ->
|
||||
when (menuItem.itemId) {
|
||||
R.id.home_item_fragment -> {
|
||||
navController.navigate(R.id.homeFragment)
|
||||
true
|
||||
}
|
||||
R.id.chat_item_fragment -> {
|
||||
navController.navigate(R.id.chatFragment)
|
||||
true
|
||||
}
|
||||
R.id.profile_item_fragment -> {
|
||||
navController.navigate(R.id.profileFragment)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeDestinationChanges() {
|
||||
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||
binding.bottomNavigation.isVisible = when (destination.id) {
|
||||
R.id.homeFragment, R.id.chatFragment, R.id.profileFragment -> true
|
||||
else -> false // Bottom Navigation tidak terlihat di layar lain
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.alya.ecommerce_serang.ui.chat
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.alya.ecommerce_serang.R
|
||||
|
||||
class ChatFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = ChatFragment()
|
||||
}
|
||||
|
||||
private val viewModel: ChatViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// TODO: Use the ViewModel
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
return inflater.inflate(R.layout.fragment_chat, container, false)
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.alya.ecommerce_serang.ui.chat
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
class ChatViewModel : ViewModel() {
|
||||
// TODO: Implement the ViewModel
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.alya.ecommerce_serang.ui.home
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alya.ecommerce_serang.data.api.dto.Category
|
||||
import com.alya.ecommerce_serang.databinding.ItemCategoryHomeBinding
|
||||
import com.bumptech.glide.Glide
|
||||
|
||||
class HomeCategoryAdapter(
|
||||
private val categories:List<Category>,
|
||||
//A lambda function that will be invoked when a category item is clicked.
|
||||
private val onClick:(category:Category) -> Unit
|
||||
): RecyclerView.Adapter<HomeCategoryAdapter.ViewHolder>() {
|
||||
|
||||
/*
|
||||
ViewHolder is responsible for caching and managing the view references for each item in
|
||||
the RecyclerView.It binds the Category data to the corresponding views within the item layout.
|
||||
*/
|
||||
inner class ViewHolder(private val binding: ItemCategoryHomeBinding): RecyclerView.ViewHolder(binding.root){
|
||||
fun bind(category: Category) = with(binding){
|
||||
Glide.with(root).load(category.image).into(image)
|
||||
name.text = category.title
|
||||
root.setOnClickListener{
|
||||
onClick(category)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder (
|
||||
ItemCategoryHomeBinding.inflate(LayoutInflater.from(parent.context),parent,false)
|
||||
)
|
||||
|
||||
override fun getItemCount() = categories.size
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.bind(categories[position])
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
package com.alya.ecommerce_serang.ui.home
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.response.ProductsItem
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||
import com.alya.ecommerce_serang.data.repository.ProductRepository
|
||||
import com.alya.ecommerce_serang.databinding.FragmentHomeBinding
|
||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||
import com.alya.ecommerce_serang.utils.HorizontalMarginItemDecoration
|
||||
import com.alya.ecommerce_serang.utils.setLightStatusBar
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
//@AndroidEntryPoint
|
||||
class HomeFragment : Fragment() {
|
||||
|
||||
private var _binding: FragmentHomeBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private lateinit var viewModel: HomeViewModel
|
||||
private var productAdapter: HorizontalProductAdapter? = null
|
||||
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentHomeBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val repository = ProductRepository(ApiConfig.getApiService())
|
||||
viewModel = ViewModelProvider(
|
||||
this,
|
||||
// Pass a lambda that creates the ViewModel
|
||||
BaseViewModelFactory {
|
||||
HomeViewModel(repository)
|
||||
}
|
||||
)[HomeViewModel::class.java]
|
||||
|
||||
initUi()
|
||||
setupRecyclerView()
|
||||
observeData()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
productAdapter = HorizontalProductAdapter(
|
||||
products = emptyList(),
|
||||
onClick = { product -> handleProductClick(product) }
|
||||
)
|
||||
|
||||
binding.newProducts.apply {
|
||||
adapter = productAdapter
|
||||
layoutManager = LinearLayoutManager(
|
||||
context,
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeData() {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.uiState.collect { state ->
|
||||
when (state) {
|
||||
is HomeUiState.Loading -> {
|
||||
binding.loading.root.isVisible = true
|
||||
binding.error.root.isVisible = false
|
||||
binding.home.isVisible = false
|
||||
}
|
||||
is HomeUiState.Success -> {
|
||||
binding.loading.root.isVisible = false
|
||||
binding.error.root.isVisible = false
|
||||
binding.home.isVisible = true
|
||||
productAdapter?.updateProducts(state.products)
|
||||
}
|
||||
is HomeUiState.Error -> {
|
||||
binding.loading.root.isVisible = false
|
||||
binding.error.root.isVisible = true
|
||||
binding.home.isVisible = false
|
||||
binding.error.errorMessage.text = state.message
|
||||
binding.error.retryButton.setOnClickListener {
|
||||
viewModel.retry()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initUi() {
|
||||
// For LightStatusBar
|
||||
setLightStatusBar()
|
||||
val banners = binding.banners
|
||||
banners.offscreenPageLimit = 1
|
||||
|
||||
val nextItemVisiblePx = resources.getDimension(R.dimen.viewpager_next_item_visible)
|
||||
val currentItemHorizontalMarginPx =
|
||||
resources.getDimension(R.dimen.viewpager_current_item_horizontal_margin)
|
||||
val pageTranslationX = nextItemVisiblePx + currentItemHorizontalMarginPx
|
||||
|
||||
banners.setPageTransformer { page, position ->
|
||||
page.translationX = -pageTranslationX * position
|
||||
page.scaleY = 1 - (0.25f * kotlin.math.abs(position))
|
||||
}
|
||||
|
||||
banners.addItemDecoration(
|
||||
HorizontalMarginItemDecoration(
|
||||
requireContext(),
|
||||
R.dimen.viewpager_current_item_horizontal_margin
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun handleProductClick(product: ProductsItem) {
|
||||
// Navigate to product detail
|
||||
// findNavController().navigate(
|
||||
// HomeFragmentDirections.actionHomeToDetail(product.id)
|
||||
// )
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
private fun showLoading(isLoading: Boolean) {
|
||||
if (isLoading) {
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.progressBar.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package com.alya.ecommerce_serang.ui.home
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.alya.ecommerce_serang.data.api.response.AllProductResponse
|
||||
import com.alya.ecommerce_serang.data.api.response.ProductsItem
|
||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||
import com.alya.ecommerce_serang.data.repository.ProductRepository
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class HomeViewModel (
|
||||
private val productRepository: ProductRepository
|
||||
): ViewModel() {
|
||||
private val _uiState = MutableStateFlow<HomeUiState>(HomeUiState.Loading)
|
||||
val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()
|
||||
val home = MutableLiveData<AllProductResponse?>(null)
|
||||
constructor() : this(ProductRepository(ApiConfig.getApiService()))
|
||||
|
||||
|
||||
init {
|
||||
loadProducts()
|
||||
}
|
||||
|
||||
private fun loadProducts() {
|
||||
viewModelScope.launch {
|
||||
_uiState.value = HomeUiState.Loading
|
||||
productRepository.getAllProducts()
|
||||
.onSuccess { products ->
|
||||
_uiState.value = HomeUiState.Success(products)
|
||||
}
|
||||
.onFailure { error ->
|
||||
_uiState.value = HomeUiState.Error(error.message ?: "Unknown error")
|
||||
Log.e("ProductViewModel", "Products fetch failed", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun retry() {
|
||||
loadProducts()
|
||||
}
|
||||
|
||||
// fun toggleWishlist(product: Product) = viewModelScope.launch {
|
||||
// try {
|
||||
// productRepository.toggleWishlist(product.id,product.wishlist)
|
||||
// }catch (e:Exception){
|
||||
//
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
sealed class HomeUiState {
|
||||
object Loading : HomeUiState()
|
||||
data class Success(val products: List<ProductsItem>) : HomeUiState()
|
||||
data class Error(val message: String) : HomeUiState()
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.alya.ecommerce_serang.ui.home
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alya.ecommerce_serang.data.api.response.ProductsItem
|
||||
import com.alya.ecommerce_serang.databinding.ItemProductHorizontalBinding
|
||||
import com.bumptech.glide.Glide
|
||||
|
||||
class HorizontalProductAdapter(
|
||||
private var products: List<ProductsItem>,
|
||||
private val onClick: (ProductsItem) -> Unit
|
||||
) : RecyclerView.Adapter<HorizontalProductAdapter.ProductViewHolder>() {
|
||||
|
||||
inner class ProductViewHolder(private val binding: ItemProductHorizontalBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(product: ProductsItem) = with(binding) {
|
||||
itemName.text = product.name
|
||||
itemPrice.text = product.price
|
||||
rating.text = product.rating
|
||||
// productSold.text = "${product.totalSold} sold"
|
||||
|
||||
// Load image using Glide
|
||||
Glide.with(itemView)
|
||||
// .load("${BuildConfig.BASE_URL}/product/${product.image}")
|
||||
// .load("${BuildConfig.BASE_URL}/${product.image}")
|
||||
.load(product.image)
|
||||
.into(image)
|
||||
|
||||
root.setOnClickListener { onClick(product) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
|
||||
val binding = ItemProductHorizontalBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
)
|
||||
return ProductViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun getItemCount() = products.size
|
||||
|
||||
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
|
||||
holder.bind(products[position])
|
||||
}
|
||||
|
||||
fun updateProducts(newProducts: List<ProductsItem>) {
|
||||
products = newProducts
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.alya.ecommerce_serang.ui.product
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alya.ecommerce_serang.R
|
||||
import com.alya.ecommerce_serang.data.api.dto.Product
|
||||
import com.alya.ecommerce_serang.databinding.ItemProductHorizontalBinding
|
||||
import com.bumptech.glide.Glide
|
||||
|
||||
class ProductViewHolder(private val binding: ItemProductHorizontalBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(
|
||||
product: Product,
|
||||
onClick: (product: Product) -> Unit,
|
||||
) = with(binding) {
|
||||
Glide.with(root).load(product.image).into(image)
|
||||
|
||||
// discount.isVisible = product.discount != null
|
||||
// product.discount?.let {
|
||||
// val discount = (product.discount / product.price * 100).roundToInt()
|
||||
// binding.discount.text =
|
||||
// root.context.getString(R.string.fragment_item_product_discount, discount)
|
||||
// }
|
||||
|
||||
itemName.text = product.title
|
||||
rating.text = String.format("%.1f", product.rating)
|
||||
|
||||
// val current = product.price - (product.discount ?: 0.0)
|
||||
val current = product.price
|
||||
itemPrice.text = root.context.getString(R.string.item_price_txt, current)
|
||||
|
||||
root.setOnClickListener {
|
||||
onClick(product)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.alya.ecommerce_serang.ui.profile
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.alya.ecommerce_serang.R
|
||||
|
||||
class ProfileFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = ProfileFragment()
|
||||
}
|
||||
|
||||
private val viewModel: ProfileViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// TODO: Use the ViewModel
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
return inflater.inflate(R.layout.fragment_profile, container, false)
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.alya.ecommerce_serang.ui.profile
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
class ProfileViewModel : ViewModel() {
|
||||
// TODO: Implement the ViewModel
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.alya.ecommerce_serang.utils
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
|
||||
typealias Inflate<T> = (LayoutInflater, ViewGroup?, Boolean) -> T
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.alya.ecommerce_serang.utils
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
|
||||
class BaseViewModelFactory<VM : ViewModel>(
|
||||
private val creator: () -> VM
|
||||
) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return creator() as T
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.alya.ecommerce_serang.utils
|
||||
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.WindowInsetsController
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
fun Fragment.setLightStatusBar(){
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
requireActivity().window.insetsController?.setSystemBarsAppearance(
|
||||
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
|
||||
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
requireActivity().window.decorView.systemUiVisibility = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
||||
} else {
|
||||
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.alya.ecommerce_serang.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
import androidx.annotation.DimenRes
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
class HorizontalMarginItemDecoration(context: Context, @DimenRes horizontalMarginInDp: Int) :
|
||||
RecyclerView.ItemDecoration() {
|
||||
|
||||
private val horizontalMarginInPx: Int =
|
||||
context.resources.getDimension(horizontalMarginInDp).toInt()
|
||||
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
|
||||
) {
|
||||
outRect.right = horizontalMarginInPx
|
||||
outRect.left = horizontalMarginInPx
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.alya.ecommerce_serang.utils
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.alya.ecommerce_serang.data.api.dto.Category
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class ProductQuery (
|
||||
val category: Category? = null,
|
||||
val search:String? = null,
|
||||
val range:Pair<Float,Float> = 0f to 10000f,
|
||||
val rating:Int? = null,
|
||||
val discount:Int? = null,
|
||||
val sort:List<Sort> = emptyList(),
|
||||
val favorite:Boolean = false
|
||||
): Parcelable
|
||||
|
||||
enum class Sort{
|
||||
disconunt, voucher, shipping, delivery
|
||||
}
|
BIN
app/src/main/res/drawable/banner_default.jpg
Normal file
BIN
app/src/main/res/drawable/banner_default.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.9 KiB |
5
app/src/main/res/drawable/baseline_account_circle_24.xml
Normal file
5
app/src/main/res/drawable/baseline_account_circle_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#489EC6" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,6c1.93,0 3.5,1.57 3.5,3.5S13.93,13 12,13s-3.5,-1.57 -3.5,-3.5S10.07,6 12,6zM12,20c-2.03,0 -4.43,-0.82 -6.14,-2.88C7.55,15.8 9.68,15 12,15s4.45,0.8 6.14,2.12C16.43,19.18 14.03,20 12,20z"/>
|
||||
|
||||
</vector>
|
5
app/src/main/res/drawable/baseline_arrow_back_24.xml
Normal file
5
app/src/main/res/drawable/baseline_arrow_back_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#489EC6" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
|
||||
|
||||
</vector>
|
5
app/src/main/res/drawable/baseline_chat_24.xml
Normal file
5
app/src/main/res/drawable/baseline_chat_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#489EC6" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM6,9h12v2L6,11L6,9zM14,14L6,14v-2h8v2zM18,8L6,8L6,6h12v2z"/>
|
||||
|
||||
</vector>
|
5
app/src/main/res/drawable/baseline_home_24.xml
Normal file
5
app/src/main/res/drawable/baseline_home_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#489EC6" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
|
||||
|
||||
</vector>
|
5
app/src/main/res/drawable/baseline_search_24.xml
Normal file
5
app/src/main/res/drawable/baseline_search_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#E8ECF2" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@color/soft_gray" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||
|
||||
</vector>
|
5
app/src/main/res/drawable/baseline_star_24.xml
Normal file
5
app/src/main/res/drawable/baseline_star_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFE86D" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
|
||||
|
||||
</vector>
|
BIN
app/src/main/res/drawable/makanan_ringan.jpg
Normal file
BIN
app/src/main/res/drawable/makanan_ringan.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
8
app/src/main/res/drawable/outline_notifications_24.xml
Normal file
8
app/src/main/res/drawable/outline_notifications_24.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#489EC6" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM18,16v-5c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.64,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2zM16,17L8,17v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5v6z"
|
||||
/>
|
||||
|
||||
</vector>
|
5
app/src/main/res/drawable/outline_shopping_cart_24.xml
Normal file
5
app/src/main/res/drawable/outline_shopping_cart_24.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#489EC6" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M15.55,13c0.75,0 1.41,-0.41 1.75,-1.03l3.58,-6.49c0.37,-0.66 -0.11,-1.48 -0.87,-1.48L5.21,4l-0.94,-2L1,2v2h2l3.6,7.59 -1.35,2.44C4.52,15.37 5.48,17 7,17h12v-2L7,15l1.1,-2h7.45zM6.16,6h12.15l-2.76,5L8.53,11L6.16,6zM7,18c-1.1,0 -1.99,0.9 -1.99,2S5.9,22 7,22s2,-0.9 2,-2 -0.9,-2 -2,-2zM17,18c-1.1,0 -1.99,0.9 -1.99,2s0.89,2 1.99,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
||||
|
||||
</vector>
|
7
app/src/main/res/drawable/rating_background.xml
Normal file
7
app/src/main/res/drawable/rating_background.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<stroke android:width="1dp"
|
||||
android:color="#33B8BBC6"/>
|
||||
<corners android:radius="11dp"/>
|
||||
</selector>
|
6
app/src/main/res/drawable/search_background.xml
Normal file
6
app/src/main/res/drawable/search_background.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<stroke android:width="1dp"
|
||||
android:color="@color/soft_gray"/>
|
||||
<corners android:radius="15dp"/>
|
||||
</shape>
|
8
app/src/main/res/drawable/selector_account.xml
Normal file
8
app/src/main/res/drawable/selector_account.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:state_checked="true"
|
||||
android:drawable="@drawable/baseline_account_circle_24" />
|
||||
<item
|
||||
android:drawable="@drawable/outline_account_circle_24" />
|
||||
</selector>
|
8
app/src/main/res/drawable/selector_chat.xml
Normal file
8
app/src/main/res/drawable/selector_chat.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:state_checked="true"
|
||||
android:drawable="@drawable/baseline_chat_24" />
|
||||
<item
|
||||
android:drawable="@drawable/outline_chat_24" />
|
||||
</selector>
|
8
app/src/main/res/drawable/selector_home.xml
Normal file
8
app/src/main/res/drawable/selector_home.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:state_checked="true"
|
||||
android:drawable="@drawable/baseline_home_24" />
|
||||
<item
|
||||
android:drawable="@drawable/outline_home_24" />
|
||||
</selector>
|
@ -1,32 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:context=".ui.MainActivity">
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World!"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/bottom_navigation"
|
||||
<!-- NavHostFragment -->
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/nav_host_fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottom_navigation"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/nav_graph" />
|
||||
|
||||
<!-- BottomNavigationView -->
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/bottom_navigation"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
style="@style/Widget.Material3.BottomNavigationView"
|
||||
app:menu="@menu/bottom_navigation_menu"
|
||||
app:itemIconTint="#489EC6"
|
||||
app:itemIconSize="@dimen/m3_comp_navigation_bar_active_indicator_height"/>
|
||||
app:itemIconSize="@dimen/m3_comp_navigation_bar_active_indicator_height" />
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
13
app/src/main/res/layout/fragment_chat.xml
Normal file
13
app/src/main/res/layout/fragment_chat.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.chat.ChatFragment">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="Hello" />
|
||||
|
||||
</FrameLayout>
|
120
app/src/main/res/layout/fragment_home.xml
Normal file
120
app/src/main/res/layout/fragment_home.xml
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:context=".ui.home.HomeFragment">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/home"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<include
|
||||
android:id="@+id/searchContainer"
|
||||
layout="@layout/view_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="19dp"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/banners"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="132dp"
|
||||
android:layout_marginTop="23dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintTop_toBottomOf="@id/searchContainer"
|
||||
tools:layout_editor_absoluteX="16dp" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/categoriesText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/fragment_home_categories"
|
||||
android:textColor="@color/dark"
|
||||
android:textSize="22sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/banners" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/showAll"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:text="@string/show_all"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/blue1"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/categoriesText"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/categories"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="19dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="24dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintTop_toBottomOf="@id/categoriesText"
|
||||
tools:layout_editor_absoluteX="0dp"
|
||||
tools:listitem="@layout/item_category_home" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/new_products"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="39dp"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:orientation="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintTop_toBottomOf="@id/categories"
|
||||
tools:itemCount="5"
|
||||
tools:listitem="@layout/item_section_horizontal" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
||||
|
||||
<include
|
||||
android:id="@+id/loading"
|
||||
layout="@layout/view_loading"/>
|
||||
|
||||
<include
|
||||
android:id="@+id/error"
|
||||
layout="@layout/view_error"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
<!-- <com.zhpan.indicator.IndicatorView-->
|
||||
<!-- android:id="@+id/indicator"-->
|
||||
<!-- android:layout_width="wrap_content"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_marginTop="20dp"-->
|
||||
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||
<!-- app:layout_constraintStart_toStartOf="parent"-->
|
||||
<!-- app:layout_constraintTop_toBottomOf="@+id/banners" />-->
|
13
app/src/main/res/layout/fragment_profile.xml
Normal file
13
app/src/main/res/layout/fragment_profile.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.profile.ProfileFragment">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="Hello" />
|
||||
|
||||
</FrameLayout>
|
6
app/src/main/res/layout/item_category.xml
Normal file
6
app/src/main/res/layout/item_category.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
36
app/src/main/res/layout/item_category_home.xml
Normal file
36
app/src/main/res/layout/item_category_home.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="88dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/imageLayout"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:cardCornerRadius="14dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:strokeWidth="1dp"
|
||||
app:strokeColor="@color/gray_1">
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/image"
|
||||
android:src="@drawable/makanan_ringan"
|
||||
android:scaleType="centerCrop" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/name"
|
||||
android:textAlignment="center"
|
||||
android:text="@string/fragment_home_item_categories"
|
||||
app:layout_constraintTop_toBottomOf="@id/imageLayout"
|
||||
android:textSize="16sp"
|
||||
android:textColor="@color/dark"
|
||||
android:layout_marginTop="12dp"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
66
app/src/main/res/layout/item_product_horizontal.xml
Normal file
66
app/src/main/res/layout/item_product_horizontal.xml
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="185dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/imageLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:cardCornerRadius="14dp"
|
||||
app:layout_constraintDimensionRatio="272:218"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="@color/gray_1"
|
||||
app:strokeWidth="1dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@color/blue1" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/item_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="17dp"
|
||||
android:text="Banana"
|
||||
android:textColor="@color/dark"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintTop_toBottomOf="@id/imageLayout" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/item_price"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/item_price_txt"
|
||||
android:textColor="@color/dark"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintTop_toBottomOf="@id/item_name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/rating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/rating_background"
|
||||
android:drawablePadding="4dp"
|
||||
android:paddingStart="7dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingEnd="11dp"
|
||||
android:paddingBottom="3dp"
|
||||
android:text="4.5"
|
||||
android:textColor="@color/dark"
|
||||
android:textSize="10sp"
|
||||
android:textAlignment="center"
|
||||
android:gravity="center"
|
||||
app:drawableStartCompat="@drawable/baseline_star_24"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/item_price" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
46
app/src/main/res/layout/item_section_horizontal.xml
Normal file
46
app/src/main/res/layout/item_section_horizontal.xml
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_marginVertical="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:textColor="@color/dark"
|
||||
android:text="All grocery"
|
||||
android:textSize="22sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/showAll"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:text="@string/show_all"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/blue1"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/title"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/products"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="23dp"
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal"
|
||||
tools:listitem="@layout/item_product_horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
46
app/src/main/res/layout/item_section_vertical.xml
Normal file
46
app/src/main/res/layout/item_section_vertical.xml
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="20dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:textColor="@color/dark"
|
||||
android:text="All grocery"
|
||||
android:textSize="22sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/showAll"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:text="@string/show_all"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/blue1"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/title"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/products"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingVertical="25dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
tools:itemCount="5"
|
||||
tools:layout_editor_absoluteX="16dp"
|
||||
tools:listitem="@layout/item_product_horizontal" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
31
app/src/main/res/layout/view_error.xml
Normal file
31
app/src/main/res/layout/view_error.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/errorMessage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/retryButton"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/retryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Retry"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/errorMessage" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
6
app/src/main/res/layout/view_loading.xml
Normal file
6
app/src/main/res/layout/view_loading.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
49
app/src/main/res/layout/view_search.xml
Normal file
49
app/src/main/res/layout/view_search.xml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/search"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="@drawable/search_background"
|
||||
android:hint="@string/fragment_home_search"
|
||||
android:textColor="@color/soft_gray"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:paddingHorizontal="25dp"
|
||||
android:imeOptions="actionSearch"
|
||||
android:inputType="text"
|
||||
app:layout_constraintEnd_toStartOf="@id/btn_notification"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:drawableStart="@drawable/baseline_search_24" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_notification"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:backgroundTint="@color/white"
|
||||
android:src="@drawable/outline_notifications_24"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintBottom_toBottomOf="@id/search"
|
||||
app:layout_constraintEnd_toStartOf="@id/btn_cart"
|
||||
app:layout_constraintTop_toTopOf="@id/search"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_cart"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:padding="8dp"
|
||||
android:backgroundTint="@color/white"
|
||||
android:src="@drawable/outline_shopping_cart_24"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintBottom_toBottomOf="@id/search"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/search"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,18 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/page_1"
|
||||
android:id="@+id/home_item_fragment"
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/outline_home_24"
|
||||
android:icon="@drawable/selector_home"
|
||||
android:title="Beranda" />
|
||||
<item
|
||||
android:id="@+id/page_2"
|
||||
android:id="@+id/chat_item_fragment"
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/outline_chat_24"
|
||||
android:icon="@drawable/selector_chat"
|
||||
android:title="Pesan" />
|
||||
<item
|
||||
android:id="@+id/page_3"
|
||||
android:id="@+id/profile_item_fragment"
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/outline_account_circle_24"
|
||||
android:icon="@drawable/selector_account"
|
||||
android:title="Profil" />
|
||||
</menu>
|
23
app/src/main/res/navigation/nav_graph.xml
Normal file
23
app/src/main/res/navigation/nav_graph.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/nav_graph"
|
||||
app:startDestination="@id/homeFragment">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/homeFragment"
|
||||
android:name="com.alya.ecommerce_serang.ui.home.HomeFragment"
|
||||
android:label="fragment_home"
|
||||
tools:layout="@layout/fragment_home" />
|
||||
<fragment
|
||||
android:id="@+id/profileFragment"
|
||||
android:name="com.alya.ecommerce_serang.ui.profile.ProfileFragment"
|
||||
android:label="fragment_profile"
|
||||
tools:layout="@layout/fragment_profile" />
|
||||
<fragment
|
||||
android:id="@+id/chatFragment"
|
||||
android:name="com.alya.ecommerce_serang.ui.chat.ChatFragment"
|
||||
android:label="fragment_chat"
|
||||
tools:layout="@layout/fragment_chat" />
|
||||
</navigation>
|
@ -2,4 +2,8 @@
|
||||
<resources>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="gray_1">#E8ECF2</color>
|
||||
<color name="soft_gray">#7D8FAB</color>
|
||||
<color name="dark">#303733</color>
|
||||
<color name="blue1">#489EC6</color>
|
||||
</resources>
|
5
app/src/main/res/values/dimens.xml
Normal file
5
app/src/main/res/values/dimens.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="viewpager_current_item_horizontal_margin">32dp</dimen>
|
||||
<dimen name="viewpager_next_item_visible">16dp</dimen>
|
||||
</resources>
|
@ -1,3 +1,14 @@
|
||||
<resources>
|
||||
<string name="app_name">ecommerce_serang</string>
|
||||
|
||||
|
||||
<!--Placeholder-->
|
||||
<string name="fragment_home_search">Cari produk</string>
|
||||
<string name="fragment_home_categories">Kategori Produk</string>
|
||||
<string name="fragment_home_item_categories">Makanan Ringan</string>
|
||||
<string name="show_all">Lainnya</string>
|
||||
|
||||
<string name="item_price_txt">Rp%.1f</string>
|
||||
<string name="retry">Coba lagi\n</string>
|
||||
<string name="error_loading">Terdapat error...</string>
|
||||
</resources>
|
13
app/src/main/res/xml/network_security_config.xml
Normal file
13
app/src/main/res/xml/network_security_config.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="true">
|
||||
<trust-anchors>
|
||||
<certificates src="system" />
|
||||
<certificates src="user" />
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">192.168.1.13</domain>
|
||||
<domain includeSubdomains="true">localhost</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
@ -1,4 +1,11 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath ("androidx.navigation:navigation-safe-args-gradle-plugin:2.5.1")
|
||||
// classpath("com.google.dagger:hilt-android-gradle-plugin:2.55")
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.jetbrains.kotlin.android) apply false
|
||||
|
@ -1,5 +1,7 @@
|
||||
[versions]
|
||||
agp = "8.5.2"
|
||||
hiltAndroid = "2.51"
|
||||
hiltLifecycleViewmodel = "1.0.0-alpha03"
|
||||
kotlin = "1.9.0"
|
||||
coreKtx = "1.10.1"
|
||||
junit = "4.13.2"
|
||||
@ -9,9 +11,17 @@ appcompat = "1.7.0"
|
||||
material = "1.12.0"
|
||||
activity = "1.9.2"
|
||||
constraintlayout = "2.1.4"
|
||||
legacySupportV4 = "1.0.0"
|
||||
lifecycleLivedataKtx = "2.8.7"
|
||||
lifecycleViewmodelKtx = "2.8.7"
|
||||
fragmentKtx = "1.5.6"
|
||||
navigationFragmentKtx = "2.8.5"
|
||||
navigationUiKtx = "2.8.5"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
androidx-hilt-lifecycle-viewmodel = { module = "androidx.hilt:hilt-lifecycle-viewmodel", version.ref = "hiltLifecycleViewmodel" }
|
||||
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" }
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
@ -19,6 +29,12 @@ androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version
|
||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
||||
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
||||
androidx-legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacySupportV4" }
|
||||
androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
|
||||
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||
androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragmentKtx" }
|
||||
androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
|
||||
androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
|
Reference in New Issue
Block a user