mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-12 18:22:22 +00:00
fixed otp
This commit is contained in:
@ -23,7 +23,7 @@ android {
|
|||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
buildConfigField("String", "BASE_URL", "\"http://192.168.1.13:3000/\"")
|
buildConfigField("String", "BASE_URL", "\"http://192.168.1.6:3000/\"")
|
||||||
isMinifyEnabled = false
|
isMinifyEnabled = false
|
||||||
proguardFiles(
|
proguardFiles(
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
@ -31,7 +31,7 @@ android {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
debug {
|
debug {
|
||||||
buildConfigField("String", "BASE_URL", "\"http://192.168.1.13:3000/\"")
|
buildConfigField("String", "BASE_URL", "\"http://192.168.1.6:3000/\"")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
@ -72,6 +72,8 @@ dependencies {
|
|||||||
implementation("com.github.bumptech.glide:glide:4.16.0")
|
implementation("com.github.bumptech.glide:glide:4.16.0")
|
||||||
implementation("androidx.paging:paging-runtime:3.2.1")
|
implementation("androidx.paging:paging-runtime:3.2.1")
|
||||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||||
|
implementation("de.hdodenhof:circleimageview:3.1.0")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// implementation(libs.hilt.android)
|
// implementation(libs.hilt.android)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@ -10,17 +10,14 @@
|
|||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Ecommerce_serang"
|
android:theme="@style/Theme.Ecommerce_serang"
|
||||||
tools:targetApi="31"
|
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
android:networkSecurityConfig="@xml/network_security_config">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.TokoSayaActivity"
|
android:name=".ui.auth.RegisterActivity"
|
||||||
android:exported="false" />
|
|
||||||
<activity
|
|
||||||
android:name=".ui.MainActivity"
|
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@ -28,6 +25,20 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.auth.LoginActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
<activity
|
||||||
|
android:name=".ui.profile.DetailProfileActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
<activity
|
||||||
|
android:name=".ui.TokoSayaActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
<activity
|
||||||
|
android:name=".ui.MainActivity"
|
||||||
|
android:exported="true">
|
||||||
|
|
||||||
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.alya.ecommerce_serang.data.api.dto
|
||||||
|
|
||||||
|
data class LoginRequest (
|
||||||
|
val email: String,
|
||||||
|
val password: String,
|
||||||
|
)
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.alya.ecommerce_serang.data.api.dto
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class OtpRequest(
|
||||||
|
@SerializedName("email") val email: String
|
||||||
|
)
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.alya.ecommerce_serang.data.api.dto
|
||||||
|
|
||||||
|
data class RegisterRequest (
|
||||||
|
val name: String?,
|
||||||
|
val email: String?,
|
||||||
|
val password: String?,
|
||||||
|
val username: String?,
|
||||||
|
val phone: String?,
|
||||||
|
val birthDate: String?,
|
||||||
|
val image: String?,
|
||||||
|
val otp: String? = null
|
||||||
|
)
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.alya.ecommerce_serang.data.api.response
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class LoginResponse(
|
||||||
|
|
||||||
|
@field:SerializedName("role")
|
||||||
|
val role: String,
|
||||||
|
|
||||||
|
@field:SerializedName("message")
|
||||||
|
val message: String,
|
||||||
|
|
||||||
|
@field:SerializedName("accessToken")
|
||||||
|
val accessToken: String
|
||||||
|
)
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.alya.ecommerce_serang.data.api.response
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class OtpResponse(
|
||||||
|
|
||||||
|
@field:SerializedName("message")
|
||||||
|
val message: String
|
||||||
|
)
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.alya.ecommerce_serang.data.api.response
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RegisterResponse(
|
||||||
|
|
||||||
|
@field:SerializedName("message")
|
||||||
|
val message: String,
|
||||||
|
|
||||||
|
@field:SerializedName("user")
|
||||||
|
val user: User
|
||||||
|
)
|
||||||
|
|
||||||
|
data class User(
|
||||||
|
|
||||||
|
@field:SerializedName("image")
|
||||||
|
val image: String,
|
||||||
|
|
||||||
|
@field:SerializedName("password")
|
||||||
|
val password: String,
|
||||||
|
|
||||||
|
@field:SerializedName("role")
|
||||||
|
val role: String,
|
||||||
|
|
||||||
|
@field:SerializedName("phone")
|
||||||
|
val phone: String,
|
||||||
|
|
||||||
|
@field:SerializedName("birth_date")
|
||||||
|
val birthDate: String,
|
||||||
|
|
||||||
|
@field:SerializedName("name")
|
||||||
|
val name: String,
|
||||||
|
|
||||||
|
@field:SerializedName("id")
|
||||||
|
val id: Int,
|
||||||
|
|
||||||
|
@field:SerializedName("email")
|
||||||
|
val email: String,
|
||||||
|
|
||||||
|
@field:SerializedName("username")
|
||||||
|
val username: String
|
||||||
|
)
|
@ -0,0 +1,138 @@
|
|||||||
|
package com.alya.ecommerce_serang.data.api.response
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class StoreResponse(
|
||||||
|
|
||||||
|
@field:SerializedName("shipping")
|
||||||
|
val shipping: List<ShippingItem>,
|
||||||
|
|
||||||
|
@field:SerializedName("payment")
|
||||||
|
val payment: List<PaymentItem>,
|
||||||
|
|
||||||
|
@field:SerializedName("store")
|
||||||
|
val store: Store,
|
||||||
|
|
||||||
|
@field:SerializedName("message")
|
||||||
|
val message: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Store(
|
||||||
|
|
||||||
|
@field:SerializedName("approval_reason")
|
||||||
|
val approvalReason: String,
|
||||||
|
|
||||||
|
@field:SerializedName("store_status")
|
||||||
|
val storeStatus: String,
|
||||||
|
|
||||||
|
@field:SerializedName("sppirt")
|
||||||
|
val sppirt: String,
|
||||||
|
|
||||||
|
@field:SerializedName("user_name")
|
||||||
|
val userName: String,
|
||||||
|
|
||||||
|
@field:SerializedName("nib")
|
||||||
|
val nib: String,
|
||||||
|
|
||||||
|
@field:SerializedName("latitude")
|
||||||
|
val latitude: String,
|
||||||
|
|
||||||
|
@field:SerializedName("store_type_id")
|
||||||
|
val storeTypeId: Int,
|
||||||
|
|
||||||
|
@field:SerializedName("balance")
|
||||||
|
val balance: String,
|
||||||
|
|
||||||
|
@field:SerializedName("street")
|
||||||
|
val street: String,
|
||||||
|
|
||||||
|
@field:SerializedName("store_name")
|
||||||
|
val storeName: String,
|
||||||
|
|
||||||
|
@field:SerializedName("user_phone")
|
||||||
|
val userPhone: String,
|
||||||
|
|
||||||
|
@field:SerializedName("halal")
|
||||||
|
val halal: String,
|
||||||
|
|
||||||
|
@field:SerializedName("id")
|
||||||
|
val id: Int,
|
||||||
|
|
||||||
|
@field:SerializedName("email")
|
||||||
|
val email: String,
|
||||||
|
|
||||||
|
@field:SerializedName("store_image")
|
||||||
|
val storeImage: Any,
|
||||||
|
|
||||||
|
@field:SerializedName("longitude")
|
||||||
|
val longitude: String,
|
||||||
|
|
||||||
|
@field:SerializedName("store_id")
|
||||||
|
val storeId: Int,
|
||||||
|
|
||||||
|
@field:SerializedName("is_store_location")
|
||||||
|
val isStoreLocation: Boolean,
|
||||||
|
|
||||||
|
@field:SerializedName("ktp")
|
||||||
|
val ktp: String,
|
||||||
|
|
||||||
|
@field:SerializedName("approval_status")
|
||||||
|
val approvalStatus: String,
|
||||||
|
|
||||||
|
@field:SerializedName("npwp")
|
||||||
|
val npwp: String,
|
||||||
|
|
||||||
|
@field:SerializedName("store_type")
|
||||||
|
val storeType: String,
|
||||||
|
|
||||||
|
@field:SerializedName("is_on_leave")
|
||||||
|
val isOnLeave: Boolean,
|
||||||
|
|
||||||
|
@field:SerializedName("user_id")
|
||||||
|
val userId: Int,
|
||||||
|
|
||||||
|
@field:SerializedName("province_id")
|
||||||
|
val provinceId: Int,
|
||||||
|
|
||||||
|
@field:SerializedName("phone")
|
||||||
|
val phone: String,
|
||||||
|
|
||||||
|
@field:SerializedName("subdistrict")
|
||||||
|
val subdistrict: String,
|
||||||
|
|
||||||
|
@field:SerializedName("recipient")
|
||||||
|
val recipient: String,
|
||||||
|
|
||||||
|
@field:SerializedName("detail")
|
||||||
|
val detail: String,
|
||||||
|
|
||||||
|
@field:SerializedName("postal_code")
|
||||||
|
val postalCode: String,
|
||||||
|
|
||||||
|
@field:SerializedName("store_description")
|
||||||
|
val storeDescription: String,
|
||||||
|
|
||||||
|
@field:SerializedName("city_id")
|
||||||
|
val cityId: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
data class ShippingItem(
|
||||||
|
|
||||||
|
@field:SerializedName("courier")
|
||||||
|
val courier: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class PaymentItem(
|
||||||
|
|
||||||
|
@field:SerializedName("qris_image")
|
||||||
|
val qrisImage: String,
|
||||||
|
|
||||||
|
@field:SerializedName("bank_num")
|
||||||
|
val bankNum: String,
|
||||||
|
|
||||||
|
@field:SerializedName("bank_name")
|
||||||
|
val bankName: String,
|
||||||
|
|
||||||
|
@field:SerializedName("id")
|
||||||
|
val id: Int
|
||||||
|
)
|
@ -1,24 +1,51 @@
|
|||||||
package com.alya.ecommerce_serang.data.api.retrofit
|
package com.alya.ecommerce_serang.data.api.retrofit
|
||||||
|
|
||||||
import com.alya.ecommerce_serang.BuildConfig
|
import com.alya.ecommerce_serang.BuildConfig
|
||||||
|
import com.alya.ecommerce_serang.utils.AuthInterceptor
|
||||||
|
import com.alya.ecommerce_serang.utils.SessionManager
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
class ApiConfig {
|
class ApiConfig {
|
||||||
companion object{
|
companion object {
|
||||||
fun getApiService(): ApiService {
|
fun getApiService(tokenManager: SessionManager): ApiService {
|
||||||
val loggingInterceptor =
|
val loggingInterceptor = HttpLoggingInterceptor().apply {
|
||||||
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
|
level = HttpLoggingInterceptor.Level.BODY
|
||||||
|
}
|
||||||
|
|
||||||
|
val authInterceptor = AuthInterceptor(tokenManager)
|
||||||
|
|
||||||
val client = OkHttpClient.Builder()
|
val client = OkHttpClient.Builder()
|
||||||
.addInterceptor(loggingInterceptor)
|
.addInterceptor(loggingInterceptor)
|
||||||
|
.addInterceptor(authInterceptor)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val retrofit = Retrofit.Builder()
|
val retrofit = Retrofit.Builder()
|
||||||
.baseUrl(BuildConfig.BASE_URL)
|
.baseUrl(BuildConfig.BASE_URL)
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.client(client)
|
.client(client)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
return retrofit.create(ApiService::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUnauthenticatedApiService(): ApiService {
|
||||||
|
val loggingInterceptor = HttpLoggingInterceptor().apply {
|
||||||
|
level = 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)
|
return retrofit.create(ApiService::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,45 @@
|
|||||||
package com.alya.ecommerce_serang.data.api.retrofit
|
package com.alya.ecommerce_serang.data.api.retrofit
|
||||||
|
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.LoginRequest
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.OtpRequest
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
|
||||||
import com.alya.ecommerce_serang.data.api.response.AllProductResponse
|
import com.alya.ecommerce_serang.data.api.response.AllProductResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.LoginResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.OtpResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.ProductResponse
|
import com.alya.ecommerce_serang.data.api.response.ProductResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.RegisterResponse
|
||||||
import com.alya.ecommerce_serang.data.api.response.StoreResponse
|
import com.alya.ecommerce_serang.data.api.response.StoreResponse
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
|
import retrofit2.Response
|
||||||
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.POST
|
||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
|
|
||||||
interface ApiService {
|
interface ApiService {
|
||||||
@GET("product")
|
@POST("registeruser")
|
||||||
fun getAllProduct(
|
suspend fun register (
|
||||||
@Header("Authorization") token: String = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzEsIm5hbWUiOiJhbHlhIiwiZW1haWwiOiJha3VuYmVsYWphci5hbHlhQGdtYWlsLmNvbSIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzM4NDg0OTc0LCJleHAiOjE3NDEwNzY5NzR9.0JyXJQ_6CKiZEi0gvk1gcn-0ILu3a9lOr3HqjhJXbBE"
|
@Body registerRequest: RegisterRequest
|
||||||
): Call<AllProductResponse>
|
): Response<RegisterResponse>
|
||||||
|
|
||||||
|
@POST("otp")
|
||||||
|
suspend fun getOTP(
|
||||||
|
@Body otpRequest: OtpRequest
|
||||||
|
):OtpResponse
|
||||||
|
|
||||||
|
@POST("login")
|
||||||
|
fun login(
|
||||||
|
@Body loginRequest: LoginRequest
|
||||||
|
): Call<LoginResponse>
|
||||||
|
|
||||||
|
@GET("product")
|
||||||
|
fun getAllProduct(): Call<AllProductResponse>
|
||||||
|
|
||||||
@GET("product/detail/{id}")
|
@GET("product/detail/{id}")
|
||||||
fun getDetailProduct (
|
fun getDetailProduct (
|
||||||
@Header("Authorization") token: String,
|
|
||||||
@Path("id") productId: Int
|
@Path("id") productId: Int
|
||||||
): Call<ProductResponse>
|
): Call<ProductResponse>
|
||||||
|
|
||||||
@GET("mystore")
|
@GET("mystore")
|
||||||
fun getStore (
|
fun getStore (): Call<StoreResponse>
|
||||||
@Header("Authorization") token: String = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzEsIm5hbWUiOiJhbHlhIiwiZW1haWwiOiJha3VuYmVsYWphci5hbHlhQGdtYWlsLmNvbSIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzM4NDg0OTc0LCJleHAiOjE3NDEwNzY5NzR9.0JyXJQ_6CKiZEi0gvk1gcn-0ILu3a9lOr3HqjhJXbBE"
|
|
||||||
): Call<StoreResponse>
|
|
||||||
}
|
}
|
@ -17,19 +17,15 @@ class ProductRepository(private val apiService: ApiService) {
|
|||||||
Log.d("ProductRepository", "Response message: ${response.message()}")
|
Log.d("ProductRepository", "Response message: ${response.message()}")
|
||||||
|
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
Result.success(response.body()?.products ?: emptyList())
|
// Return a Result.Success with the list of products
|
||||||
|
Result.Success(response.body()?.products ?: emptyList())
|
||||||
} else {
|
} else {
|
||||||
Result.failure(Exception("Failed to fetch products"))
|
// Return a Result.Error with a custom Exception
|
||||||
|
Result.Error(Exception("Failed to fetch products. Code: ${response.code()}"))
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Result.failure(e)
|
// Return a Result.Error with the exception caught
|
||||||
|
Result.Error(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
|
|
||||||
}
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.alya.ecommerce_serang.data.repository
|
||||||
|
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.OtpRequest
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.OtpResponse
|
||||||
|
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
|
||||||
|
|
||||||
|
class UserRepository(private val apiService: ApiService) {
|
||||||
|
|
||||||
|
suspend fun requestOtpRep(email: String): OtpResponse {
|
||||||
|
|
||||||
|
// fun requestOtpRep(email: String): Result<String> {
|
||||||
|
|
||||||
|
return apiService.getOTP(OtpRequest(email))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun registerUser(request: RegisterRequest): String {
|
||||||
|
val response = apiService.register(request) // API call
|
||||||
|
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
val responseBody = response.body() ?: throw Exception("Empty response body")
|
||||||
|
return responseBody.message // Get the message from RegisterResponse
|
||||||
|
} else {
|
||||||
|
throw Exception("Registration failed: ${response.errorBody()?.string()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class Result<out T> {
|
||||||
|
data class Success<out T>(val data: T) : Result<T>()
|
||||||
|
data class Error(val exception: Throwable) : Result<Nothing>()
|
||||||
|
object Loading : Result<Nothing>()
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.alya.ecommerce_serang.ui.auth
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import com.alya.ecommerce_serang.R
|
||||||
|
|
||||||
|
class LoginActivity : AppCompatActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enableEdgeToEdge()
|
||||||
|
setContentView(R.layout.activity_login)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.alya.ecommerce_serang.ui.auth
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.alya.ecommerce_serang.R
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
|
||||||
|
class OtpBottomSheetDialog(
|
||||||
|
private val userData: RegisterRequest, // Store user data
|
||||||
|
private val onRegister: (RegisterRequest) -> Unit)
|
||||||
|
: BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
val view = inflater.inflate(R.layout.dialog_otp, container, false)
|
||||||
|
|
||||||
|
val etOtp = view.findViewById<EditText>(R.id.etOtp)
|
||||||
|
val btnSubmit = view.findViewById<Button>(R.id.btnSubmit)
|
||||||
|
|
||||||
|
btnSubmit.setOnClickListener {
|
||||||
|
val otp = etOtp.text.toString()
|
||||||
|
if (otp.isNotEmpty()) {
|
||||||
|
val updatedUserData = userData.copy(otp = otp) // Add OTP to userData
|
||||||
|
onRegister(updatedUserData) // Send full data to ViewModel
|
||||||
|
dismiss() // Close dialog
|
||||||
|
} else {
|
||||||
|
Toast.makeText(requireContext(), "Please enter OTP", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
// override fun getTheme(): Int {
|
||||||
|
// return R.style.BottomSheetDialogTheme // Optional: Customize style
|
||||||
|
// }
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
package com.alya.ecommerce_serang.ui.auth
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
|
||||||
|
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||||
|
import com.alya.ecommerce_serang.data.repository.Result
|
||||||
|
import com.alya.ecommerce_serang.data.repository.UserRepository
|
||||||
|
import com.alya.ecommerce_serang.databinding.ActivityRegisterBinding
|
||||||
|
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||||
|
|
||||||
|
class RegisterActivity : AppCompatActivity() {
|
||||||
|
private lateinit var binding: ActivityRegisterBinding
|
||||||
|
private val registerViewModel: RegisterViewModel by viewModels{
|
||||||
|
BaseViewModelFactory {
|
||||||
|
val apiService = ApiConfig.getUnauthenticatedApiService()
|
||||||
|
val userRepository = UserRepository(apiService)
|
||||||
|
RegisterViewModel(userRepository)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enableEdgeToEdge()
|
||||||
|
binding = ActivityRegisterBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
// Observe OTP state
|
||||||
|
observeOtpState()
|
||||||
|
|
||||||
|
// Observe Register state
|
||||||
|
observeRegisterState()
|
||||||
|
|
||||||
|
binding.btnSignup.setOnClickListener {
|
||||||
|
// Retrieve values inside the click listener (so we get latest input)
|
||||||
|
val birthDate = binding.etBirthDate.text.toString()
|
||||||
|
val email = binding.etEmail.text.toString()
|
||||||
|
val password = binding.etPassword.text.toString()
|
||||||
|
val phone = binding.etNumberPhone.text.toString()
|
||||||
|
val username = binding.etUsername.text.toString()
|
||||||
|
val name = binding.etFullname.text.toString()
|
||||||
|
val image = "not yet"
|
||||||
|
|
||||||
|
val userData = RegisterRequest(name, email, password, username, phone, birthDate, image)
|
||||||
|
|
||||||
|
Log.d("RegisterActivity", "Requesting OTP for email: $email")
|
||||||
|
|
||||||
|
// Request OTP and wait for success before showing dialog
|
||||||
|
registerViewModel.requestOtp(userData.email.toString())
|
||||||
|
|
||||||
|
// Observe OTP state and show OTP dialog only when successful
|
||||||
|
registerViewModel.otpState.observe(this) { result ->
|
||||||
|
when (result) {
|
||||||
|
is Result.Success -> {
|
||||||
|
Log.d("RegisterActivity", "OTP sent successfully. Showing OTP dialog.")
|
||||||
|
// Show OTP dialog after OTP is successfully sent
|
||||||
|
val otpBottomSheet = OtpBottomSheetDialog(userData) { fullUserData ->
|
||||||
|
Log.d("RegisterActivity", "OTP entered successfully. Proceeding with registration.")
|
||||||
|
registerViewModel.registerUser(fullUserData) // Send complete data
|
||||||
|
}
|
||||||
|
otpBottomSheet.show(supportFragmentManager, "OtpBottomSheet")
|
||||||
|
}
|
||||||
|
is Result.Error -> {
|
||||||
|
// Show error message if OTP request fails
|
||||||
|
Log.e("RegisterActivity", "Failed to request OTP: ${result.exception.message}")
|
||||||
|
Toast.makeText(this, "Failed to request OTP: ${result.exception.message}", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
is Result.Loading -> {
|
||||||
|
// Optional: Show loading indicator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeOtpState() {
|
||||||
|
registerViewModel.otpState.observe(this) { result ->
|
||||||
|
when (result) {
|
||||||
|
is Result.Loading -> {
|
||||||
|
// Show loading indicator
|
||||||
|
binding.progressBarOtp.visibility = android.view.View.VISIBLE
|
||||||
|
}
|
||||||
|
is Result.Success -> {
|
||||||
|
// Hide loading indicator and show success message
|
||||||
|
binding.progressBarOtp.visibility = android.view.View.GONE
|
||||||
|
// Toast.makeText(this@RegisterActivity, result.data, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
is Result.Error -> {
|
||||||
|
// Hide loading indicator and show error message
|
||||||
|
binding.progressBarOtp.visibility = android.view.View.GONE
|
||||||
|
Toast.makeText(this, "OTP Request Failed: ${result.exception.message}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeRegisterState() {
|
||||||
|
registerViewModel.registerState.observe(this) { result ->
|
||||||
|
when (result) {
|
||||||
|
is Result.Loading -> {
|
||||||
|
// Show loading indicator for registration
|
||||||
|
binding.progressBarRegister.visibility = android.view.View.VISIBLE
|
||||||
|
}
|
||||||
|
is Result.Success -> {
|
||||||
|
// Hide loading indicator and show success message
|
||||||
|
binding.progressBarRegister.visibility = android.view.View.GONE
|
||||||
|
Toast.makeText(this, result.data, Toast.LENGTH_SHORT).show()
|
||||||
|
// Navigate to another screen if needed
|
||||||
|
}
|
||||||
|
is com.alya.ecommerce_serang.data.repository.Result.Error -> {
|
||||||
|
// Hide loading indicator and show error message
|
||||||
|
binding.progressBarRegister.visibility = android.view.View.GONE
|
||||||
|
Toast.makeText(this, "Registration Failed: ${result.exception.message}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
package com.alya.ecommerce_serang.ui.auth
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
|
||||||
|
import com.alya.ecommerce_serang.data.api.response.OtpResponse
|
||||||
|
import com.alya.ecommerce_serang.data.repository.Result
|
||||||
|
import com.alya.ecommerce_serang.data.repository.UserRepository
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class RegisterViewModel(private val repository: UserRepository) : ViewModel() {
|
||||||
|
|
||||||
|
// MutableLiveData for handling register state (Loading, Success, or Error)
|
||||||
|
private val _registerState = MutableLiveData<Result<String>>()
|
||||||
|
val registerState: LiveData<Result<String>> = _registerState
|
||||||
|
|
||||||
|
// MutableLiveData for handling OTP request state
|
||||||
|
private val _otpState = MutableLiveData<Result<Unit>>()
|
||||||
|
val otpState: LiveData<Result<Unit>> = _otpState
|
||||||
|
|
||||||
|
// MutableLiveData to store messages from API responses
|
||||||
|
private val _message = MutableLiveData<String>()
|
||||||
|
val message: LiveData<String> = _message
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to request OTP by sending an email to the API.
|
||||||
|
* - It sets the OTP state to `Loading` before calling the repository.
|
||||||
|
* - If successful, it updates `_message` with the response message and signals success.
|
||||||
|
* - If an error occurs, it updates `_otpState` with `Result.Error` and logs the failure.
|
||||||
|
*/
|
||||||
|
fun requestOtp(email: String) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
_otpState.value = Result.Loading // Indicating API call in progress
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Call the repository function to request OTP
|
||||||
|
val response: OtpResponse = repository.requestOtpRep(email)
|
||||||
|
|
||||||
|
// Log and store success message
|
||||||
|
Log.d("RegisterViewModel", "OTP Response: ${response.message}")
|
||||||
|
_message.value = response.message // Store the message for UI feedback
|
||||||
|
|
||||||
|
// Update state to indicate success
|
||||||
|
_otpState.value = Result.Success(Unit)
|
||||||
|
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
// Handle any errors and update state
|
||||||
|
_otpState.value = Result.Error(exception)
|
||||||
|
_message.value = exception.localizedMessage ?: "Failed to request OTP"
|
||||||
|
|
||||||
|
// Log the error for debugging
|
||||||
|
Log.e("RegisterViewModel", "OTP request failed for: $email", exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to register a new user.
|
||||||
|
* - It first sets `_registerState` to `Loading` to indicate the process is starting.
|
||||||
|
* - Calls the repository function to handle user registration.
|
||||||
|
* - If successful, it updates `_message` and signals success with the response message.
|
||||||
|
* - If an error occurs, it updates `_registerState` with `Result.Error` and logs the failure.
|
||||||
|
*/
|
||||||
|
fun registerUser(request: RegisterRequest) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
_registerState.value = Result.Loading // Indicating API call in progress
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Call repository function to register the user
|
||||||
|
val message = repository.registerUser(request)
|
||||||
|
|
||||||
|
// Store and display success message
|
||||||
|
_message.value = message
|
||||||
|
_registerState.value = Result.Success(message) // Store success result
|
||||||
|
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
// Handle any errors and update state
|
||||||
|
_registerState.value = Result.Error(exception)
|
||||||
|
_message.value = exception.localizedMessage ?: "Registration failed"
|
||||||
|
|
||||||
|
// Log the error for debugging
|
||||||
|
Log.e("RegisterViewModel", "User registration failed", exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -6,7 +6,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.alya.ecommerce_serang.R
|
import com.alya.ecommerce_serang.R
|
||||||
@ -16,6 +16,7 @@ import com.alya.ecommerce_serang.data.repository.ProductRepository
|
|||||||
import com.alya.ecommerce_serang.databinding.FragmentHomeBinding
|
import com.alya.ecommerce_serang.databinding.FragmentHomeBinding
|
||||||
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
|
||||||
import com.alya.ecommerce_serang.utils.HorizontalMarginItemDecoration
|
import com.alya.ecommerce_serang.utils.HorizontalMarginItemDecoration
|
||||||
|
import com.alya.ecommerce_serang.utils.SessionManager
|
||||||
import com.alya.ecommerce_serang.utils.setLightStatusBar
|
import com.alya.ecommerce_serang.utils.setLightStatusBar
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ -24,8 +25,15 @@ class HomeFragment : Fragment() {
|
|||||||
|
|
||||||
private var _binding: FragmentHomeBinding? = null
|
private var _binding: FragmentHomeBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
private lateinit var viewModel: HomeViewModel
|
private val viewModel: HomeViewModel by viewModels {
|
||||||
|
BaseViewModelFactory {
|
||||||
|
val apiService = ApiConfig.getApiService(sessionManager)
|
||||||
|
val productRepository = ProductRepository(apiService)
|
||||||
|
HomeViewModel(productRepository)
|
||||||
|
}
|
||||||
|
}
|
||||||
private var productAdapter: HorizontalProductAdapter? = null
|
private var productAdapter: HorizontalProductAdapter? = null
|
||||||
|
private lateinit var sessionManager: SessionManager
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
@ -33,21 +41,14 @@ class HomeFragment : Fragment() {
|
|||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
_binding = FragmentHomeBinding.inflate(inflater, container, false)
|
_binding = FragmentHomeBinding.inflate(inflater, container, false)
|
||||||
|
sessionManager = SessionManager(requireContext()) // Initialize SessionManager
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
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()
|
initUi()
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
observeData()
|
observeData()
|
||||||
@ -124,10 +125,7 @@ class HomeFragment : Fragment() {
|
|||||||
|
|
||||||
|
|
||||||
private fun handleProductClick(product: ProductsItem) {
|
private fun handleProductClick(product: ProductsItem) {
|
||||||
// Navigate to product detail
|
|
||||||
// findNavController().navigate(
|
|
||||||
// HomeFragmentDirections.actionHomeToDetail(product.id)
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package com.alya.ecommerce_serang.ui.home
|
package com.alya.ecommerce_serang.ui.home
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
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.response.ProductsItem
|
||||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
|
||||||
import com.alya.ecommerce_serang.data.repository.ProductRepository
|
import com.alya.ecommerce_serang.data.repository.ProductRepository
|
||||||
|
import com.alya.ecommerce_serang.data.repository.Result
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@ -18,8 +16,6 @@ class HomeViewModel (
|
|||||||
): ViewModel() {
|
): ViewModel() {
|
||||||
private val _uiState = MutableStateFlow<HomeUiState>(HomeUiState.Loading)
|
private val _uiState = MutableStateFlow<HomeUiState>(HomeUiState.Loading)
|
||||||
val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()
|
val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()
|
||||||
val home = MutableLiveData<AllProductResponse?>(null)
|
|
||||||
constructor() : this(ProductRepository(ApiConfig.getApiService()))
|
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -29,28 +25,30 @@ class HomeViewModel (
|
|||||||
private fun loadProducts() {
|
private fun loadProducts() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_uiState.value = HomeUiState.Loading
|
_uiState.value = HomeUiState.Loading
|
||||||
productRepository.getAllProducts()
|
|
||||||
.onSuccess { products ->
|
productRepository.getAllProducts().let { result ->
|
||||||
_uiState.value = HomeUiState.Success(products)
|
when (result) {
|
||||||
}
|
is Result.Success -> {
|
||||||
.onFailure { error ->
|
// Handle the success case
|
||||||
_uiState.value = HomeUiState.Error(error.message ?: "Unknown error")
|
_uiState.value = HomeUiState.Success(result.data) // result.data contains the list of products
|
||||||
Log.e("ProductViewModel", "Products fetch failed", error)
|
}
|
||||||
|
is com.alya.ecommerce_serang.data.repository.Result.Error -> {
|
||||||
|
// Handle the error case
|
||||||
|
_uiState.value = HomeUiState.Error(result.exception.message ?: "Unknown error")
|
||||||
|
Log.e("HomeViewModel", "Failed to fetch products", result.exception)
|
||||||
|
}
|
||||||
|
com.alya.ecommerce_serang.data.repository.Result.Loading -> {
|
||||||
|
// Optionally handle the loading state if needed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun retry() {
|
fun retry() {
|
||||||
loadProducts()
|
loadProducts()
|
||||||
}
|
}
|
||||||
|
|
||||||
// fun toggleWishlist(product: Product) = viewModelScope.launch {
|
|
||||||
// try {
|
|
||||||
// productRepository.toggleWishlist(product.id,product.wishlist)
|
|
||||||
// }catch (e:Exception){
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class HomeUiState {
|
sealed class HomeUiState {
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.alya.ecommerce_serang.ui.profile
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import com.alya.ecommerce_serang.R
|
||||||
|
|
||||||
|
class DetailProfileActivity : AppCompatActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enableEdgeToEdge()
|
||||||
|
setContentView(R.layout.activity_detail_profile)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,16 +5,13 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import com.alya.ecommerce_serang.databinding.FragmentProfileBinding
|
||||||
import com.alya.ecommerce_serang.R
|
|
||||||
|
|
||||||
class ProfileFragment : Fragment() {
|
class ProfileFragment : Fragment() {
|
||||||
|
|
||||||
companion object {
|
private var _binding: FragmentProfileBinding? = null
|
||||||
fun newInstance() = ProfileFragment()
|
private val binding get() = _binding!!
|
||||||
}
|
private lateinit var viewModel: ProfileViewModel
|
||||||
|
|
||||||
private val viewModel: ProfileViewModel by viewModels()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -26,6 +23,7 @@ class ProfileFragment : Fragment() {
|
|||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
return inflater.inflate(R.layout.fragment_profile, container, false)
|
_binding = FragmentProfileBinding.inflate(inflater, container, false)
|
||||||
|
return binding.root
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.alya.ecommerce_serang.utils
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class AuthInterceptor(private val sessionManager: SessionManager) : Interceptor {
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val token = sessionManager.getToken()
|
||||||
|
Log.d("AuthInterceptor", "Token: $token")
|
||||||
|
val request = if (!token.isNullOrEmpty()) {
|
||||||
|
chain.request().newBuilder()
|
||||||
|
.addHeader("Authorization", "Bearer $token")
|
||||||
|
.build()
|
||||||
|
} else {
|
||||||
|
chain.request()
|
||||||
|
}
|
||||||
|
|
||||||
|
return chain.proceed(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.alya.ecommerce_serang.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
class SessionManager(context: Context) {
|
||||||
|
private var sharedPreferences: SharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val PREFS_NAME = "app_prefs"
|
||||||
|
private const val USER_TOKEN = "user_token"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveAuthToken(token: String) {
|
||||||
|
val editor = sharedPreferences.edit()
|
||||||
|
editor.putString(USER_TOKEN, token)
|
||||||
|
editor.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getToken(): String? {
|
||||||
|
val token = sharedPreferences.getString("auth_token", null)
|
||||||
|
Log.d("SessionManager", "Retrieved token: $token")
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearToken() {
|
||||||
|
val editor = sharedPreferences.edit()
|
||||||
|
editor.remove(USER_TOKEN)
|
||||||
|
editor.apply()
|
||||||
|
}
|
||||||
|
}
|
5
app/src/main/res/drawable/ic_back_24.xml
Normal file
5
app/src/main/res/drawable/ic_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="#211E1E" 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>
|
160
app/src/main/res/layout/activity_detail_profile.xml
Normal file
160
app/src/main/res/layout/activity_detail_profile.xml
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<?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"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/white"
|
||||||
|
tools:context=".ui.profile.DetailProfileActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/top_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_back"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_back_24"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_profile_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="Profil"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:fontFamily="@font/dmsans_bold"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:gravity="center"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/card_profile"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="4dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/top_title"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
|
android:id="@+id/profile_image"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:src="@drawable/baseline_account_circle_24"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_ubah_profil"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Ubah Profil"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/profile_image"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/til_nama"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/card_profile">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Nama"
|
||||||
|
android:text="@string/users_name"
|
||||||
|
android:enabled="false"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/til_username"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/til_nama">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Username"
|
||||||
|
android:text="@string/username_profile"
|
||||||
|
android:enabled="false"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/til_email"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/til_username">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Email"
|
||||||
|
android:text="@string/users_email"
|
||||||
|
android:enabled="false"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/til_nomor_handphone"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/til_email">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Nomor Handphone"
|
||||||
|
android:text="@string/phone_number"
|
||||||
|
android:enabled="false"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/til_tanggal_lahir"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/til_nomor_handphone">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Tanggal Lahir"
|
||||||
|
android:text="@string/date_birth"
|
||||||
|
android:enabled="false"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
103
app/src/main/res/layout/activity_login.xml
Normal file
103
app/src/main/res/layout/activity_login.xml
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout 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:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginVertical="16dp"
|
||||||
|
tools:context=".ui.auth.LoginActivity">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/login"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:layout_marginBottom="24dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/login_email"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/et_login_email"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/hint_login_email"
|
||||||
|
android:inputType="textEmailAddress"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/password"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
app:passwordToggleEnabled="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/et_login_password"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/hint_login_password"
|
||||||
|
android:inputType="textPassword"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_forgetPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/forget_password"
|
||||||
|
android:textColor="@android:color/holo_red_light"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/login"
|
||||||
|
app:cornerRadius="8dp"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/no_account"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/signup"
|
||||||
|
android:textColor="@color/blue1"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
250
app/src/main/res/layout/activity_register.xml
Normal file
250
app/src/main/res/layout/activity_register.xml
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView 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:background="@color/white"
|
||||||
|
tools:context=".ui.auth.RegisterActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginVertical="16dp"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Buat Akun"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:layout_marginBottom="24dp"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/email"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/et_email"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/hint_email"
|
||||||
|
android:inputType="textEmailAddress"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/username"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/et_username"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/hint_username"
|
||||||
|
android:inputType="text"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/full_name"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/et_fullname"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/hint_fullname"
|
||||||
|
android:inputType="text"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/password"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
app:passwordToggleEnabled="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/et_password"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/hint_password"
|
||||||
|
android:inputType="textPassword"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/confirm_password"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
app:passwordToggleEnabled="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/et_confirm_password"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/hint_confirmation_password"
|
||||||
|
android:inputType="textPassword"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/birth_date"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu">
|
||||||
|
|
||||||
|
<AutoCompleteTextView
|
||||||
|
android:id="@+id/et_birth_date"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/hint_birth_date"
|
||||||
|
android:inputType="date"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/gender"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu">
|
||||||
|
|
||||||
|
<AutoCompleteTextView
|
||||||
|
android:id="@+id/et_gender"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/hint_gender"
|
||||||
|
android:inputType="textFilter"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/number_phone"/>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/et_number_phone"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/hint_number_phone"
|
||||||
|
android:inputType="phone"/>
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_signup"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/signup"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:cornerRadius="8dp"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/no_account"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_login_alt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/login"
|
||||||
|
android:textColor="@color/blue1"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBarOtp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
|
<!-- ProgressBar for Registration -->
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBarRegister"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
35
app/src/main/res/layout/dialog_otp.xml
Normal file
35
app/src/main/res/layout/dialog_otp.xml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="@android:color/white">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/enter_otp"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etOtp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Enter OTP"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLength="6"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="8dp"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnSubmit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Submit"
|
||||||
|
android:layout_marginTop="12dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -20,4 +20,14 @@
|
|||||||
android:name="com.alya.ecommerce_serang.ui.chat.ChatFragment"
|
android:name="com.alya.ecommerce_serang.ui.chat.ChatFragment"
|
||||||
android:label="fragment_chat"
|
android:label="fragment_chat"
|
||||||
tools:layout="@layout/fragment_chat" />
|
tools:layout="@layout/fragment_chat" />
|
||||||
|
<activity
|
||||||
|
android:id="@+id/registerActivity"
|
||||||
|
android:name="com.alya.ecommerce_serang.ui.auth.RegisterActivity"
|
||||||
|
android:label="activity_register"
|
||||||
|
tools:layout="@layout/activity_register" />
|
||||||
|
<activity
|
||||||
|
android:id="@+id/loginActivity"
|
||||||
|
android:name="com.alya.ecommerce_serang.ui.auth.LoginActivity"
|
||||||
|
android:label="activity_login"
|
||||||
|
tools:layout="@layout/activity_login" />
|
||||||
</navigation>
|
</navigation>
|
@ -17,4 +17,33 @@
|
|||||||
<string name="delivery">Dikirim</string>
|
<string name="delivery">Dikirim</string>
|
||||||
<string name="packages">Dikemas</string>
|
<string name="packages">Dikemas</string>
|
||||||
<string name="waiting_payment">Belum Dibayar</string>
|
<string name="waiting_payment">Belum Dibayar</string>
|
||||||
|
<string name="users_email">youremail@gmail.com</string>
|
||||||
|
<string name="phone_number">123456789123</string>
|
||||||
|
<string name="date_birth">24 Oktober 2024</string>
|
||||||
|
<string name="username_profile">User123</string>
|
||||||
|
<string name="users_name">User</string>
|
||||||
|
<string name="hint_confirmation_password">Konfirmasi Kata Sandi</string>
|
||||||
|
<string name="email">Email</string>
|
||||||
|
<string name="hint_email">Masukkan Email</string>
|
||||||
|
<string name="username">Nama Pengguna</string>
|
||||||
|
<string name="hint_username">Masukkan Nama Pengguna</string>
|
||||||
|
<string name="full_name">Nama Lengkap</string>
|
||||||
|
<string name="hint_fullname">Masukkan Nama Lengkap</string>
|
||||||
|
<string name="password">Kata Sandi</string>
|
||||||
|
<string name="hint_password">Masukkan Kata Sandi Baru</string>
|
||||||
|
<string name="confirm_password">Konfirmasi Kata Sandi</string>
|
||||||
|
<string name="birth_date">Tanggal Lahir</string>
|
||||||
|
<string name="hint_birth_date">Pilih Tanggal Lahir</string>
|
||||||
|
<string name="gender">Jenis Kelamin</string>
|
||||||
|
<string name="hint_gender">Pilih Jenis Kelamin</string>
|
||||||
|
<string name="number_phone">Nomor Telepon</string>
|
||||||
|
<string name="hint_number_phone">Masukkan Nomor Telepon</string>
|
||||||
|
<string name="no_account">Belum punya akun?</string>
|
||||||
|
<string name="login">Masuk</string>
|
||||||
|
<string name="signup">Daftar</string>
|
||||||
|
<string name="login_email">Email atau Nomor Telepon</string>
|
||||||
|
<string name="hint_login_email">Email atau No. Handphone</string>
|
||||||
|
<string name="hint_login_password">Kata Sandi</string>
|
||||||
|
<string name="forget_password">Lupa Kata Sandi?</string>
|
||||||
|
<string name="enter_otp">Masukkan Kode OTP</string>
|
||||||
</resources>
|
</resources>
|
Reference in New Issue
Block a user