Compare commits

1 Commits

Author SHA1 Message Date
4d24673107 Add files via upload 2025-08-21 13:39:03 +07:00
64 changed files with 660 additions and 1748 deletions

View File

@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-08-17T17:32:55.497700100Z">
<DropdownSelection timestamp="2025-05-08T14:50:55.425322500Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\Gracia Hotmauli\.android\avd\Pixel_9_2.avd" />
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\Gracia Hotmauli\.android\avd\Pixel_8_2_2.avd" />
</handle>
</Target>
</DropdownSelection>

View File

@ -124,7 +124,4 @@ dependencies {
implementation(platform("com.google.firebase:firebase-bom:33.13.0"))
implementation("com.google.firebase:firebase-analytics")
implementation("com.google.firebase:firebase-messaging-ktx")
//Splash screen
implementation("androidx.core:core-splashscreen:1.0.0")
}

View File

@ -29,9 +29,6 @@
android:theme="@style/Theme.Ecommerce_serang"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".ui.profile.ChangePasswordActivity"
android:exported="false" />
<activity
android:name=".ui.auth.ResetPassActivity"
android:exported="false" />

View File

@ -10,6 +10,9 @@ data class Store(
@field:SerializedName("store_status")
val storeStatus: String,
@field:SerializedName("sppirt")
val sppirt: String,
@field:SerializedName("user_name")
val userName: String,
@ -34,6 +37,9 @@ data class Store(
@field:SerializedName("user_phone")
val userPhone: String,
@field:SerializedName("halal")
val halal: String,
@field:SerializedName("id")
val id: Int,

View File

@ -1,13 +1,18 @@
package com.alya.ecommerce_serang.data.api.response.store
import com.alya.ecommerce_serang.data.api.dto.Store
import com.alya.ecommerce_serang.data.api.response.store.profile.Payment
import com.alya.ecommerce_serang.data.api.response.store.profile.Shipping
import com.google.gson.annotations.SerializedName
data class StoreResponse(
val message: String,
val store: Store,
val shipping: List<Shipping> = emptyList(),
val payment: List<Payment> = emptyList()
val store: Store
)
data class Store(
@SerializedName("store_id") val storeId: Int,
@SerializedName("store_status") val storeStatus: String,
@SerializedName("store_name") val storeName: String,
@SerializedName("user_name") val userName: String,
val email: String,
@SerializedName("user_phone") val userPhone: String,
val balance: String
)

View File

@ -4,7 +4,7 @@ import android.util.Log
import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.alya.ecommerce_serang.data.api.dto.Store
import com.alya.ecommerce_serang.data.api.response.auth.ListStoreTypeResponse
import com.alya.ecommerce_serang.data.api.response.store.StoreResponse
import com.alya.ecommerce_serang.data.api.response.customer.product.StoreResponse
import com.alya.ecommerce_serang.data.api.response.store.profile.StoreDataResponse
import com.alya.ecommerce_serang.data.api.response.store.sells.OrderListResponse
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
@ -15,13 +15,13 @@ import retrofit2.Response
import java.io.IOException
class MyStoreRepository(private val apiService: ApiService) {
suspend fun fetchMyStoreProfile(): Result<StoreResponse?> {
suspend fun fetchMyStoreProfile(): Result<Store?> {
return try {
val response = apiService.getMyStoreData()
val response = apiService.getStore()
if (response.isSuccessful) {
val storeResponse = response.body()
Result.Success(storeResponse)
val storeResponse: StoreResponse? = response.body()
Result.Success(storeResponse?.store)
} else {
val errorMessage = response.errorBody()?.string() ?: "Unknown API error"
Log.e("MyStoreRepository", "Error: $errorMessage")

View File

@ -72,7 +72,7 @@ class LoginActivity : AppCompatActivity() {
val password = binding.etLoginPassword.text.toString()
if (email.isEmpty() || password.isEmpty()) {
Toast.makeText(this, "Mohon masukkan email atau password dengan benar", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Please fill in all fields", Toast.LENGTH_SHORT).show()
} else {
loginViewModel.login(email, password)
}
@ -100,14 +100,14 @@ class LoginActivity : AppCompatActivity() {
retrieveFCMToken()
// sessionManager.saveUserId(response.userId)
Toast.makeText(this, "Berhasil masuk", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Login Successful", Toast.LENGTH_SHORT).show()
startActivity(Intent(this, MainActivity::class.java))
finish()
}
is com.alya.ecommerce_serang.data.repository.Result.Error -> {
Log.e("LoginActivity", "Login Failed: ${result.exception.message}")
Toast.makeText(this, "Gagal masuk", Toast.LENGTH_LONG).show()
Toast.makeText(this, "Login Failed: ${result.exception.message}", Toast.LENGTH_LONG).show()
}
is Result.Loading -> {
// Show loading state

View File

@ -29,7 +29,7 @@ class OtpBottomSheetDialog(
onRegister(updatedUserData) // Send full data to ViewModel
dismiss() // Close dialog
} else {
Toast.makeText(requireContext(), "Silahkan masukkan kode OTP", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Please enter OTP", Toast.LENGTH_SHORT).show()
}
}
return view

View File

@ -86,72 +86,20 @@ class RegisterActivity : AppCompatActivity() {
}
}
// In RegisterActivity, add debug to navigateToStep:
// navigate step register in fragment
fun navigateToStep(step: Int, userData: RegisterRequest?) {
Log.d("RegisterActivity", "=== NAVIGATE TO STEP START ===")
Log.d("RegisterActivity", "Target step: $step")
Log.d("RegisterActivity", "Current fragment count: ${supportFragmentManager.fragments.size}")
Log.d("RegisterActivity", "UserData: ${userData?.email}")
Log.d("RegisterActivity", "Navigation called from:")
Thread.currentThread().stackTrace.take(10).forEach { element ->
Log.d("RegisterActivity", " at ${element.className}.${element.methodName}(${element.fileName}:${element.lineNumber})")
val fragment = when (step) {
1 -> RegisterStep1Fragment.newInstance()
2 -> RegisterStep2Fragment.newInstance(userData)
3 -> RegisterStep3Fragment.newInstance()
else -> null
}
try {
val fragment = when (step) {
1 -> {
Log.d("RegisterActivity", "Creating RegisterStep1Fragment")
RegisterStep1Fragment.newInstance()
}
2 -> {
Log.d("RegisterActivity", "Creating RegisterStep2Fragment")
RegisterStep2Fragment.newInstance(userData)
}
3 -> {
Log.d("RegisterActivity", "Creating RegisterStep3Fragment")
RegisterStep3Fragment.newInstance()
}
else -> {
Log.e("RegisterActivity", "Invalid step: $step")
return
}
}
Log.d("RegisterActivity", "Fragment created, starting transaction")
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, fragment)
Log.d("RegisterActivity", "About to commit transaction")
transaction.commit()
Log.d("RegisterActivity", "Transaction committed")
// Update ViewModel step
registerViewModel.setStep(step)
Log.d("RegisterActivity", "ViewModel step updated to: $step")
} catch (e: Exception) {
Log.e("RegisterActivity", "Exception in navigateToStep: ${e.message}", e)
e.printStackTrace()
}
Log.d("RegisterActivity", "=== NAVIGATE TO STEP END ===")
}
// Handle Android back button - close activity or go to step 1
override fun onBackPressed() {
val currentStep = registerViewModel.currentStep.value ?: 1
if (currentStep == 1) {
// On step 1, exit the activity
super.onBackPressed()
} else {
// On other steps, go back to step 1
navigateToStep(1, null)
fragment?.let {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, it)
.addToBackStack(null)
.commit()
}
}
}

View File

@ -111,7 +111,7 @@ class ResetPassActivity : AppCompatActivity() {
}
private fun handleError(errorMessage: String) {
Log.e(TAG, "Error: $errorMessage")
Toast.makeText(this, "Error: $errorMessage", Toast.LENGTH_LONG).show()
// Optionally show error dialog
AlertDialog.Builder(this)

View File

@ -155,20 +155,19 @@ class RegisterStep1Fragment : Fragment() {
"email" -> {
isEmailValid = isValid
if (!isValid) {
Toast.makeText(requireContext(), "Email sudah digunakan. Gunakan email lainnya.", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Email is already registered", Toast.LENGTH_SHORT).show()
}
}
"phone" -> {
isPhoneValid = isValid
if (!isValid) {
Toast.makeText(requireContext(), "Nomor handphone sudah digunakan. Gunakan nomor lainnya. ", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Phone number is already registered", Toast.LENGTH_SHORT).show()
}
}
}
}
is com.alya.ecommerce_serang.data.repository.Result.Error -> {
Toast.makeText(requireContext(), "Gagal melakukan validasi", Toast.LENGTH_SHORT).show()
Log.e(TAG, "Validation failed: ${result.exception.message}")
Toast.makeText(requireContext(), "Validation failed: ${result.exception.message}", Toast.LENGTH_SHORT).show()
}
}
}
@ -201,8 +200,7 @@ class RegisterStep1Fragment : Fragment() {
is Result.Error -> {
binding.progressBar.visibility = View.GONE
binding.btnNext.isEnabled = true
Log.e(TAG, "OTP Request Failed: ${result.exception.message}")
Toast.makeText(requireContext(), "Gagal mendapatkan OTP. Kirim ulang OTP", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "OTP Request Failed: ${result.exception.message}", Toast.LENGTH_SHORT).show()
}
}
}
@ -231,13 +229,13 @@ class RegisterStep1Fragment : Fragment() {
// Check if all fields are filled
if (email.isEmpty() || password.isEmpty() || confirmPassword.isEmpty() || phone.isEmpty() ||
username.isEmpty() || fullName.isEmpty() || birthDate.isEmpty()) {
Toast.makeText(requireContext(), "Silahkan lengkapi seluruh isian", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Please fill all required fields", Toast.LENGTH_SHORT).show()
return
}
// Check if passwords match
if (password != confirmPassword) {
Toast.makeText(requireContext(), "Konfirmasi kata sandi tidak sesua. Periksa kembali", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Passwords do not match", Toast.LENGTH_SHORT).show()
return
}
@ -255,7 +253,7 @@ class RegisterStep1Fragment : Fragment() {
if (isEmailValid && isPhoneValid) {
requestOtp(email)
} else {
Toast.makeText(requireContext(), "Silahkan perbaiki data yang dimasukkan", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "Please fix validation errors before proceeding", Toast.LENGTH_SHORT).show()
}
}

View File

@ -1,7 +1,5 @@
package com.alya.ecommerce_serang.ui.auth.fragments
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.CountDownTimer
@ -15,7 +13,6 @@ import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.dto.FcmReq
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.OrderRepository
@ -27,15 +24,11 @@ import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.SessionManager
import com.alya.ecommerce_serang.utils.viewmodel.RegisterViewModel
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.firebase.messaging.FirebaseMessaging
class RegisterStep2Fragment : Fragment() {
private var _binding: FragmentRegisterStep2Binding? = null
private val binding get() = _binding!!
private lateinit var sessionManager: SessionManager
private var countDownTimer: CountDownTimer? = null
private var timeRemaining = 30
private var isTimerRunning = false
// In RegisterStep2Fragment AND RegisterStep3Fragment:
private val registerViewModel: RegisterViewModel by activityViewModels {
@ -46,8 +39,8 @@ class RegisterStep2Fragment : Fragment() {
RegisterViewModel(userRepository, orderRepository, requireContext())
}
}
// private var countDownTimer: CountDownTimer? = null
// private var timeRemaining = 30 // 30 seconds cooldown for resend
private var countDownTimer: CountDownTimer? = null
private var timeRemaining = 30 // 30 seconds cooldown for resend
companion object {
@ -119,20 +112,6 @@ class RegisterStep2Fragment : Fragment() {
observeRegistrationState()
observeLoginState()
Log.d(TAG, "Registration and login state observers set up")
binding.btnBack.setOnClickListener {
Log.d(TAG, "Back button clicked - cleaning up timer and going to step 1")
// Stop the timer before navigating
stopTimer()
// Small delay to ensure timer is properly canceled
binding.root.postDelayed({
// (activity as? RegisterActivity)?.navigateToStep(1, null)
val intent = Intent(requireContext(), RegisterActivity::class.java)
startActivity(intent)
requireActivity().finish()
}, 100)
}
}
private fun verifyOtp(userData: RegisterRequest?) {
@ -150,6 +129,11 @@ class RegisterStep2Fragment : Fragment() {
Log.d(TAG, "Updating user data with OTP: $otp")
registerViewModel.updateUserData(updatedUserData)
// For demo purposes, we're just proceeding to Step 3
// In a real app, you would verify the OTP with the server first
// registerViewModel.setStep(3)
// (activity as? RegisterActivity)?.navigateToStep(3, updatedUserData)
registerViewModel.registerUser(updatedUserData)
} ?: Log.e(TAG, "userData is null, cannot proceed with verification")
}
@ -186,9 +170,37 @@ class RegisterStep2Fragment : Fragment() {
} ?: Log.e(TAG, "Cannot resend OTP: email is null")
}
private fun startResendCooldown() {
Log.d(TAG, "startResendCooldown called")
timeRemaining = 30
binding.tvResendOtp.isEnabled = false
binding.tvResendOtp.setTextColor(ContextCompat.getColor(requireContext(), R.color.soft_gray))
countDownTimer?.cancel()
countDownTimer = object : CountDownTimer(30000, 1000) {
override fun onTick(millisUntilFinished: Long) {
timeRemaining = (millisUntilFinished / 1000).toInt()
binding.tvTimer.text = "Kirim ulang OTP dalam waktu 00:${String.format("%02d", timeRemaining)}"
if (timeRemaining % 5 == 0) {
Log.d(TAG, "Cooldown remaining: $timeRemaining seconds")
}
}
override fun onFinish() {
Log.d(TAG, "Cooldown finished, enabling resend button")
binding.tvTimer.text = "Dapat mengirim ulang kode OTP"
binding.tvResendOtp.isEnabled = true
binding.tvResendOtp.setTextColor(ContextCompat.getColor(requireContext(), R.color.blue1))
timeRemaining = 0
}
}.start()
}
private fun observeRegistrationState() {
registerViewModel.message.observe(viewLifecycleOwner) { message ->
Log.d(TAG, "Message from server: $message")
// You can use the message here if needed, e.g., for showing in a specific UI element
// or for storing for later use
}
registerViewModel.registerState.observe(viewLifecycleOwner) { result ->
when (result) {
@ -238,8 +250,6 @@ class RegisterStep2Fragment : Fragment() {
// Save the token in fragment
val accessToken = result.data.accessToken
sessionManager.saveToken(accessToken)
retrieveFCMToken()
Log.d(TAG, "Token saved to SessionManager: $accessToken")
// Proceed to Step 3
@ -269,148 +279,9 @@ class RegisterStep2Fragment : Fragment() {
}
}
private fun retrieveFCMToken() {
FirebaseMessaging.getInstance().token
.addOnCompleteListener { task ->
if (!task.isSuccessful) {
Log.e(TAG, "Failed to get FCM token", task.exception)
return@addOnCompleteListener
}
val token = task.result
// tokenTes = token
Log.d(TAG, "FCM token retrieved: $token")
// Save token locally
val sharedPreferences = requireContext().getSharedPreferences("FCM_PREFS", Context.MODE_PRIVATE)
sharedPreferences.edit().putString("FCM_TOKEN", token).apply()
// Send to your server
sendTokenToServer(token)
}
}
private fun sendTokenToServer(token: String) {
Log.d(TAG, "Would send token to server: $token")
val tokenFcm=FcmReq(
fcmToken = token
)
registerViewModel.sendFcm(tokenFcm)
Log.d(TAG, "Sent token fcm: $token")
}
private fun startResendCooldown() {
Log.d(TAG, "startResendCooldown called")
// Cancel any existing timer first
stopTimer()
timeRemaining = 30
isTimerRunning = true
binding.tvResendOtp.isEnabled = false
binding.tvResendOtp.setTextColor(ContextCompat.getColor(requireContext(), R.color.soft_gray))
countDownTimer = object : CountDownTimer(30000, 1000) {
override fun onTick(millisUntilFinished: Long) {
if (!isTimerRunning) {
cancel()
return
}
timeRemaining = (millisUntilFinished / 1000).toInt()
// Check if fragment is still attached before updating UI
if (isAdded && _binding != null) {
binding.tvTimer.text = "Kirim ulang OTP dalam waktu 00:${String.format("%02d", timeRemaining)}"
if (timeRemaining % 5 == 0) {
Log.d(TAG, "Cooldown remaining: $timeRemaining seconds")
}
}
}
override fun onFinish() {
if (!isTimerRunning) return
Log.d(TAG, "Cooldown finished, enabling resend button")
// Check if fragment is still attached before updating UI
if (isAdded && _binding != null) {
binding.tvTimer.text = "Dapat mengirim ulang kode OTP"
binding.tvResendOtp.isEnabled = true
binding.tvResendOtp.setTextColor(ContextCompat.getColor(requireContext(), R.color.blue1))
timeRemaining = 0
}
isTimerRunning = false
}
}.start()
}
private fun stopTimer() {
Log.d(TAG, "stopTimer called")
isTimerRunning = false
countDownTimer?.cancel()
countDownTimer = null
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause - stopping timer")
stopTimer()
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop - stopping timer")
stopTimer()
}
override fun onDestroyView() {
Log.d(TAG, "onDestroyView - cleaning up")
super.onDestroyView()
// Ensure timer is stopped
stopTimer()
countDownTimer?.cancel()
_binding = null
}
override fun onDetach() {
super.onDetach()
Log.d(TAG, "onDetach - final cleanup")
stopTimer()
}
}
// override fun onDestroyView() {
// super.onDestroyView()
// countDownTimer?.cancel()
// _binding = null
// }
// private fun startResendCooldown() {
// Log.d(TAG, "startResendCooldown called")
// timeRemaining = 30
// binding.tvResendOtp.isEnabled = false
// binding.tvResendOtp.setTextColor(ContextCompat.getColor(requireContext(), R.color.soft_gray))
//
// countDownTimer?.cancel()
// countDownTimer = object : CountDownTimer(30000, 1000) {
// override fun onTick(millisUntilFinished: Long) {
// timeRemaining = (millisUntilFinished / 1000).toInt()
// binding.tvTimer.text = "Kirim ulang OTP dalam waktu 00:${String.format("%02d", timeRemaining)}"
// if (timeRemaining % 5 == 0) {
// Log.d(TAG, "Cooldown remaining: $timeRemaining seconds")
// }
// }
//
// override fun onFinish() {
// Log.d(TAG, "Cooldown finished, enabling resend button")
// binding.tvTimer.text = "Dapat mengirim ulang kode OTP"
// binding.tvResendOtp.isEnabled = true
// binding.tvResendOtp.setTextColor(ContextCompat.getColor(requireContext(), R.color.blue1))
// timeRemaining = 0
// }
// }.start()
// }
}

View File

@ -104,20 +104,11 @@ class RegisterStep3Fragment : Fragment() {
// Set up button listeners
binding.btnPrevious.setOnClickListener {
// Go back to the previous step
// parentFragmentManager.popBackStack()
// (activity as? RegisterActivity)?.navigateToStep(2, null)
// (activity as? RegisterActivity)?.goBackToPreviousStep()
// Option 2: Direct navigation to step 1
val step2Fragment = RegisterStep2Fragment()
parentFragmentManager.beginTransaction()
.replace(R.id.fragment_container, step2Fragment)
.commit()
parentFragmentManager.popBackStack()
}
binding.btnRegister.setOnClickListener {
submitAddress()
sessionManager.clearAll()
}
// If user skips address entry
@ -512,7 +503,7 @@ class RegisterStep3Fragment : Fragment() {
private fun showRegistrationSuccess() {
// Now we can show the success message for the overall registration process
Toast.makeText(requireContext(), "Berhasil mendaftarkan akun", Toast.LENGTH_LONG).show()
Toast.makeText(requireContext(), "Registration completed successfully!", Toast.LENGTH_LONG).show()
// Navigate to login screen
startActivity(Intent(requireContext(), LoginActivity::class.java))
@ -530,5 +521,4 @@ class RegisterStep3Fragment : Fragment() {
ViewCompat.setWindowInsetsAnimationCallback(binding.root, null)
_binding = null
}
}

View File

@ -41,16 +41,11 @@ class CartActivity : AppCompatActivity() {
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sessionManager = SessionManager(this)
apiService = ApiConfig.getApiService(sessionManager)
binding = ActivityCartBinding.inflate(layoutInflater)
setContentView(binding.root)
if (!sessionManager.isLoggedIn()){
binding.emptyCart.text = "Silahkan masuk terlebih dahulu"
}
sessionManager = SessionManager(this)
apiService = ApiConfig.getApiService(sessionManager)
WindowCompat.setDecorFitsSystemWindows(window, false)
@ -123,7 +118,7 @@ class CartActivity : AppCompatActivity() {
// Start checkout with the prepared items
startCheckoutWithWholesaleInfo(selectedItems)
} else {
Toast.makeText(this, "Pilih produk yang sama dengan toko", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Please select items from a single store only", Toast.LENGTH_SHORT).show()
}
}
} else {

View File

@ -124,7 +124,7 @@ class ChatActivity : AppCompatActivity() {
if (token.isEmpty()) {
// User not logged in, redirect to login
Toast.makeText(this, "Silahkan masuk terlebih dahulu", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Please login first", Toast.LENGTH_SHORT).show()
startActivity(Intent(this, LoginActivity::class.java))
finish()
return
@ -506,7 +506,7 @@ class ChatActivity : AppCompatActivity() {
}
startActivity(intent)
} catch (e: Exception) {
Toast.makeText(this, "Gagal memuat produk", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Cannot open product details", Toast.LENGTH_SHORT).show()
Log.e(TAG, "Error navigating to product detail", e)
}
}
@ -622,7 +622,7 @@ class ChatActivity : AppCompatActivity() {
if (outputFile.exists() && outputFile.length() > 0) {
if (outputFile.length() > 5 * 1024 * 1024) {
Log.e(TAG, "File too large: ${outputFile.length()} bytes")
Toast.makeText(this, "Gambar terlalu besar. Maksimal 1MB", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Image too large (max 5MB)", Toast.LENGTH_SHORT).show()
return
}

View File

@ -5,6 +5,7 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
@ -79,10 +80,8 @@ class ChatListFragment : Fragment() {
}
}
is Result.Error -> {
// binding.tvEmptyChat.visibility = View.VISIBLE
binding.progressBarChat.visibility = View.VISIBLE
// Toast.makeText(requireContext(), "Failed to load chats", Toast.LENGTH_SHORT).show()
Log.e(TAG, "Failed to load chats")
binding.tvEmptyChat.visibility = View.VISIBLE
Toast.makeText(requireContext(), "Failed to load chats", Toast.LENGTH_SHORT).show()
}
Result.Loading -> {
binding.progressBarChat.visibility = View.VISIBLE

View File

@ -6,7 +6,6 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
@ -33,7 +32,6 @@ import com.alya.ecommerce_serang.utils.SessionManager
import com.alya.ecommerce_serang.utils.setLightStatusBar
import com.alya.ecommerce_serang.utils.viewmodel.HomeUiState
import com.alya.ecommerce_serang.utils.viewmodel.HomeViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
//@AndroidEntryPoint
@ -142,13 +140,12 @@ class HomeFragment : Fragment() {
viewModel.uiState.collect { state ->
when (state) {
is HomeUiState.Loading -> {
binding.loadingAll.root.visibility = View.VISIBLE
binding.loading.root.isVisible = true
binding.error.root.isVisible = false
binding.home.isVisible = false
delay(5000)
}
is HomeUiState.Success -> {
binding.loadingAll.root.visibility = View.GONE
binding.loading.root.isVisible = false
binding.error.root.isVisible = false
binding.home.isVisible = true
val products = state.products
@ -157,12 +154,10 @@ class HomeFragment : Fragment() {
productAdapter?.updateLimitedProducts(products)
}
is HomeUiState.Error -> {
binding.loadingAll.root.visibility = View.GONE
binding.loading.root.isVisible = false
binding.error.root.isVisible = true
binding.home.isVisible = false
// binding.error.errorMessage.text = state.message
Log.e("HomeFragment", "Error load data: ${state.message}")
Toast.makeText(requireContext(), "Terjadi kendala. Muat ulang halaman", Toast.LENGTH_SHORT) .show()
binding.error.errorMessage.text = state.message
binding.error.retryButton.setOnClickListener {
viewModel.retry()
}

View File

@ -7,15 +7,12 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.repository.ProductRepository
@ -109,11 +106,6 @@ class SearchHomeFragment : Fragment() {
}
})
val searchText = findViewById<TextView>(androidx.appcompat.R.id.search_src_text)
searchText.textSize = 14f // in sp
searchText.setHintTextColor(ContextCompat.getColor(context, R.color.black_200))
searchText.setTextColor(ContextCompat.getColor(context, R.color.black))
if (args.query.isNullOrEmpty()) {
requestFocus()
post {

View File

@ -78,4 +78,4 @@ import com.google.firebase.messaging.RemoteMessage
val notificationId = System.currentTimeMillis().toInt()
notificationManager.notify(notificationId, notificationBuilder.build())
}
}
}

View File

@ -154,18 +154,8 @@ class CheckoutActivity : AppCompatActivity() {
// Observe address details
viewModel.addressDetails.observe(this) { address ->
if (address != null) {
// Show selected address
binding.containerEmptyAddress.visibility = View.GONE
binding.containerAddress.visibility = View.VISIBLE
binding.tvPlacesAddress.text = address.recipient
binding.tvAddress.text = "${address.street}, ${address.subdistrict}"
} else {
// Show empty address state
binding.containerEmptyAddress.visibility = View.VISIBLE
binding.containerAddress.visibility = View.GONE
}
binding.tvPlacesAddress.text = address?.recipient
binding.tvAddress.text = "${address?.street}, ${address?.subdistrict}"
}
viewModel.availablePaymentMethods.observe(this) { paymentMethods ->
@ -182,7 +172,9 @@ class CheckoutActivity : AppCompatActivity() {
// Update the adapter ONLY if it exists
paymentAdapter?.let { adapter ->
// This line was causing issues - using setSelectedPayment instead of setSelectedPaymentName
adapter.setSelectedPaymentId(selectedPayment.id)
Log.d("CheckoutActivity", "Updated adapter with selected payment: ${selectedPayment.id}")
}
}
@ -191,20 +183,20 @@ class CheckoutActivity : AppCompatActivity() {
// Observe loading state
viewModel.isLoading.observe(this) { isLoading ->
binding.btnPay.isEnabled = !isLoading
}
// Observe error messages
viewModel.errorMessage.observe(this) { message ->
if (message.isNotEmpty()) {
Toast.makeText(this, "Terdapat kendala di pemesanan", Toast.LENGTH_SHORT).show()
Log.e("CheckoutActivity", "Error from errorMessage: $message")
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
// Observe order creation
viewModel.orderCreated.observe(this) { created ->
if (created) {
Toast.makeText(this, "Berhasil membuat pesanan", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Order successfully created!", Toast.LENGTH_SHORT).show()
setResult(RESULT_OK)
finish()
}
@ -214,17 +206,10 @@ class CheckoutActivity : AppCompatActivity() {
private fun setupPaymentMethodsRecyclerView(paymentMethods: List<DetailPaymentItem>) {
if (paymentMethods.isEmpty()) {
Log.e("CheckoutActivity", "Payment methods list is empty")
Toast.makeText(this, "Tidak ditemukan metode pembayaran", Toast.LENGTH_SHORT).show()
// Show empty payment state
binding.containerEmptyPayment.visibility = View.VISIBLE
binding.rvPaymentInfo.visibility = View.GONE
Toast.makeText(this, "No payment methods available", Toast.LENGTH_SHORT).show()
return
}
binding.containerEmptyPayment.visibility = View.GONE
binding.rvPaymentInfo.visibility = View.VISIBLE
// Debug logging
Log.d("CheckoutActivity", "Setting up payment methods: ${paymentMethods.size} methods available")
@ -281,16 +266,6 @@ class CheckoutActivity : AppCompatActivity() {
this.adapter = adapter
isNestedScrollingEnabled = false
}
// if (checkoutData.cartItems.isEmpty()) {
// // Show empty products state
// binding.containerEmptyProducts.visibility = View.VISIBLE
// binding.rvProductItems.visibility = View.GONE
// return
// }
binding.containerEmptyProducts.visibility = View.GONE
binding.rvProductItems.visibility = View.VISIBLE
}
private fun updateOrderSummary() {
@ -315,8 +290,7 @@ class CheckoutActivity : AppCompatActivity() {
private fun updateShippingUI(shipName: String, shipService: String, shipEtd: String, shipPrice: Int) {
if (shipName.isNotEmpty() && shipService.isNotEmpty()) {
// Hide empty state and show selected shipping
binding.containerEmptyShipping.visibility = View.GONE
// Display shipping name and service in one line
binding.cardShipment.visibility = View.VISIBLE
binding.tvCourierName.text = "$shipName $shipService"
@ -324,8 +298,6 @@ class CheckoutActivity : AppCompatActivity() {
binding.tvShippingPrice.text = formatCurrency(shipPrice.toDouble())
binding.rbJne.isChecked = true
} else {
// Show empty shipping state
binding.containerEmptyShipping.visibility = View.VISIBLE
binding.cardShipment.visibility = View.GONE
}
}
@ -338,10 +310,10 @@ class CheckoutActivity : AppCompatActivity() {
}
// Shipping method selection
binding.tvShippingOption.setOnClickListener {
binding.layoutShippingMethod.setOnClickListener {
val addressId = viewModel.addressDetails.value?.id ?: 0
if (addressId <= 0) {
Toast.makeText(this, "Silahkan pilih alamat dahulu", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Please select delivery address first", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
@ -391,7 +363,7 @@ class CheckoutActivity : AppCompatActivity() {
viewModel.setSelectedAddress(addressId)
// You might want to show a toast or some UI feedback
Toast.makeText(this, "Berhasil memilih alamat", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Address selected successfully", Toast.LENGTH_SHORT).show()
}
}
}

View File

@ -67,7 +67,7 @@ class ShippingActivity : AppCompatActivity() {
// Validate required information
if (addressId <= 0 || productId <= 0) {
Log.e(TAG, "Missing required shipping information: addressId=$addressId, productId=$productId")
Toast.makeText(this, "Gagal memuat pengiriman", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Missing required shipping information", Toast.LENGTH_SHORT).show()
finish()
return
}

View File

@ -52,12 +52,12 @@ class AddressActivity : AppCompatActivity() {
windowInsets
}
viewModel.fetchAddresses()
setupToolbar()
setupRecyclerView()
setupObservers()
viewModel.fetchAddresses()
}
@ -126,11 +126,6 @@ class AddressActivity : AppCompatActivity() {
finish()
}
override fun onResume() {
super.onResume()
viewModel.fetchAddresses()
}
companion object {
const val EXTRA_ADDRESS_ID = "extra_address_id"
}

View File

@ -61,8 +61,8 @@ class AddEvidencePaymentActivity : AppCompatActivity() {
}
private val paymentMethods = arrayOf(
"Pilih Metode Pembayaran",
"Transfer Bank",
"QRIS",
)
// private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
@ -122,6 +122,7 @@ class AddEvidencePaymentActivity : AppCompatActivity() {
} catch (e: Exception) {
Log.e(TAG, "ERROR in AddEvidencePaymentActivity onCreate: ${e.message}", e)
Toast.makeText(this, "Error: ${e.message}", Toast.LENGTH_LONG).show()
}
}
@ -287,7 +288,7 @@ class AddEvidencePaymentActivity : AppCompatActivity() {
}
} catch (e: Exception) {
Log.e(TAG, "Error handling selected image", e)
Toast.makeText(this, "Terjadi kendala", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
@ -313,10 +314,10 @@ class AddEvidencePaymentActivity : AppCompatActivity() {
return
}
// if (binding.spinnerPaymentMethod.selectedItemPosition == 0) {
// Toast.makeText(this, "Silahkan pilih metode pembayaran", Toast.LENGTH_SHORT).show()
// return
// }
if (binding.spinnerPaymentMethod.selectedItemPosition == 0) {
Toast.makeText(this, "Silahkan pilih metode pembayaran", Toast.LENGTH_SHORT).show()
return
}
binding.etAccountNumber.visibility = View.GONE
// if (binding.etAccountNumber.text.toString().trim().isEmpty()) {
@ -324,10 +325,10 @@ class AddEvidencePaymentActivity : AppCompatActivity() {
// return
// }
// if (binding.tvPaymentDate.text.toString() == "Pilih tanggal") {
// Toast.makeText(this, "Silahkan pilih tanggal pembayaran", Toast.LENGTH_SHORT).show()
// return
// }
if (binding.tvPaymentDate.text.toString() == "Pilih tanggal") {
Toast.makeText(this, "Silahkan pilih tanggal pembayaran", Toast.LENGTH_SHORT).show()
return
}
// All validations passed, proceed with upload
uploadPaymentProof()
@ -366,7 +367,7 @@ class AddEvidencePaymentActivity : AppCompatActivity() {
viewModel.uploadPaymentProof(request)
} catch (e: Exception) {
Log.e(TAG, "Error creating upload request: ${e.message}", e)
Toast.makeText(this, "Gagal mengunggah foto", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Error preparing upload: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}

View File

@ -160,8 +160,7 @@ class PaymentActivity : AppCompatActivity() {
viewModel.error.observe(this) { error ->
if (error.isNotEmpty()) {
Toast.makeText(this, "Gagal melakukan pembayaran", Toast.LENGTH_SHORT).show()
Log.e(TAG, "Failed payment: $error")
Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
}
}
}

View File

@ -517,14 +517,14 @@ class OrderHistoryAdapter(
} else {
// Log error and show a Toast instead if we can't get a FragmentManager
Log.e("OrderHistoryAdapter", "Cannot show bottom sheet: Context is not a FragmentActivity")
Toast.makeText(context, "Terjadi kendala", Toast.LENGTH_SHORT).show()
Toast.makeText(context, "Cannot show cancel order dialog", Toast.LENGTH_SHORT).show()
return
}
}
else -> {
// Log error and show a Toast instead if we can't get a FragmentManager
Log.e("OrderHistoryAdapter", "Cannot show bottom sheet: Context is not a FragmentActivity")
Toast.makeText(context, "Terjadi kendala", Toast.LENGTH_SHORT).show()
Toast.makeText(context, "Cannot show cancel order dialog", Toast.LENGTH_SHORT).show()
return
}
}
@ -535,7 +535,7 @@ class OrderHistoryAdapter(
onOrderCancelled = {
callbacks.onOrderCancelled(orderId.toString(), true, "Order cancelled successfully")
// Show a success message
Toast.makeText(context, "Pesanan berhasil dibatalkan", Toast.LENGTH_SHORT).show()
Toast.makeText(context, "Order cancelled successfully", Toast.LENGTH_SHORT).show()
}
)
@ -547,6 +547,15 @@ class OrderHistoryAdapter(
// Use ViewModel to fetch order details
viewModel.getOrderDetails(order.orderId)
// Create loading dialog
// val loadingDialog = Dialog(itemView.context).apply {
// requestWindowFeature(Window.FEATURE_NO_TITLE)
// setContentView(R.layout.dialog_loading)
// window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
// setCancelable(false)
// }
// loadingDialog.show()
viewModel.error.observe(itemView.findViewTreeLifecycleOwner()!!) { errorMsg ->
if (!errorMsg.isNullOrEmpty()) {
Toast.makeText(itemView.context, errorMsg, Toast.LENGTH_SHORT).show()

View File

@ -67,7 +67,7 @@ class CancelOrderBottomSheet(
btnConfirm.setOnClickListener {
if (selectedReason == null) {
Toast.makeText(context, "Pilih alasan pembatalan", Toast.LENGTH_SHORT).show()
Toast.makeText(context, "Please select a reason", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}

View File

@ -90,7 +90,7 @@ class CreateReviewActivity : AppCompatActivity() {
)
})
} catch (e: Exception) {
Toast.makeText(this, "Gagal memuat ulasan", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Error loading review items", Toast.LENGTH_SHORT).show()
finish()
}
} else {
@ -110,7 +110,7 @@ class CreateReviewActivity : AppCompatActivity() {
)
)
} else {
Toast.makeText(this, "Tidak ada produk untuk direview", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "No items to review", Toast.LENGTH_SHORT).show()
finish()
}
}

View File

@ -112,17 +112,13 @@ class DetailProductActivity : AppCompatActivity() {
when (result) {
is Result.Success -> {
updateStoreInfo(result.data)
binding.progressBarDetailStore.visibility = View.GONE
}
is Result.Error -> {
// Show error message, maybe a Toast or Snackbar
binding.progressBarDetailStore.visibility = View.GONE
Log.e("DetailProfileActivity", "Failed to load store: ${result.exception.message}")
Toast.makeText(this, "Kendala memuat toko", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Failed to load store: ${result.exception.message}", Toast.LENGTH_SHORT).show()
}
is Result.Loading -> {
// Show loading indicator if needed
binding.progressBarDetailStore.visibility = View.VISIBLE
}
}
}
@ -164,10 +160,6 @@ class DetailProductActivity : AppCompatActivity() {
val products = viewModel.otherProducts.value.orEmpty()
if (products.isNotEmpty()) {
updateOtherProducts(products, storeMap)
} else {
binding.emptyOtherProducts.visibility = View.VISIBLE
binding.recyclerViewOtherProducts.visibility = View.GONE
binding.tvViewAllProducts.visibility = View.GONE
}
}
}
@ -198,14 +190,12 @@ class DetailProductActivity : AppCompatActivity() {
private fun updateOtherProducts(products: List<ProductsItem>, storeMap: Map<Int, StoreItem>) {
if (products.isEmpty()) {
Log.d("DetailProductActivity", "Product list is empty, hiding RecyclerView")
binding.recyclerViewOtherProducts.visibility = View.GONE
binding.emptyOtherProducts.visibility = View.VISIBLE
binding.recyclerViewOtherProducts.visibility = View.VISIBLE
binding.tvViewAllProducts.visibility = View.GONE
} else {
Log.d("DetailProductActivity", "Displaying product list in RecyclerView")
binding.recyclerViewOtherProducts.visibility = View.VISIBLE
binding.tvViewAllProducts.visibility = View.VISIBLE
binding.emptyOtherProducts.visibility = View.GONE
productAdapter = OtherProductAdapter(products, onClick = { product ->
handleProductClick(product)
@ -326,13 +316,11 @@ class DetailProductActivity : AppCompatActivity() {
val limitedReviewList = if (reviewList.isNotEmpty()) listOf(reviewList.first()) else emptyList()
if (reviewList.isEmpty()) {
binding.recyclerViewReviews.visibility = View.GONE
binding.emptyReview.visibility = View.VISIBLE
binding.tvViewAllReviews.visibility = View.GONE
// binding.tvNoReviews.visibility = View.VISIBLE
} else {
binding.recyclerViewReviews.visibility = View.VISIBLE
binding.tvViewAllReviews.visibility = View.VISIBLE
binding.emptyReview.visibility = View.GONE
}
// binding.tvNoReviews.visibility = View.GONE
reviewsAdapter = ReviewsAdapter(
@ -531,11 +519,7 @@ class DetailProductActivity : AppCompatActivity() {
attachProduct = true // This will auto-attach the product!
)
}
override fun onResume() {
super.onResume()
loadData()
}
companion object {

View File

@ -64,9 +64,10 @@ class StoreDetailActivity : AppCompatActivity() {
)
windowInsets
}
loadData()
setupUI()
setupObservers()
loadData()
}
private fun setupUI() {
@ -87,18 +88,15 @@ class StoreDetailActivity : AppCompatActivity() {
viewModel.storeDetail.observe(this) { result ->
when (result) {
is Result.Success -> {
binding.progressBarDetailProdItem.visibility = View.GONE
updateStoreInfo(result.data)
viewModel.loadOtherProducts(result.data.storeId)
}
is Result.Error -> {
// Show error message, maybe a Toast or Snackbar
binding.progressBarDetailProdItem.visibility = View.GONE
Toast.makeText(this, "Failed to load store: ${result.exception.message}", Toast.LENGTH_SHORT).show()
}
is Result.Loading -> {
// Show loading indicator if needed
binding.progressBarDetailProdItem.visibility = View.VISIBLE
}
}
}
@ -111,9 +109,6 @@ class StoreDetailActivity : AppCompatActivity() {
val products = viewModel.otherProducts.value.orEmpty()
if (products.isNotEmpty()) {
updateProducts(products, storeMap)
} else {
binding.progressBarDetailProdItem.visibility = View.VISIBLE
binding.rvProducts.visibility = View.GONE
}
}
}
@ -151,7 +146,7 @@ class StoreDetailActivity : AppCompatActivity() {
.into(binding.ivStoreImage)
val ratingStr = it.storeRating
val ratingValue = ratingStr.toFloatOrNull()
val ratingValue = ratingStr?.toFloatOrNull()
if (ratingValue != null && ratingValue > 0f) {
binding.tvStoreRating.text = String.format("%.1f", ratingValue)
@ -166,12 +161,10 @@ class StoreDetailActivity : AppCompatActivity() {
private fun updateProducts(products: List<ProductsItem>, storeMap: Map<Int, StoreItem>) {
if (products.isEmpty()) {
binding.rvProducts.visibility = View.GONE
binding.progressBarDetailProdItem.visibility = View.VISIBLE
Log.d("StoreDetailActivity", "Product list is empty, hiding RecyclerView")
} else {
Log.d("StoreDetailActivity", "Displaying product list in RecyclerView")
binding.progressBarDetailProdItem.visibility = View.GONE
binding.rvProducts.visibility = View.VISIBLE
productAdapter = HorizontalProductAdapter(products, onClick = { product ->
handleProductClick(product)

View File

@ -1,21 +0,0 @@
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 ChangePasswordActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_change_password)
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
}
}
}

View File

@ -90,8 +90,6 @@ class DetailProfileActivity : AppCompatActivity() {
Log.e("DetailProfileActivity", "Error from ViewModel: $error")
Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
}
}
private fun setupClickListeners() {
@ -108,8 +106,7 @@ class DetailProfileActivity : AppCompatActivity() {
}
editProfileLauncher.launch(intent)
} ?: run {
Toast.makeText(this, "Akun tidak ditemukan", Toast.LENGTH_SHORT).show()
Log.e("DetailProfileActivity", "Profile data is not available")
Toast.makeText(this, "Profile data is not available", Toast.LENGTH_SHORT).show()
}
}
}

View File

@ -20,10 +20,10 @@ import com.alya.ecommerce_serang.data.repository.MyStoreRepository
import com.alya.ecommerce_serang.data.repository.UserRepository
import com.alya.ecommerce_serang.databinding.FragmentProfileBinding
import com.alya.ecommerce_serang.ui.auth.LoginActivity
import com.alya.ecommerce_serang.ui.profile.mystore.RegisterStoreActivity
import com.alya.ecommerce_serang.ui.order.address.AddressActivity
import com.alya.ecommerce_serang.ui.order.history.HistoryActivity
import com.alya.ecommerce_serang.ui.profile.mystore.MyStoreActivity
import com.alya.ecommerce_serang.ui.profile.mystore.RegisterStoreActivity
import com.alya.ecommerce_serang.ui.profile.mystore.StoreOnReviewActivity
import com.alya.ecommerce_serang.ui.profile.mystore.StoreSuspendedActivity
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
@ -58,6 +58,7 @@ class ProfileFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sessionManager = SessionManager(requireContext())
}
override fun onCreateView(
@ -71,57 +72,26 @@ class ProfileFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sessionManager = SessionManager(requireContext())
if (!sessionManager.isLoggedIn()) {
// Redirect to LoginActivity
binding.tvName.text = "Selamat Datang"
binding.tvUsername.text = "Silahkan masuk"
binding.btnDetailProfile.text = "Masuk"
binding.btnDetailProfile.setOnClickListener {
val intent = Intent(requireContext(), LoginActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
// ✅ Finish the host activity so user cant go back
requireActivity().finish()
}
binding.containerBukaToko.visibility = View.GONE
binding.cardPesanan.visibility = View.GONE
binding.tvPengaturanAkun.visibility = View.GONE
binding.containerSettings.visibility = View.GONE
binding.cardAbout.visibility = View.GONE
binding.cardLogout.visibility = View.GONE
}
viewModel.loadUserProfile()
viewModel.checkStoreUser()
observeUserProfile()
observeStoreStatus()
viewModel.loadUserProfile()
viewModel.checkStoreUser()
binding.cardBukaToko.setOnClickListener{
// if (hasStore == true) startActivity(Intent(requireContext(), MyStoreActivity::class.java))
// else startActivity(Intent(requireContext(), RegisterStoreActivity::class.java))
if (viewModel.checkStore.value == true) {
myStoreViewModel.loadMyStore()
myStoreViewModel.myStoreProfile.observe(viewLifecycleOwner) { storeDataResponse ->
storeDataResponse?.let { storeResponse ->
val store = storeResponse.store
when (store.approvalStatus) {
myStoreViewModel.myStoreProfile.observe(viewLifecycleOwner) { store ->
store?.let {
when (store.storeStatus) {
"process" -> startActivity(Intent(requireContext(), StoreOnReviewActivity::class.java))
"rejected" -> startActivity(
Intent(requireContext(), RegisterStoreActivity::class.java).putExtra("REAPPLY", true))
else -> {
when(store.storeStatus){
"suspended" -> startActivity(Intent(requireContext(), StoreSuspendedActivity::class.java))
else -> startActivity(Intent(requireContext(), MyStoreActivity::class.java))
}
}
"active" -> startActivity(Intent(requireContext(), MyStoreActivity::class.java))
"inactive" -> startActivity(Intent(requireContext(), MyStoreActivity::class.java))
"suspended" -> startActivity(Intent(requireContext(), StoreSuspendedActivity::class.java))
else -> startActivity(Intent(requireContext(), RegisterStoreActivity::class.java))
}
} ?: run {
Toast.makeText(requireContext(), "Gagal memuat data toko", Toast.LENGTH_SHORT).show()
@ -145,11 +115,6 @@ class ProfileFragment : Fragment() {
startActivity(intent)
}
binding.cardChangePass.setOnClickListener{
val intent = Intent(requireContext(), ChangePasswordActivity::class.java)
startActivity(intent)
}
binding.cardLogout.setOnClickListener{
logout()
}
@ -165,8 +130,7 @@ class ProfileFragment : Fragment() {
user?.let { updateUI(it) }
}
viewModel.errorMessage.observe(viewLifecycleOwner) { errorMessage ->
// Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show()
Log.e("Profile Fragment", "Failed to load profile: $errorMessage")
Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show()
}
}
@ -222,8 +186,6 @@ class ProfileFragment : Fragment() {
sessionManager.clearAll()
val intent = Intent(requireContext(), LoginActivity::class.java)
startActivity(intent)
requireActivity().finish()
} catch (e: Exception) {
Toast.makeText(
requireContext(),
@ -234,11 +196,4 @@ class ProfileFragment : Fragment() {
}
}
override fun onResume() {
super.onResume()
viewModel.loadUserProfile()
viewModel.checkStoreUser()
}
}

View File

@ -2,7 +2,6 @@ package com.alya.ecommerce_serang.ui.profile.editprofile
import android.Manifest
import android.app.Activity
import android.app.AlertDialog
import android.app.DatePickerDialog
import android.content.Intent
import android.content.pm.PackageManager
@ -25,6 +24,7 @@ import com.alya.ecommerce_serang.BuildConfig.BASE_URL
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.dto.UserProfile
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
import com.alya.ecommerce_serang.data.repository.Result
import com.alya.ecommerce_serang.data.repository.UserRepository
import com.alya.ecommerce_serang.databinding.ActivityEditProfileCustBinding
@ -33,6 +33,7 @@ import com.alya.ecommerce_serang.utils.SessionManager
import com.alya.ecommerce_serang.utils.viewmodel.ProfileViewModel
import com.bumptech.glide.Glide
import com.google.gson.Gson
import java.io.File
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
@ -40,9 +41,9 @@ import java.util.TimeZone
class EditProfileCustActivity : AppCompatActivity() {
private lateinit var binding: ActivityEditProfileCustBinding
private lateinit var apiService: ApiService
private lateinit var sessionManager: SessionManager
private var selectedImageUri: Uri? = null
private var currentUser: UserProfile? = null
private val viewModel: ProfileViewModel by viewModels {
BaseViewModelFactory {
@ -53,7 +54,7 @@ class EditProfileCustActivity : AppCompatActivity() {
}
private val getContent = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
data?.data?.let {
selectedImageUri = it
@ -104,8 +105,8 @@ class EditProfileCustActivity : AppCompatActivity() {
}
userProfile?.let {
currentUser = it
populateFields(it)
setupClickListeners()
observeViewModel()
}
@ -117,7 +118,7 @@ class EditProfileCustActivity : AppCompatActivity() {
binding.etNumberPhoneUser.setText(profile.phone)
// Format birth date for display
profile.birthDate.let {
profile.birthDate?.let {
binding.etDateBirth.setText(formatDate(it))
}
@ -155,7 +156,7 @@ class EditProfileCustActivity : AppCompatActivity() {
}
binding.btnSave.setOnClickListener {
if (hasChanged()) confirmUpdate() else finish()
saveProfile()
}
}
@ -212,38 +213,25 @@ class EditProfileCustActivity : AppCompatActivity() {
datePickerDialog.show()
}
private fun confirmUpdate() {
AlertDialog.Builder(this)
.setTitle("Konfirmasi Perubahan")
.setMessage("Apakah Anda yakin ingin menyimpan perubahan profil toko Anda?")
.setPositiveButton("Ya") { _, _ -> saveProfile() }
.setNegativeButton("Batal", null)
.show()
}
private fun hasChanged(): Boolean {
val name = binding.etNameUser.text.toString() != currentUser?.name
val username = binding.etUsername.text.toString() != currentUser?.username
val email = binding.etEmailUser.text.toString() != currentUser?.email
val phone = binding.etNumberPhoneUser.text.toString() != currentUser?.phone
val displayDate = binding.etDateBirth.text.toString() != currentUser?.birthDate.toString()
val imgProfile = selectedImageUri != null
return name || username || email || phone || displayDate || imgProfile
}
private fun saveProfile() {
val name = binding.etNameUser.text.toString()
val username = binding.etUsername.text.toString()
val email = binding.etEmailUser.text.toString()
val phone = binding.etNumberPhoneUser.text.toString()
val displayDate = binding.etDateBirth.text.toString()
val imgProfile = selectedImageUri
if (name.isEmpty() || username.isEmpty() || email.isEmpty() || phone.isEmpty() || displayDate.isEmpty()) {
Toast.makeText(this, "Semua field harus diisi", Toast.LENGTH_SHORT).show()
return
}
// Convert date to server format
val serverBirthDate = convertToServerDateFormat(displayDate)
Log.d(TAG, "Starting profile save with direct method")
Log.d(TAG, "Selected image URI: $selectedImageUri")
// Disable the button to prevent multiple clicks
binding.btnSave.isEnabled = false
// Call the repository method via ViewModel
@ -254,10 +242,82 @@ class EditProfileCustActivity : AppCompatActivity() {
phone = phone,
birthDate = serverBirthDate,
email = email,
imageUri = imgProfile
imageUri = selectedImageUri
)
}
private fun getRealPathFromURI(uri: Uri): String? {
Log.d(TAG, "Getting real path from URI: $uri")
// Handle different URI schemes
when {
// File URI
uri.scheme == "file" -> {
val path = uri.path
Log.d(TAG, "URI is file scheme, path: $path")
return path
}
// Content URI
uri.scheme == "content" -> {
try {
val projection = arrayOf(MediaStore.Images.Media.DATA)
contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
val path = cursor.getString(columnIndex)
Log.d(TAG, "Found path from content URI: $path")
return path
} else {
Log.e(TAG, "Cursor is empty")
}
} ?: Log.e(TAG, "Cursor is null")
// If the above fails, try the documented API way
contentResolver.openInputStream(uri)?.use { inputStream ->
// Create a temp file
val fileName = getFileName(uri) ?: "temp_img_${System.currentTimeMillis()}.jpg"
val tempFile = File(cacheDir, fileName)
tempFile.outputStream().use { outputStream ->
inputStream.copyTo(outputStream)
}
Log.d(TAG, "Created temporary file: ${tempFile.absolutePath}")
return tempFile.absolutePath
}
} catch (e: Exception) {
Log.e(TAG, "Error getting real path: ${e.message}", e)
}
}
}
Log.e(TAG, "Could not get real path for URI: $uri")
return null
}
private fun getFileName(uri: Uri): String? {
var result: String? = null
if (uri.scheme == "content") {
contentResolver.query(uri, null, null, null, null)?.use { cursor ->
if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
if (columnIndex >= 0) {
result = cursor.getString(columnIndex)
Log.d(TAG, "Found filename from content URI: $result")
}
}
}
}
if (result == null) {
result = uri.path
val cut = result?.lastIndexOf('/') ?: -1
if (cut != -1) {
result = result?.substring(cut + 1)
}
Log.d(TAG, "Extracted filename from path: $result")
}
return result
}
private fun formatDate(dateString: String?): String {
if (dateString.isNullOrEmpty()) return "N/A"

View File

@ -59,13 +59,12 @@ class MyStoreActivity : AppCompatActivity() {
finish()
}
viewModel.myStoreProfile.observe(this){ user ->
user?.let { myStoreProfileOverview(it.store) }
}
viewModel.loadMyStore()
viewModel.loadMyStoreProducts()
viewModel.fetchBalance()
viewModel.myStoreProfile.observe(this){ user ->
user?.let { myStoreProfileOverview(it) }
}
viewModel.errorMessage.observe(this) { error ->
Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
@ -73,6 +72,7 @@ class MyStoreActivity : AppCompatActivity() {
setUpClickListeners()
getCountOrder()
observeViewModel()
viewModel.fetchBalance()
fetchBalance()
}
@ -206,13 +206,6 @@ class MyStoreActivity : AppCompatActivity() {
}
}
override fun onResume() {
super.onResume()
viewModel.loadMyStore()
viewModel.loadMyStoreProducts()
viewModel.fetchBalance()
}
companion object {
private const val PROFILE_REQUEST_CODE = 100
}

View File

@ -27,7 +27,6 @@ import androidx.core.view.WindowInsetsCompat
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.data.api.response.auth.StoreTypesItem
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.repository.MyStoreRepository
import com.alya.ecommerce_serang.data.repository.Result
import com.alya.ecommerce_serang.data.repository.UserRepository
import com.alya.ecommerce_serang.databinding.ActivityRegisterStoreBinding
@ -36,17 +35,8 @@ import com.alya.ecommerce_serang.ui.order.address.CityAdapter
import com.alya.ecommerce_serang.ui.order.address.ProvinceAdapter
import com.alya.ecommerce_serang.ui.order.address.SubdsitrictAdapter
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.FileUtils
import com.alya.ecommerce_serang.utils.ImageUtils
import com.alya.ecommerce_serang.utils.SessionManager
import com.alya.ecommerce_serang.utils.viewmodel.MyStoreViewModel
import com.alya.ecommerce_serang.utils.viewmodel.RegisterStoreViewModel
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import androidx.core.net.toUri
class RegisterStoreActivity : AppCompatActivity() {
@ -63,7 +53,6 @@ class RegisterStoreActivity : AppCompatActivity() {
private val PICK_KTP_REQUEST = 1002
private val PICK_NPWP_REQUEST = 1003
private val PICK_NIB_REQUEST = 1004
private var isReapply: Boolean = false
// Location request code
private val LOCATION_PERMISSION_REQUEST = 2001
@ -75,15 +64,6 @@ class RegisterStoreActivity : AppCompatActivity() {
RegisterStoreViewModel(orderRepository)
}
}
private val myStoreViewModel: MyStoreViewModel by viewModels {
BaseViewModelFactory {
val apiService = ApiConfig.getApiService(sessionManager)
val myStoreRepository = MyStoreRepository(apiService)
MyStoreViewModel(myStoreRepository)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRegisterStoreBinding.inflate(layoutInflater)
@ -109,8 +89,6 @@ class RegisterStoreActivity : AppCompatActivity() {
setupHeader()
isReapply = intent.getBooleanExtra("REAPPLY", false)
provinceAdapter = ProvinceAdapter(this)
cityAdapter = CityAdapter(this)
subdistrictAdapter = SubdsitrictAdapter(this)
@ -151,140 +129,19 @@ class RegisterStoreActivity : AppCompatActivity() {
viewModel.cityId.observe(this) { validateRequiredFields() }
viewModel.storeTypeId.observe(this) { validateRequiredFields() }
if (isReapply) {
binding.btnRegister.text = "Ajukan Kembali"
binding.layoutRejected.visibility = View.VISIBLE
myStoreViewModel.loadMyStore()
myStoreViewModel.myStoreProfile.observe(this) { storeDataResponse ->
storeDataResponse?.let { storeResponse ->
val store = storeResponse.store
binding.tvRejectedReason.text = store.approvalReason
// Prefill basic fields
binding.etStoreName.setText(store.storeName)
binding.etStoreDescription.setText(store.storeDescription)
binding.etStreet.setText(store.street)
binding.etPostalCode.setText(store.postalCode)
binding.etAddressDetail.setText(store.detail)
viewModel.storeName.value = store.storeName
viewModel.storeDescription.value = store.storeDescription
viewModel.street.value = store.street
viewModel.postalCode.value = store.postalCode.toIntOrNull() ?: 0
viewModel.addressDetail.value = store.detail
// Prefill bank info
storeResponse.payment.firstOrNull()?.let { payment ->
viewModel.bankName.value = payment.bankName
viewModel.bankNumber.value = payment.bankNum.toIntOrNull() ?: 0
val bankPosition = bankAdapter.findPositionByName(payment.bankName)
binding.spinnerBankName.setSelection(bankPosition, false)
}
// Prefill couriers
storeResponse.shipping.forEach { courier ->
when (courier.courier) {
"jne" -> binding.checkboxJne.isChecked = true
"pos" -> binding.checkboxPos.isChecked = true
"tiki" -> binding.checkboxTiki.isChecked = true
}
}
// Prefill document URIs
store.ktp.let { ktpUri ->
viewModel.ktpUri = ktpUri.toUri()
updateImagePreview(viewModel.ktpUri, binding.imgKtp, binding.layoutUploadKtp)
}
store.npwp.let { npwpUri ->
viewModel.npwpUri = npwpUri.toUri()
updateDocumentPreview(binding.layoutUploadNpwp)
}
store.nib.let { nibUri ->
viewModel.nibUri = nibUri.toUri()
updateDocumentPreview(binding.layoutUploadNib)
}
// Prefill spinner for store types
preselectStoreType(store.storeTypeId)
// Prefill province, city, and subdistrict
preselectProvinceCitySubdistrict(
provinceId = store.provinceId,
cityId = store.cityId,
subdistrictId = store.subdistrict
)
validateRequiredFields()
}
}
binding.btnRegister.setOnClickListener {
doUpdateStoreProfile()
}
} else {
binding.btnRegister.setOnClickListener {
if (viewModel.validateForm()) viewModel.registerStore(this)
else Toast.makeText(this, "Harap lengkapi semua field yang wajib diisi", Toast.LENGTH_SHORT).show()
}
}
}
private fun preselectStoreType(storeTypeId: Int) {
// The adapter is created in setupStoreTypeSpinner(...)
val adapter = binding.spinnerStoreType.adapter
if (adapter != null) {
val count = adapter.count
for (i in 0 until count) {
val item = adapter.getItem(i) as? StoreTypesItem
if (item?.id == storeTypeId) {
binding.spinnerStoreType.setSelection(i, false)
break
}
}
}
}
private fun preselectProvinceCitySubdistrict(
provinceId: Int,
cityId: String,
subdistrictId: String
) {
// Province first (this will trigger cities fetch)
val provCount = provinceAdapter.count
for (i in 0 until provCount) {
if (provinceAdapter.getProvinceId(i) == provinceId) {
binding.spinnerProvince.setSelection(i, false)
break
// Setup register button
binding.btnRegister.setOnClickListener {
Log.d(TAG, "Register button clicked")
if (viewModel.validateForm()) {
Log.d(TAG, "Form validation successful, proceeding with registration")
viewModel.registerStore(this)
} else {
Log.e(TAG, "Form validation failed")
Toast.makeText(this, "Harap lengkapi semua field yang wajib diisi", Toast.LENGTH_SHORT).show()
}
}
// When cities arrive, select the city, then load subdistricts
viewModel.citiesState.observe(this) { state ->
if (state is Result.Success) {
val cityCount = cityAdapter.count
for (i in 0 until cityCount) {
if (cityAdapter.getCityId(i) == cityId) {
binding.spinnerCity.setSelection(i, false)
break
}
}
}
}
// When subdistricts arrive, select the subdistrict
viewModel.subdistrictState.observe(this) { state ->
if (state is Result.Success) {
val subCount = subdistrictAdapter.count
for (i in 0 until subCount) {
if (subdistrictAdapter.getSubdistrictId(i) == subdistrictId) {
binding.spinnerSubdistrict.setSelection(i, false)
break
}
}
}
}
Log.d(TAG, "onCreate: RegisterStoreActivity setup completed")
}
private fun setupHeader() {
@ -320,11 +177,10 @@ class RegisterStoreActivity : AppCompatActivity() {
if (isFormValid) {
binding.btnRegister.setBackgroundResource(R.drawable.bg_button_active)
binding.btnRegister.setTextColor(ContextCompat.getColor(this, R.color.white))
binding.btnRegister.isEnabled = true
} else {
binding.btnRegister.setBackgroundResource(R.drawable.bg_button_disabled)
binding.btnRegister.setTextColor(ContextCompat.getColor(this, R.color.black_300))
binding.btnRegister.isEnabled = false
}
}
@ -446,7 +302,7 @@ class RegisterStoreActivity : AppCompatActivity() {
viewModel.errorMessage.observe(this) { errorMsg ->
if (errorMsg.isNotEmpty()) {
Log.e(TAG, "setupStoreTypesObserver: Error loading store types: $errorMsg")
// Toast.makeText(this, "Error loading store types: $errorMsg", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Error loading store types: $errorMsg", Toast.LENGTH_SHORT).show()
}
}
@ -992,63 +848,6 @@ class RegisterStoreActivity : AppCompatActivity() {
}
}
private fun doUpdateStoreProfile() {
val nameBody: RequestBody = (viewModel.storeName.value ?: "")
.toRequestBody("text/plain".toMediaTypeOrNull())
val typeBody: RequestBody = ((viewModel.storeTypeId.value ?: 0).toString())
.toRequestBody("text/plain".toMediaTypeOrNull())
val descBody: RequestBody = (viewModel.storeDescription.value ?: "")
.toRequestBody("text/plain".toMediaTypeOrNull())
val onLeaveBody: RequestBody = "false"
.toRequestBody("text/plain".toMediaTypeOrNull())
// --- Build Multipart for store image (optional) ---
// Prefer compressing images to keep payload small; fall back to raw copy if needed.
val storeImgPart: MultipartBody.Part? = viewModel.storeImageUri?.let { uri ->
try {
// (A) Optional safety check: only allow jpg/png/webp
val allowed = Regex("^(jpg|jpeg|png|webp)$", RegexOption.IGNORE_CASE)
if (!ImageUtils.isAllowedFileType(this, uri, allowed)) {
Toast.makeText(this, "Format gambar tidak didukung", Toast.LENGTH_SHORT).show()
null
} else {
// (B) Compress for upload (ke cacheDir), then build multipart
val compressed: File = ImageUtils.compressImage(
context = this,
uri = uri,
filename = "storeimg", // prefix
maxWidth = 1024,
maxHeight = 1024,
quality = 80
)
FileUtils.createMultipartFromFile("storeimg", compressed)
}
} catch (e: Exception) {
// If compression fails, try raw copy as fallback
val rawFile = FileUtils.createTempFileFromUri(this, uri)
rawFile?.let { FileUtils.createMultipartFromFile("storeimg", it) }
}
}
myStoreViewModel.updateStoreProfile(
storeName = nameBody,
storeType = typeBody,
description = descBody,
isOnLeave = onLeaveBody,
storeImage = storeImgPart
)
myStoreViewModel.updateStoreProfileResult.observe(this) {
Toast.makeText(this, "Pengajuan ulang berhasil dikirim", Toast.LENGTH_SHORT).show()
finish()
}
myStoreViewModel.errorMessage.observe(this) {
if (!it.isNullOrEmpty()) {
Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
}
}
}
companion object {
private const val TAG = "RegisterStoreActivity"
}

View File

@ -91,10 +91,10 @@ class DetailStoreProfileActivity : AppCompatActivity() {
viewModel.fetchStoreTypes()
viewModel.myStoreProfile.observe(this) {
currentStore = it?.store
currentStore = it
currentStoreLoaded = true
if (storeTypesLoaded) setupStoreTypeSpinner(storeTypesList)
updateUI(it?.store)
updateUI(it)
}
viewModel.storeTypes.observe(this) {

View File

@ -97,7 +97,7 @@ class SellsAdapter(
val product = order.orderItems?.firstOrNull()
tvSellsProductName.text = product?.productName
tvSellsProductQty.text = "x${product?.quantity}"
tvSellsProductPrice.text = product?.price?.let { formatPrice(it.toDouble().toInt()) }
tvSellsProductPrice.text = product?.price?.let { formatPrice(it.toInt()) }
val fullImageUrl = when (val img = product?.productImage) {
is String -> {
@ -170,7 +170,7 @@ class SellsAdapter(
val product = order.orderItems?.firstOrNull()
tvSellsProductName.text = product?.productName
tvSellsProductQty.text = "x${product?.quantity}"
tvSellsProductPrice.text = product?.price?.let { formatPrice(it.toDouble().toInt()) }
tvSellsProductPrice.text = product?.price?.let { formatPrice(it.toInt()) }
val fullImageUrl = when (val img = product?.productImage) {
is String -> {
@ -186,7 +186,7 @@ class SellsAdapter(
.into(ivSellsProduct)
tvSellsQty.text = "${order.orderItems?.size} produk"
tvSellsPrice.text = order.totalAmount?.let { formatPrice(it.toDouble().toInt()) }
tvSellsPrice.text = order.totalAmount?.let { formatPrice(it.toInt()) }
}
"paid" -> {
layoutOrders.visibility = View.GONE

View File

@ -83,10 +83,10 @@ class SellsListFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
loadSells()
setupRecyclerView()
observeSellsList()
observePaymentConfirmation()
loadSells()
// getAllOrderCountsAndNavigate()
}
@ -211,12 +211,6 @@ class SellsListFragment : Fragment() {
}
}
override fun onResume() {
super.onResume()
viewModel.getSellList(status)
observeSellsList()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null

View File

@ -10,8 +10,6 @@ import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.alya.ecommerce_serang.data.api.dto.Store
import com.alya.ecommerce_serang.data.api.response.auth.StoreTypesItem
import com.alya.ecommerce_serang.data.api.response.store.StoreResponse
import com.alya.ecommerce_serang.data.api.response.store.profile.Payment
import com.alya.ecommerce_serang.data.api.response.store.profile.Shipping
import com.alya.ecommerce_serang.data.api.response.store.profile.StoreDataResponse
import com.alya.ecommerce_serang.data.repository.MyStoreRepository
import com.alya.ecommerce_serang.data.repository.Result
@ -25,18 +23,12 @@ import java.util.Locale
class MyStoreViewModel(private val repository: MyStoreRepository): ViewModel() {
private var TAG = "MyStoreViewModel"
private val _myStoreProfile = MutableLiveData<StoreResponse?>()
val myStoreProfile: LiveData<StoreResponse?> = _myStoreProfile
private val _myStoreProfile = MutableLiveData<Store?>()
val myStoreProfile: LiveData<Store?> = _myStoreProfile
private val _storeTypes = MutableLiveData<List<StoreTypesItem>>()
val storeTypes: LiveData<List<StoreTypesItem>> = _storeTypes
private val _shipping = MutableLiveData<List<Shipping>>()
val shipping: LiveData<List<Shipping>> = _shipping
private val _payment = MutableLiveData<List<Payment>>()
val payment: LiveData<List<Payment>> = _payment
private val _isLoadingType = MutableLiveData<Boolean>()
val isLoadingType: LiveData<Boolean> = _isLoadingType
@ -55,12 +47,7 @@ class MyStoreViewModel(private val repository: MyStoreRepository): ViewModel() {
fun loadMyStore(){
viewModelScope.launch {
when (val result = repository.fetchMyStoreProfile()){
is Result.Success -> {
val storeData = result.data
_myStoreProfile.postValue(storeData)
_shipping.postValue(storeData?.shipping)
_payment.postValue(storeData?.payment)
}
is Result.Success -> _myStoreProfile.postValue(result.data)
is Result.Error -> _errorMessage.postValue(result.exception.message ?: "Unknown Error")
is Result.Loading -> null
}

View File

@ -7,11 +7,9 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alya.ecommerce_serang.data.api.dto.CreateAddressRequest
import com.alya.ecommerce_serang.data.api.dto.FcmReq
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
import com.alya.ecommerce_serang.data.api.dto.ResetPassReq
import com.alya.ecommerce_serang.data.api.dto.VerifRegisReq
import com.alya.ecommerce_serang.data.api.response.auth.FcmTokenResponse
import com.alya.ecommerce_serang.data.api.response.auth.LoginResponse
import com.alya.ecommerce_serang.data.api.response.auth.OtpResponse
import com.alya.ecommerce_serang.data.api.response.auth.RegisterResponse
@ -390,34 +388,6 @@ class RegisterViewModel(private val repository: UserRepository, private val orde
}
fun sendFcm(token: FcmReq) {
viewModelScope.launch {
_otpState.value = Result.Loading // Indicating API call in progress
try {
// Call the repository function to request OTP
val authenticatedApiService = getAuthenticatedApiService()
val authenticatedOrderRepo = UserRepository(authenticatedApiService)
val response: FcmTokenResponse = authenticatedOrderRepo.sendFcm(token)
// Log and store success message
Log.d("LoginViewModel", "OTP Response: ${response.message}")
_message.value = response.message ?: "berhasil" // 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("LoginViewModel", "OTP request failed for: $token", exception)
}
}
}
companion object {
private const val TAG = "RegisterViewModel"
}

View File

@ -1,5 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="100dp" android:tint="#489EC6" android:viewportHeight="24" android:viewportWidth="24" android:width="100dp">
<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>

View File

@ -1,5 +0,0 @@
<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.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#211E1E" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M7,18c-1.1,0 -1.99,0.9 -1.99,2S5.9,22 7,22s2,-0.9 2,-2 -0.9,-2 -2,-2zM1,2v2h2l3.6,7.59 -1.35,2.45c-0.16,0.28 -0.25,0.61 -0.25,0.96 0,1.1 0.9,2 2,2h12v-2L7.42,15c-0.14,0 -0.25,-0.11 -0.25,-0.25l0.03,-0.12 0.9,-1.63h7.45c0.75,0 1.41,-0.41 1.75,-1.03l3.58,-6.49c0.08,-0.14 0.12,-0.31 0.12,-0.48 0,-0.55 -0.45,-1 -1,-1L5.21,4l-0.94,-2L1,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>

View File

@ -1,5 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#211E1E" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM20,18L4,18v-6h16v6zM20,8L4,8L4,6h16v2z"/>
</vector>

View File

@ -3,6 +3,6 @@
android:shape="rectangle">
<solid android:color="@color/blue_500" />
<corners android:radius="24dp" />
<corners android:radius="5dp" />
</shape>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -113,7 +113,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:visibility="gone"
android:text="Metode Pembayaran *"
android:fontFamily="@font/dmsans_semibold"
android:textSize="16sp" />
@ -123,7 +122,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:visibility="gone"
android:background="@drawable/edit_text_background"
android:minHeight="50dp"
android:padding="12dp" />

View File

@ -1,102 +0,0 @@
<?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:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.profile.ChangePasswordActivity">
<include
android:id="@+id/headerStoreProduct"
layout="@layout/header" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="32dp"
android:paddingVertical="16dp">
<!-- Password label-->
<TextView
android:id="@+id/tv_password_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="@font/dmsans_medium"
android:text="Kata Sandi Lama"
android:textSize="18sp"
android:layout_marginVertical="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<!-- Password input -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_login_password"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
app:passwordToggleEnabled="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_password_label"
app:layout_constraintEnd_toEndOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_login_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Masukkan kata sandi akun"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Password label-->
<TextView
android:id="@+id/tv_new_password_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="@font/dmsans_medium"
android:text="Kata Sandi Baru"
android:textSize="18sp"
android:layout_marginVertical="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/til_login_password"
app:layout_constraintEnd_toEndOf="parent" />
<!-- Password input -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/til_login_new_password"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
app:passwordToggleEnabled="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_new_password_label"
app:layout_constraintEnd_toEndOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_login_new_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Masukkan kata sandi baru"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Change Pass button -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_change_pass"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Ubah Kata Sandi"
app:cornerRadius="8dp"
android:layout_marginVertical="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/til_login_new_password" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View File

@ -34,50 +34,69 @@
android:orientation="vertical">
<!-- Delivery Address Section -->
<com.google.android.material.card.MaterialCardView
<androidx.cardview.widget.CardView
android:id="@+id/card_delivery_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@color/white"
app:strokeColor="#E0E0E0"
app:strokeWidth="1dp">
android:layout_marginHorizontal="0dp"
android:layout_marginTop="0dp"
app:cardElevation="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp">
android:orientation="vertical"
android:padding="16dp"
android:background="@color/white">
<!-- Header Row -->
<LinearLayout
android:id="@+id/address_header"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_location_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/baseline_location_pin_24"
app:tint="@color/blue_300" />
android:layout_gravity="center_vertical"
app:tint="#3D84FF" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Alamat Pengiriman"
android:textSize="16sp"
android:fontFamily="@font/dmsans_medium"
android:layout_marginStart="8dp" />
</LinearLayout>
<TextView
android:id="@+id/tv_places_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="-"
android:textColor="#5A5A5A"
android:paddingHorizontal="8dp"
android:paddingVertical="2dp"
android:textSize="12sp"
android:layout_marginTop="8dp"
android:layout_marginStart="32dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="8dp">
<TextView
android:id="@+id/tv_address"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Alamat Pengiriman"
android:textSize="16sp"
android:textColor="@android:color/black"
android:fontFamily="@font/dmsans_medium"
android:layout_marginStart="12dp" />
android:text="-"
android:textSize="14sp"
android:layout_marginStart="32dp" />
<TextView
android:id="@+id/tv_change_address"
@ -85,441 +104,169 @@
android:layout_height="wrap_content"
android:text="Pilih Alamat"
android:textColor="#3D84FF"
android:textSize="14sp"
android:fontFamily="@font/dmsans_medium"
android:background="?attr/selectableItemBackgroundBorderless"
android:paddingHorizontal="8dp"
android:paddingVertical="4dp" />
android:textSize="14sp" />
</LinearLayout>
<!-- Empty Address State -->
<LinearLayout
android:id="@+id/container_empty_address"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="4dp"
android:gravity="center"
android:padding="8dp"
app:layout_constraintTop_toBottomOf="@id/address_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Belum ada alamat dipilih"
android:fontFamily="@font/dmsans_medium"
android:textColor="#757575"
android:textSize="14sp"
android:gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Pilih alamat pengiriman untuk melanjutkan"
android:textColor="#BDBDBD"
android:textSize="12sp"
android:gravity="center" />
</LinearLayout>
<!-- Selected Address Content -->
<LinearLayout
android:id="@+id/container_address"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="4dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/address_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<!-- Address Label -->
<TextView
android:id="@+id/tv_places_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rumah"
android:textColor="#3D84FF"
android:textSize="12sp"
android:fontFamily="@font/dmsans_medium"
android:background="@drawable/bg_edit_text_background"
android:paddingHorizontal="8dp"
android:paddingVertical="4dp"
tools:text="Rumah" />
<!-- Full Address -->
<TextView
android:id="@+id/tv_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Jl. Raya Serang No. 123, Kecamatan Serang, Kabupaten Serang, Banten 42111"
android:textSize="14sp"
android:textColor="@android:color/black"
android:lineSpacingExtra="2dp"
tools:text="Jl. Raya Serang No. 123, Kecamatan Serang, Kabupaten Serang, Banten 42111" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Product Items Section -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/card_product"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="8dp"
app:cardBackgroundColor="@color/white"
app:strokeColor="#E0E0E0"
app:strokeWidth="1dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp">
<!-- Header Row -->
<LinearLayout
android:id="@+id/product_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/baseline_local_grocery_store_24"
app:tint="@color/blue_300" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Produk Pesanan"
android:textSize="16sp"
android:textColor="@android:color/black"
android:fontFamily="@font/dmsans_medium"
android:layout_marginStart="12dp" />
</LinearLayout>
<!-- Empty Product State -->
<LinearLayout
android:id="@+id/container_empty_products"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="4dp"
android:gravity="center"
android:padding="8dp"
android:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/product_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Tidak ada produk"
android:fontFamily="@font/dmsans_medium"
android:textColor="#757575"
android:textSize="14sp"
android:gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="Keranjang belanja kosong"
android:textColor="#BDBDBD"
android:textSize="12sp"
android:gravity="center" />
</LinearLayout>
<!-- Products RecyclerView -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_product_items"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/product_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:listitem="@layout/item_order_seller" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/card_shipping_method"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="8dp"
app:cardBackgroundColor="@color/white"
app:strokeColor="#E0E0E0"
app:strokeWidth="1dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp">
<!-- Header Row -->
<LinearLayout
android:id="@+id/shipping_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Metode Pengiriman"
android:textSize="16sp"
android:textColor="@android:color/black"
android:fontFamily="@font/dmsans_medium"
android:layout_marginStart="12dp" />
<TextView
android:id="@+id/tv_shipping_option"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pilih"
android:textColor="#3D84FF"
android:textSize="14sp"
android:fontFamily="@font/dmsans_medium"
android:background="?attr/selectableItemBackgroundBorderless"
android:paddingHorizontal="8dp"
android:paddingVertical="4dp" />
</LinearLayout>
<!-- Empty Shipping State -->
<LinearLayout
android:id="@+id/container_empty_shipping"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="4dp"
android:gravity="center"
android:padding="12dp"
app:layout_constraintTop_toBottomOf="@id/shipping_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="Belum ada metode pengiriman"
android:fontFamily="@font/dmsans_medium"
android:textColor="#757575"
android:textSize="14sp"
android:gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Pilih alamat terlebih dahulu"
android:textColor="#BDBDBD"
android:textSize="12sp"
android:gravity="center" />
</LinearLayout>
<!-- Selected Shipping Content -->
<androidx.cardview.widget.CardView
android:id="@+id/card_shipment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:visibility="gone"
app:cardCornerRadius="8dp"
app:cardElevation="0dp"
app:cardBackgroundColor="#F5F5F5"
app:layout_constraintTop_toBottomOf="@id/shipping_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp">
<RadioButton
android:id="@+id/rb_jne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginStart="8dp">
<TextView
android:id="@+id/tv_courier_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="JNE"
android:textSize="16sp"
android:fontFamily="@font/dmsans_medium" />
<TextView
android:id="@+id/tv_delivery_estimate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3 - 4 hari kerja"
android:textSize="14sp"
android:textColor="#757575" />
</LinearLayout>
<TextView
android:id="@+id/tv_shipping_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp15.000"
android:textSize="16sp"
android:fontFamily="@font/dmsans_medium"
android:layout_gravity="center_vertical" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Payment Method Section -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/card_payment_method"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="8dp"
app:cardBackgroundColor="@color/white"
app:strokeColor="#E0E0E0"
app:strokeWidth="1dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp">
<!-- Header Row -->
<LinearLayout
android:id="@+id/payment_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/baseline_payment_24"
app:tint="@color/blue_300" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Metode Pembayaran"
android:textSize="16sp"
android:textColor="@android:color/black"
android:fontFamily="@font/dmsans_medium"
android:layout_marginStart="12dp" />
<TextView
android:id="@+id/tv_payment_option"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pilih"
android:textColor="#3D84FF"
android:textSize="14sp"
android:fontFamily="@font/dmsans_medium"
android:background="?attr/selectableItemBackgroundBorderless"
android:paddingHorizontal="8dp"
android:paddingVertical="4dp"
android:visibility="gone" />
</LinearLayout>
<!-- Empty Payment State -->
<LinearLayout
android:id="@+id/container_empty_payment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="4dp"
android:gravity="center"
android:padding="12dp"
app:layout_constraintTop_toBottomOf="@id/payment_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="Belum ada metode pembayaran"
android:fontFamily="@font/dmsans_medium"
android:textColor="#757575"
android:textSize="14sp"
android:gravity="center" />
<TextView
android:id="@+id/tvEmptyPayment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Pilih alamat terlebih dahulu"
android:textColor="#BDBDBD"
android:textSize="12sp"
android:gravity="center" />
</LinearLayout>
<!-- Payment Methods RecyclerView -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_payment_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/payment_header"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:listitem="@layout/item_payment_method" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</androidx.cardview.widget.CardView>
<View
android:layout_width="match_parent"
android:layout_height="8dp"
android:background="@color/black_50" />
<!-- Product Items Section -->
<androidx.cardview.widget.CardView
android:id="@+id/card_product"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardElevation="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="16dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_product_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
tools:listitem="@layout/item_order_seller" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<View
android:layout_width="match_parent"
android:layout_height="8dp"
android:background="#F5F5F5" />
<View
android:layout_width="match_parent"
android:layout_height="8dp"
android:background="@color/black_50" />
<!-- Shipping Method Section -->
<LinearLayout
android:id="@+id/layout_shipping_method"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Metode Pengiriman"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_shipping_option"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Opsi Pengiriman"
android:textColor="#3D84FF"
android:textSize="14sp" />
</LinearLayout>
<androidx.cardview.widget.CardView
android:id="@+id/card_shipment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:visibility="gone"
app:cardCornerRadius="8dp"
app:cardElevation="0dp"
app:cardBackgroundColor="#F5F5F5">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp">
<RadioButton
android:id="@+id/rb_jne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginStart="8dp">
<TextView
android:id="@+id/tv_courier_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="JNE"
android:textSize="16sp"
android:fontFamily="@font/dmsans_medium" />
<TextView
android:id="@+id/tv_delivery_estimate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3 - 4 hari kerja"
android:textSize="14sp"
android:textColor="#757575" />
</LinearLayout>
<TextView
android:id="@+id/tv_shipping_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp15.000"
android:textSize="16sp"
android:fontFamily="@font/dmsans_medium"
android:layout_gravity="center_vertical" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="8dp"
android:background="@color/black_50" />
<!-- Payment Method Section -->
<LinearLayout
android:id="@+id/layout_payment_method"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Metode Pembayaran"
android:textSize="14sp"
android:layout_marginBottom="8dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_payment_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/item_payment_method" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="8dp"
android:layout_marginVertical="8dp"
android:background="@color/black_50" />
<!-- Price Summary Section -->
@ -547,7 +294,7 @@
android:id="@+id/tv_item_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp0"
android:text="Rp65.000"
android:textSize="14sp" />
</LinearLayout>
@ -568,7 +315,7 @@
android:id="@+id/tv_shipping_fee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp0"
android:text="Rp15.000"
android:textSize="14sp" />
</LinearLayout>
@ -595,8 +342,8 @@
android:id="@+id/tv_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp0"
android:textColor="@color/blue_400"
android:text="Rp75.000"
android:textColor="#3D84FF"
android:textSize="16sp"
android:fontFamily="@font/dmsans_bold" />
</LinearLayout>
@ -632,7 +379,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp75.000"
android:textColor="@color/blue_400"
android:textColor="#3D84FF"
android:textSize="18sp"
android:fontFamily="@font/dmsans_bold" />
</LinearLayout>
@ -645,7 +392,7 @@
android:textAllCaps="false"
android:paddingHorizontal="32dp"
app:cornerRadius="8dp"
android:backgroundTint="@color/blue_500" />
android:backgroundTint="#3D84FF" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -231,18 +231,6 @@
android:textSize="14sp" />
</LinearLayout>
<TextView
android:id="@+id/empty_review"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Belum ada ulasan"
android:textSize="16sp"
android:textColor="@color/black_200"
android:gravity="center"
android:visibility="gone"
android:fontFamily="@font/dmsans_mediumitalic"
android:layout_marginTop="8dp"/>
<!-- RecyclerView for Reviews -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewReviews"
@ -397,13 +385,6 @@
android:orientation="horizontal"
android:padding="16dp">
<ProgressBar
android:id="@+id/progress_bar_detail_store"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_gravity="center"/>
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/ivSellerImage"
android:layout_width="48dp"
@ -496,18 +477,6 @@
android:textSize="14sp" />
</LinearLayout>
<TextView
android:id="@+id/empty_other_products"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Belum ada produk lainnya"
android:textSize="16sp"
android:textColor="@color/black_200"
android:gravity="center"
android:visibility="gone"
android:fontFamily="@font/dmsans_mediumitalic"
android:layout_marginTop="8dp"/>
<!-- RecyclerView for Other Products -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewOtherProducts"

View File

@ -62,7 +62,7 @@
android:id="@+id/profile_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/baseline_account_circle_100"
android:src="@drawable/baseline_account_circle_24"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
@ -87,7 +87,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ubah Profil"
style="@style/button.large.active.medium"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/profile_image"
app:layout_constraintStart_toStartOf="parent"

View File

@ -61,7 +61,7 @@
android:id="@+id/profile_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/baseline_account_circle_100"
android:src="@drawable/baseline_account_circle_24"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
@ -188,7 +188,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Simpan"
style="@style/button.large.active.medium"
android:layout_marginTop="32dp"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="16dp"

View File

@ -136,7 +136,6 @@
android:id="@+id/tv_registrasi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/signup"
android:textColor="@color/blue1"
android:textStyle="bold" />

View File

@ -69,35 +69,6 @@
</LinearLayout>
<LinearLayout
android:id="@+id/layout_rejected"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="vertical"
android:gravity="center"
android:background="@drawable/bg_product_active"
android:padding="8dp"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/label_small"
android:textAlignment="center"
android:text="Permintaan Buka Toko Anda sebelumnya ditolak! Silahkan lakukan penyesuaian berdasarkan alasan berikut:"/>
<TextView
android:id="@+id/tv_rejected_reason"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/body_medium"
android:fontFamily="@font/dmsans_bold"
android:layout_marginTop="8dp"
android:text="KTP tidak sesuai"/>
</LinearLayout>
<!-- Nama Toko -->
<LinearLayout
android:layout_width="match_parent"

View File

@ -15,207 +15,156 @@
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent" />
<!-- Store Information Card -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/storeInfoCard"
android:layout_width="0dp"
<!-- Store Information -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/storeInfoContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="16dp"
app:cardBackgroundColor="@android:color/white"
app:cardCornerRadius="16dp"
app:cardElevation="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:background="@color/blue_50"
android:layout_marginTop="16dp"
android:padding="24dp"
app:layout_constraintTop_toBottomOf="@id/searchContainer">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/storeInfoContainer"
android:layout_width="match_parent"
<ImageView
android:id="@+id/ivStoreImage"
android:layout_width="64dp"
android:layout_height="64dp"
android:background="@drawable/circle_background"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/placeholder_image" />
<TextView
android:id="@+id/tvStoreName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="24dp">
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/ivStoreImage"
app:layout_constraintTop_toTopOf="@id/ivStoreImage"
tools:text="SnackEnak" />
<!-- Store Image with Material Card wrapper -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/storeImageCard"
android:layout_width="80dp"
android:layout_height="80dp"
app:cardCornerRadius="16dp"
app:cardElevation="2dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/tvStoreType"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/ivStoreImage"
app:layout_constraintTop_toBottomOf="@id/tvStoreName"
tools:text="Makanan Ringan" />
<ImageView
android:id="@+id/ivStoreImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:src="@drawable/placeholder_image" />
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:id="@+id/storeRatingContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintStart_toEndOf="@id/ivStoreImage"
app:layout_constraintTop_toBottomOf="@id/tvStoreType">
<ImageView
android:id="@+id/ivStoreRatingStar"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_star"
app:tint="@color/yellow" />
<!-- Store Name -->
<TextView
android:id="@+id/tvStoreName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@android:color/black"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/storeImageCard"
app:layout_constraintTop_toTopOf="@id/storeImageCard"
tools:text="SnackEnak Store" />
<!-- Store Type -->
<TextView
android:id="@+id/tvStoreType"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:background="@drawable/search_background"
android:paddingStart="12dp"
android:paddingTop="4dp"
android:paddingEnd="12dp"
android:paddingBottom="4dp"
android:textColor="@color/blue_500"
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/storeImageCard"
app:layout_constraintTop_toBottomOf="@id/tvStoreName"
tools:text="Makanan Ringan" />
<!-- Rating Container -->
<LinearLayout
android:id="@+id/storeRatingContainer"
android:id="@+id/tvStoreRating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintStart_toEndOf="@id/storeImageCard"
app:layout_constraintTop_toBottomOf="@id/tvStoreType">
android:layout_marginStart="4dp"
android:textSize="12sp"
android:textStyle="bold"
tools:text="5.0" />
</LinearLayout>
<ImageView
android:id="@+id/ivStoreRatingStar"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_star"
app:tint="@color/yellow" />
<TextView
android:id="@+id/tvStoreLocation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:textSize="12sp"
app:layout_constraintEnd_toStartOf="@id/tvActiveStatus"
app:layout_constraintStart_toEndOf="@id/ivStoreImage"
app:layout_constraintTop_toBottomOf="@id/storeRatingContainer"
tools:text="Kabupaten Serang" />
<TextView
android:id="@+id/tvStoreRating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textColor="@android:color/black"
android:textSize="14sp"
android:textStyle="bold"
tools:text="4.8" />
</LinearLayout>
<TextView
android:id="@+id/tvActiveStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:text="Aktif"
android:textColor="@android:color/black"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@id/tvStoreLocation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tvStoreLocation" />
<!-- Location and Status Row -->
<LinearLayout
android:id="@+id/locationStatusContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="16dp"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/storeImageCard"
app:layout_constraintTop_toBottomOf="@id/storeRatingContainer">
<!-- Location with Icon -->
<ImageView
android:layout_width="14dp"
android:layout_height="14dp"
android:src="@drawable/ic_location"
app:tint="@color/black_300" />
<TextView
android:id="@+id/tvStoreLocation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/blue_400"
android:textSize="13sp"
tools:text="Kabupaten Serang" />
<!-- Status Indicator -->
<View
android:id="@+id/statusDot"
android:layout_width="6dp"
android:layout_height="6dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="6dp"
android:background="@drawable/baseline_circle_24"
android:backgroundTint="@color/black_300"/>
<TextView
android:id="@+id/tvActiveStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/blue_500"
android:textSize="12sp"
android:fontFamily="@font/dmsans_semibold"
tools:text="Aktif" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Divider -->
<!-- <ImageButton-->
<!-- android:id="@+id/btnChevron"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:background="?attr/selectableItemBackgroundBorderless"-->
<!-- android:contentDescription="More"-->
<!-- android:src="@drawable/ic_chevron_right"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent" />-->
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.divider.MaterialDivider
android:id="@+id/divider_product"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:dividerColor="@color/black_200"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/storeInfoCard" />
app:layout_constraintTop_toBottomOf="@id/storeInfoContainer"/>
<ProgressBar
android:id="@+id/progress_bar_detail_prod_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/divider_product"/>
<!-- Tab Layout: TO DO implement after review -->
<!-- <com.google.android.material.tabs.TabLayout-->
<!-- android:id="@+id/tabLayout"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:layout_constraintTop_toBottomOf="@id/storeInfoContainer"-->
<!-- app:tabIndicatorColor="@color/colorPrimary"-->
<!-- app:tabSelectedTextColor="@color/colorPrimary"-->
<!-- app:tabTextColor="@android:color/darker_gray">-->
<!-- <com.google.android.material.tabs.TabItem-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="Produk" />-->
<!-- <com.google.android.material.tabs.TabItem-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="Kategori" />-->
<!-- </com.google.android.material.tabs.TabLayout>-->
<!-- Products RecyclerView -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_products"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:clipToPadding="false"
android:paddingBottom="16dp"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/divider_product"
app:spanCount="2"
tools:listitem="@layout/item_product_grid" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -168,13 +168,8 @@
app:layout_constraintTop_toBottomOf="@id/searchContainer" />
<include
android:id="@+id/loadingAll"
layout="@layout/view_loading"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
android:id="@+id/loading"
layout="@layout/view_loading"/>
<include
android:id="@+id/error"

View File

@ -304,55 +304,6 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<!-- Change Password Card -->
<androidx.cardview.widget.CardView
android:id="@+id/card_change_pass"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:foreground="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<ImageView
android:id="@+id/ivChangePass"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_change_pass"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/tvChangePass"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Ubah Kata Sandi"
android:textSize="14sp"
app:layout_constraintStart_toEndOf="@id/ivChangePass"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/ivChangePassArrow" />
<ImageView
android:id="@+id/ivChangePassArrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_right"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<!-- About Card -->
<androidx.cardview.widget.CardView
android:id="@+id/card_about"

View File

@ -50,9 +50,8 @@
android:id="@+id/et_otp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Masukkan OTP"
android:hint="Enter OTP"
android:inputType="number"
android:textSize="16dp"
android:textAlignment="center"
android:maxLength="6" />
</com.google.android.material.textfield.TextInputLayout>
@ -62,19 +61,9 @@
android:id="@+id/btn_verify"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Kirim kode OTP"
style="@style/button.large.active.medium"
android:text="Verify"
app:cornerRadius="8dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_back"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
android:text="Kembali"
app:cornerRadius="8dp"/>
<!-- Resend OTP -->
<LinearLayout
android:layout_width="match_parent"
@ -92,7 +81,7 @@
android:id="@+id/tv_resend_otp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kirim Ulang"
android:text="Resend"
android:textColor="@color/blue1"
android:textStyle="bold" />
</LinearLayout>

View File

@ -233,12 +233,6 @@
android:padding="12dp"
android:textSize="14sp" />
<CheckBox
android:id="@+id/checkbox_approve"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Saya telah membaca dan menyetujui Syarat dan Ketentuan aplikasi" />
<!-- Navigation Button (Previous) -->
<Button
android:id="@+id/btn_previous"
@ -246,14 +240,24 @@
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:background="@drawable/bg_button_outline"
android:visibility="gone"
android:text="Kembali"
android:textAllCaps="false"
android:textColor="@color/blue1"
style="@style/Widget.Material3.Button.OutlinedButton.Icon"/>
style="@style/Widget.MaterialComponents.Button.OutlinedButton"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<CheckBox
android:id="@+id/checkbox_approve"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Saya telah membaca dan menyetujui Syarat dan Ketentuan aplikasi" />
</LinearLayout>
</ScrollView>
<!-- Register Button -->

View File

@ -9,9 +9,10 @@
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:gravity="start"
android:layout_marginStart="16dp"
android:layout_marginVertical="8dp"
android:layout_marginBottom="4dp"
android:layout_gravity="center_horizontal"
android:orientation="horizontal">
<RadioButton
@ -23,54 +24,39 @@
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:weightSum="1">
<!-- Left Section -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:orientation="vertical">
<TextView
android:id="@+id/courier_name_cost"
android:fontFamily="@font/dmsans_semibold"
android:textSize="14sp"
android:paddingHorizontal="2dp"
android:paddingTop="4dp"
android:ellipsize="end"
android:scrollHorizontally="false"
android:singleLine="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:text="JNE Express"/>
<TextView
android:id="@+id/est_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:paddingHorizontal="4dp"
android:text="Estimasi 3-4 hari"/>
</LinearLayout>
<!-- Right Section -->
android:orientation="vertical">
<TextView
android:id="@+id/cost_price"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.3"
android:textSize="14sp"
android:gravity="start"
android:id="@+id/courier_name_cost"
android:fontFamily="@font/dmsans_semibold"
android:text="Rp15.000"/>
android:textSize="20sp"
android:padding="4dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="JNE"/>
<TextView
android:id="@+id/est_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:paddingHorizontal="8dp"
android:text="Estimasi 3-4 hari"/>
</LinearLayout>
<TextView
android:id="@+id/cost_price"
android:textSize="16sp"
android:gravity="center_vertical"
android:layout_margin="16dp"
android:fontFamily="@font/dmsans_semibold"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Rp15.0000"/>
</LinearLayout>
<View

View File

@ -22,8 +22,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Muat Ulang"
style="@style/Widget.Material3.FloatingActionButton.Large.Surface"
android:text="Retry"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@ -6,13 +6,12 @@
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="8dp"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -269,7 +269,7 @@
</style>
<style name="button.small.active.short">
<item name="android:layout_width">100dp</item>
<item name="android:layout_width">144dp</item>
</style>
<style name="button.small.active.short.only_icon">

BIN
unduh/PasarKlik_v2.apk Normal file

Binary file not shown.