mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-08-10 09:22:21 +00:00
fix bug
This commit is contained in:
3
app/.gitignore
vendored
3
app/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/build
|
/build
|
||||||
|
google-services.json
|
@ -15,10 +15,14 @@ class ApiConfig {
|
|||||||
|
|
||||||
val loggingInterceptor = HttpLoggingInterceptor().apply {
|
val loggingInterceptor = HttpLoggingInterceptor().apply {
|
||||||
level = HttpLoggingInterceptor.Level.BODY
|
level = HttpLoggingInterceptor.Level.BODY
|
||||||
|
//httplogginginterceptor ntuk debug dan monitoring request/response
|
||||||
}
|
}
|
||||||
|
|
||||||
val authInterceptor = AuthInterceptor(tokenManager)
|
val authInterceptor = AuthInterceptor(tokenManager)
|
||||||
|
// utk tambak token auth otomatis pada header
|
||||||
|
|
||||||
|
// Konfigurasi OkHttpClient
|
||||||
|
//Low-level HTTP client yang melakukan actual network request
|
||||||
val client = OkHttpClient.Builder()
|
val client = OkHttpClient.Builder()
|
||||||
.addInterceptor(loggingInterceptor)
|
.addInterceptor(loggingInterceptor)
|
||||||
.addInterceptor(authInterceptor)
|
.addInterceptor(authInterceptor)
|
||||||
@ -27,13 +31,17 @@ class ApiConfig {
|
|||||||
.writeTimeout(300, TimeUnit.SECONDS) // 5 minutes
|
.writeTimeout(300, TimeUnit.SECONDS) // 5 minutes
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
// Konfigurasi Retrofit
|
||||||
val retrofit = Retrofit.Builder()
|
val retrofit = Retrofit.Builder()
|
||||||
|
//almat domain backend
|
||||||
.baseUrl(BuildConfig.BASE_URL)
|
.baseUrl(BuildConfig.BASE_URL)
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
//gson convertes: mengkonversi JSON ke object Kotlin dan sebaliknya
|
||||||
.client(client)
|
.client(client)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return retrofit.create(ApiService::class.java)
|
return retrofit.create(ApiService::class.java)
|
||||||
|
// retrofit : menyederhanakan HTTP Request dgn mengubah interface Kotlin di ApiService menjadi HTTP calls secara otomatis
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUnauthenticatedApiService(): ApiService {
|
fun getUnauthenticatedApiService(): ApiService {
|
||||||
|
@ -8,9 +8,7 @@ import android.widget.Toast
|
|||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.ViewCompat
|
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import com.alya.ecommerce_serang.data.api.dto.FcmReq
|
import com.alya.ecommerce_serang.data.api.dto.FcmReq
|
||||||
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
|
||||||
import com.alya.ecommerce_serang.data.repository.Result
|
import com.alya.ecommerce_serang.data.repository.Result
|
||||||
@ -43,20 +41,18 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|
||||||
// Apply insets to your root layout
|
// ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
|
// val systemBars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
val systemBars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
// view.setPadding(
|
||||||
view.setPadding(
|
// systemBars.left,
|
||||||
systemBars.left,
|
// systemBars.top,
|
||||||
systemBars.top,
|
// systemBars.right,
|
||||||
systemBars.right,
|
// systemBars.bottom
|
||||||
systemBars.bottom
|
// )
|
||||||
)
|
// windowInsets
|
||||||
windowInsets
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
// onBackPressedDispatcher.addCallback(this) {
|
// onBackPressedDispatcher.addCallback(this) {
|
||||||
// // Handle the back button event
|
// // Handle the back button event
|
||||||
|
@ -43,24 +43,6 @@ class RegisterActivity : AppCompatActivity() {
|
|||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
sessionManager = SessionManager(this)
|
sessionManager = SessionManager(this)
|
||||||
|
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
|
||||||
|
|
||||||
enableEdgeToEdge()
|
|
||||||
|
|
||||||
// Apply insets to your root layout
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
|
|
||||||
val systemBars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
|
||||||
view.setPadding(
|
|
||||||
systemBars.left,
|
|
||||||
systemBars.top,
|
|
||||||
systemBars.right,
|
|
||||||
systemBars.bottom
|
|
||||||
)
|
|
||||||
windowInsets
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Log.d("RegisterActivity", "Token in storage: '${sessionManager.getToken()}'")
|
Log.d("RegisterActivity", "Token in storage: '${sessionManager.getToken()}'")
|
||||||
Log.d("RegisterActivity", "User ID in storage: '${sessionManager.getUserId()}'")
|
Log.d("RegisterActivity", "User ID in storage: '${sessionManager.getUserId()}'")
|
||||||
|
|
||||||
@ -104,7 +86,7 @@ class RegisterActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to navigate to the next fragment
|
// navigate step register in fragment
|
||||||
fun navigateToStep(step: Int, userData: RegisterRequest?) {
|
fun navigateToStep(step: Int, userData: RegisterRequest?) {
|
||||||
val fragment = when (step) {
|
val fragment = when (step) {
|
||||||
1 -> RegisterStep1Fragment.newInstance()
|
1 -> RegisterStep1Fragment.newInstance()
|
||||||
|
@ -204,6 +204,13 @@ class RegisterStep1Fragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerViewModel.toastMessage.observe(viewLifecycleOwner){ event ->
|
||||||
|
//memanggil toast check value email dan phone
|
||||||
|
event.getContentIfNotHandled()?.let { msg ->
|
||||||
|
Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateAndProceed() {
|
private fun validateAndProceed() {
|
||||||
|
@ -252,15 +252,10 @@ class RegisterStep2Fragment : Fragment() {
|
|||||||
sessionManager.saveToken(accessToken)
|
sessionManager.saveToken(accessToken)
|
||||||
Log.d(TAG, "Token saved to SessionManager: $accessToken")
|
Log.d(TAG, "Token saved to SessionManager: $accessToken")
|
||||||
|
|
||||||
// Also save user ID if available in the login response
|
|
||||||
// result.data.?.let { userId ->
|
|
||||||
// sessionManager.saveUserId(userId)
|
|
||||||
// }
|
|
||||||
|
|
||||||
Log.d(TAG, "Login successful, token saved: $accessToken")
|
|
||||||
|
|
||||||
// Proceed to Step 3
|
// Proceed to Step 3
|
||||||
Log.d(TAG, "Proceeding to Step 3 after successful login")
|
Log.d(TAG, "Proceeding to Step 3 after successful login")
|
||||||
|
|
||||||
|
// call navigate register step from activity
|
||||||
(activity as? RegisterActivity)?.navigateToStep(3, null )
|
(activity as? RegisterActivity)?.navigateToStep(3, null )
|
||||||
}
|
}
|
||||||
is Result.Error -> {
|
is Result.Error -> {
|
||||||
@ -270,7 +265,7 @@ class RegisterStep2Fragment : Fragment() {
|
|||||||
|
|
||||||
// Show error message but continue to Step 3 anyway
|
// Show error message but continue to Step 3 anyway
|
||||||
Log.e(TAG, "Login failed but proceeding to Step 3", result.exception)
|
Log.e(TAG, "Login failed but proceeding to Step 3", result.exception)
|
||||||
Toast.makeText(requireContext(), "Gagal login, namun berhasil membuat akun", Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), "Berhasil membuat akun, namun belum login", Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
// Proceed to Step 3
|
// Proceed to Step 3
|
||||||
(activity as? RegisterActivity)?.navigateToStep(3, null)
|
(activity as? RegisterActivity)?.navigateToStep(3, null)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.alya.ecommerce_serang.ui.cart
|
package com.alya.ecommerce_serang.ui.cart
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
@ -153,7 +154,8 @@ class CartActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.isLoading.observe(this) { isLoading ->
|
viewModel.isLoading.observe(this) { isLoading ->
|
||||||
// Show/hide loading indicator if needed
|
binding.progressBarCart?.visibility = if (isLoading) View.VISIBLE else View.GONE
|
||||||
|
Log.d("CartActivity", "Loading state: $isLoading")
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.errorMessage.observe(this) { errorMessage ->
|
viewModel.errorMessage.observe(this) { errorMessage ->
|
||||||
|
@ -129,6 +129,7 @@ class ChatActivity : AppCompatActivity() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set up data toko
|
||||||
binding.tvStoreName.text = storeName
|
binding.tvStoreName.text = storeName
|
||||||
val fullImageUrl = when (val img = storeImg) {
|
val fullImageUrl = when (val img = storeImg) {
|
||||||
is String -> {
|
is String -> {
|
||||||
@ -142,7 +143,7 @@ class ChatActivity : AppCompatActivity() {
|
|||||||
.placeholder(R.drawable.placeholder_image)
|
.placeholder(R.drawable.placeholder_image)
|
||||||
.into(binding.imgProfile)
|
.into(binding.imgProfile)
|
||||||
|
|
||||||
// Set chat parameters to ViewModel
|
// Set chat parameter to send to ViewModel with product
|
||||||
viewModel.setChatParameters(
|
viewModel.setChatParameters(
|
||||||
storeId = storeId,
|
storeId = storeId,
|
||||||
productId = productId,
|
productId = productId,
|
||||||
@ -159,10 +160,12 @@ class ChatActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup UI components
|
// Setup UI components
|
||||||
|
// rv isi chat
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
setupWindowInsets()
|
setupWindowInsets()
|
||||||
setupListeners()
|
setupListeners()
|
||||||
setupTypingIndicator()
|
setupTypingIndicator()
|
||||||
|
// observe listener from viewmodel
|
||||||
observeViewModel()
|
observeViewModel()
|
||||||
|
|
||||||
// If opened from ChatListFragment with a valid chatRoomId
|
// If opened from ChatListFragment with a valid chatRoomId
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.alya.ecommerce_serang.ui.chat
|
package com.alya.ecommerce_serang.ui.chat
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -55,31 +56,44 @@ class ChatListFragment : Fragment() {
|
|||||||
viewModel.chatList.observe(viewLifecycleOwner) { result ->
|
viewModel.chatList.observe(viewLifecycleOwner) { result ->
|
||||||
when (result) {
|
when (result) {
|
||||||
is Result.Success -> {
|
is Result.Success -> {
|
||||||
val adapter = ChatListAdapter(result.data) { chatItem ->
|
val data = result.data
|
||||||
// Use the ChatActivity.createIntent factory method for proper navigation
|
|
||||||
ChatActivity.createIntent(
|
binding.tvEmptyChat.visibility = View.GONE
|
||||||
context = requireActivity(),
|
if (data.isNotEmpty()) {
|
||||||
storeId = chatItem.storeId,
|
val adapter = ChatListAdapter(data) { chatItem ->
|
||||||
productId = 0, // Default value since we don't have it in ChatListItem
|
ChatActivity.createIntent(
|
||||||
productName = null, // Null is acceptable as per ChatActivity
|
context = requireActivity(),
|
||||||
productPrice = "",
|
storeId = chatItem.storeId,
|
||||||
productImage = null,
|
productId = 0,
|
||||||
productRating = null,
|
productName = null,
|
||||||
storeName = chatItem.storeName,
|
productPrice = "",
|
||||||
chatRoomId = chatItem.chatRoomId,
|
productImage = null,
|
||||||
storeImage = chatItem.storeImage
|
productRating = null,
|
||||||
)
|
storeName = chatItem.storeName,
|
||||||
|
chatRoomId = chatItem.chatRoomId,
|
||||||
|
storeImage = chatItem.storeImage
|
||||||
|
)
|
||||||
|
}
|
||||||
|
binding.chatListRecyclerView.adapter = adapter
|
||||||
|
} else {
|
||||||
|
binding.tvEmptyChat.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
binding.chatListRecyclerView.adapter = adapter
|
|
||||||
}
|
}
|
||||||
is Result.Error -> {
|
is Result.Error -> {
|
||||||
|
binding.tvEmptyChat.visibility = View.VISIBLE
|
||||||
Toast.makeText(requireContext(), "Failed to load chats", Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), "Failed to load chats", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
Result.Loading -> {
|
Result.Loading -> {
|
||||||
|
binding.progressBarChat.visibility = View.VISIBLE
|
||||||
// Optional: show progress bar
|
// Optional: show progress bar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//loading chat list
|
||||||
|
viewModel.isLoading.observe(viewLifecycleOwner) { isLoading ->
|
||||||
|
binding.progressBarChat?.visibility = if (isLoading) View.VISIBLE else View.GONE
|
||||||
|
Log.d(TAG, "Loading state: $isLoading")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -89,6 +103,6 @@ class ChatListFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object{
|
companion object{
|
||||||
|
private var TAG = "ChatListFragment"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -60,6 +60,9 @@ class ChatViewModel @Inject constructor(
|
|||||||
private val _state = MutableLiveData(ChatUiState())
|
private val _state = MutableLiveData(ChatUiState())
|
||||||
val state: LiveData<ChatUiState> = _state
|
val state: LiveData<ChatUiState> = _state
|
||||||
|
|
||||||
|
private val _isLoading = MutableLiveData<Boolean>()
|
||||||
|
val isLoading: LiveData<Boolean> = _isLoading
|
||||||
|
|
||||||
val _chatRoomId = MutableLiveData<Int>(0)
|
val _chatRoomId = MutableLiveData<Int>(0)
|
||||||
val chatRoomId: LiveData<Int> = _chatRoomId
|
val chatRoomId: LiveData<Int> = _chatRoomId
|
||||||
|
|
||||||
@ -94,12 +97,15 @@ class ChatViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeUser() {
|
private fun initializeUser() {
|
||||||
|
_isLoading.value = true
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
Log.d(TAG, "Initializing user session...")
|
Log.d(TAG, "Initializing user session...")
|
||||||
|
|
||||||
when (val result = chatRepository.fetchUserProfile()) {
|
when (val result = chatRepository.fetchUserProfile()) {
|
||||||
is Result.Success -> {
|
is Result.Success -> {
|
||||||
currentUserId = result.data?.userId
|
currentUserId = result.data?.userId
|
||||||
|
_isLoading.value = false
|
||||||
|
|
||||||
Log.d(TAG, "User session initialized - User ID: $currentUserId")
|
Log.d(TAG, "User session initialized - User ID: $currentUserId")
|
||||||
|
|
||||||
if (currentUserId == null || currentUserId == 0) {
|
if (currentUserId == null || currentUserId == 0) {
|
||||||
@ -111,10 +117,12 @@ class ChatViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Result.Error -> {
|
is Result.Error -> {
|
||||||
|
_isLoading.value = false
|
||||||
Log.e(TAG, "Failed to fetch user profile: ${result.exception.message}")
|
Log.e(TAG, "Failed to fetch user profile: ${result.exception.message}")
|
||||||
updateState { it.copy(error = "User authentication error. Please login again.") }
|
updateState { it.copy(error = "User authentication error. Please login again.") }
|
||||||
}
|
}
|
||||||
is Result.Loading -> {
|
is Result.Loading -> {
|
||||||
|
_isLoading.value = true
|
||||||
Log.d(TAG, "Loading user profile...")
|
Log.d(TAG, "Loading user profile...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,10 +343,13 @@ class ChatViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getChatList() {
|
fun getChatList() {
|
||||||
|
_isLoading.value = true
|
||||||
Log.d(TAG, "Getting chat list...")
|
Log.d(TAG, "Getting chat list...")
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_chatList.value = Result.Loading
|
// _chatList.value = Result.Loading
|
||||||
_chatList.value = chatRepository.getListChat()
|
_chatList.value = chatRepository.getListChat()
|
||||||
|
_isLoading.value = false
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,25 +208,6 @@ class HomeFragment : Fragment() {
|
|||||||
private fun initUi() {
|
private fun initUi() {
|
||||||
// For LightStatusBar
|
// For LightStatusBar
|
||||||
setLightStatusBar()
|
setLightStatusBar()
|
||||||
// val banners = binding.banners
|
|
||||||
// banners.offscreenPageLimit = 1
|
|
||||||
//
|
|
||||||
// val nextItemVisiblePx = resources.getDimension(R.dimen.viewpager_next_item_visible)
|
|
||||||
// val currentItemHorizontalMarginPx =
|
|
||||||
// resources.getDimension(R.dimen.viewpager_current_item_horizontal_margin)
|
|
||||||
// val pageTranslationX = nextItemVisiblePx + currentItemHorizontalMarginPx
|
|
||||||
//
|
|
||||||
// banners.setPageTransformer { page, position ->
|
|
||||||
// page.translationX = -pageTranslationX * position
|
|
||||||
// page.scaleY = 1 - (0.25f * kotlin.math.abs(position))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// banners.addItemDecoration(
|
|
||||||
// HorizontalMarginItemDecoration(
|
|
||||||
// requireContext(),
|
|
||||||
// R.dimen.viewpager_current_item_horizontal_margin
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleProductClick(product: ProductsItem) {
|
private fun handleProductClick(product: ProductsItem) {
|
||||||
@ -248,8 +229,4 @@ class HomeFragment : Fragment() {
|
|||||||
categoryAdapter = null
|
categoryAdapter = null
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// private fun showLoading(isLoading: Boolean) {
|
|
||||||
// binding.progressBar.isVisible = isLoading
|
|
||||||
// }
|
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
@ -110,11 +111,6 @@ class CheckoutActivity : AppCompatActivity() {
|
|||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// viewModel.getPaymentMethods { paymentMethods ->
|
|
||||||
// // Logging is just for debugging
|
|
||||||
// Log.d("CheckoutActivity", "Loaded ${paymentMethods.size} payment methods")
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupToolbar() {
|
private fun setupToolbar() {
|
||||||
@ -165,7 +161,7 @@ class CheckoutActivity : AppCompatActivity() {
|
|||||||
// Observe loading state
|
// Observe loading state
|
||||||
viewModel.isLoading.observe(this) { isLoading ->
|
viewModel.isLoading.observe(this) { isLoading ->
|
||||||
binding.btnPay.isEnabled = !isLoading
|
binding.btnPay.isEnabled = !isLoading
|
||||||
// Show/hide loading indicator if you have one
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Observe error messages
|
// Observe error messages
|
||||||
@ -273,10 +269,14 @@ class CheckoutActivity : AppCompatActivity() {
|
|||||||
private fun updateShippingUI(shipName: String, shipService: String, shipEtd: String, shipPrice: Int) {
|
private fun updateShippingUI(shipName: String, shipService: String, shipEtd: String, shipPrice: Int) {
|
||||||
if (shipName.isNotEmpty() && shipService.isNotEmpty()) {
|
if (shipName.isNotEmpty() && shipService.isNotEmpty()) {
|
||||||
// Display shipping name and service in one line
|
// Display shipping name and service in one line
|
||||||
|
binding.cardShipment.visibility = View.VISIBLE
|
||||||
|
|
||||||
binding.tvCourierName.text = "$shipName $shipService"
|
binding.tvCourierName.text = "$shipName $shipService"
|
||||||
binding.tvDeliveryEstimate.text = "$shipEtd hari kerja"
|
binding.tvDeliveryEstimate.text = "$shipEtd hari kerja"
|
||||||
binding.tvShippingPrice.text = formatCurrency(shipPrice.toDouble())
|
binding.tvShippingPrice.text = formatCurrency(shipPrice.toDouble())
|
||||||
binding.rbJne.isChecked = true
|
binding.rbJne.isChecked = true
|
||||||
|
} else {
|
||||||
|
binding.cardShipment.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,9 @@ import com.google.gson.Gson
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
@ -197,12 +200,12 @@ class DetailOrderStatusActivity : AppCompatActivity() {
|
|||||||
Log.d(TAG, "populateOrderDetails: Payment method=${orders.payInfoName ?: "Tidak tersedia"}")
|
Log.d(TAG, "populateOrderDetails: Payment method=${orders.payInfoName ?: "Tidak tersedia"}")
|
||||||
|
|
||||||
// Set subtotal, shipping cost, and total
|
// Set subtotal, shipping cost, and total
|
||||||
val subtotal = orders.totalAmount?.minus(orders.shipmentPrice.toIntOrNull() ?: 0) ?: 0
|
// val subtotal = orders.totalAmount?.minus(orders.shipmentPrice.toDouble() ?: 0) ?: 0
|
||||||
binding.tvSubtotal.text = formatCurrency(subtotal.toDouble())
|
// binding.tvSubtotal.text = formatCurrency(subtotal.toDouble())
|
||||||
binding.tvShippingCost.text = formatCurrency(orders.shipmentPrice.toDouble())
|
binding.tvShippingCost.text = formatCurrency(orders.shipmentPrice.toDouble())
|
||||||
binding.tvTotal.text = formatCurrency(orders.totalAmount?.toDouble() ?: 0.00)
|
binding.tvTotal.text = formatCurrency(orders.totalAmount?.toDouble() ?: 0.00)
|
||||||
|
|
||||||
Log.d(TAG, "populateOrderDetails: Subtotal=$subtotal, Shipping=${orders.shipmentPrice}, Total=${orders.totalAmount}")
|
Log.d(TAG, "populateOrderDetails: Subtotal=, Shipping=${orders.shipmentPrice}, Total=${orders.totalAmount}")
|
||||||
|
|
||||||
// Adjust buttons based on order status
|
// Adjust buttons based on order status
|
||||||
Log.d(TAG, "populateOrderDetails: Adjusting buttons for status=$orderStatus")
|
Log.d(TAG, "populateOrderDetails: Adjusting buttons for status=$orderStatus")
|
||||||
@ -223,6 +226,11 @@ class DetailOrderStatusActivity : AppCompatActivity() {
|
|||||||
this.adapter = adapter
|
this.adapter = adapter
|
||||||
}
|
}
|
||||||
adapter.submitList(orderItems)
|
adapter.submitList(orderItems)
|
||||||
|
|
||||||
|
// get data from ordetlistitemsitem untuk ambil subtotal nya dan dijumlahkan
|
||||||
|
val subtotalSum = orderItems.sumOf { it.subtotal }
|
||||||
|
binding.tvSubtotal.text = formatCurrency(subtotalSum.toDouble())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun adjustButtonsBasedOnStatus(orders: Orders, status: String) {
|
private fun adjustButtonsBasedOnStatus(orders: Orders, status: String) {
|
||||||
@ -287,7 +295,7 @@ class DetailOrderStatusActivity : AppCompatActivity() {
|
|||||||
// Show status note
|
// Show status note
|
||||||
binding.tvStatusHeader.text = "Sudah Dibayar"
|
binding.tvStatusHeader.text = "Sudah Dibayar"
|
||||||
binding.tvStatusNote.visibility = View.VISIBLE
|
binding.tvStatusNote.visibility = View.VISIBLE
|
||||||
binding.tvStatusNote.text = "Menunggu pesanan dikonfirmasi penjual ${formatDatePay(orders.updatedAt)}"
|
binding.tvStatusNote.text = "Menunggu pesanan dikonfirmasi penjual ${formatDatePaid(orders.updatedAt)}"
|
||||||
binding.tvPaymentDeadlineLabel.text = "Batas konfirmasi penjual:"
|
binding.tvPaymentDeadlineLabel.text = "Batas konfirmasi penjual:"
|
||||||
binding.tvPaymentDeadline.text = formatDatePaid(orders.updatedAt)
|
binding.tvPaymentDeadline.text = formatDatePaid(orders.updatedAt)
|
||||||
|
|
||||||
@ -606,32 +614,17 @@ class DetailOrderStatusActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun formatDate(dateString: String): String {
|
private fun formatDate(dateString: String): String {
|
||||||
Log.d(TAG, "formatDate: Formatting date: $dateString")
|
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault())
|
val jakarta = ZoneId.of("Asia/Jakarta")
|
||||||
inputFormat.timeZone = TimeZone.getTimeZone("UTC")
|
val instant = Instant.parse(dateString) // parses ISO‑8601 with ‘Z’
|
||||||
|
val zoned = instant.atZone(jakarta)
|
||||||
|
|
||||||
val timeFormat = SimpleDateFormat("HH:mm", Locale("id", "ID"))
|
val time = DateTimeFormatter.ofPattern("HH:mm", Locale("id", "ID")).format(zoned)
|
||||||
val dateFormat = SimpleDateFormat("dd MMMM yyyy", Locale("id", "ID"))
|
val date = DateTimeFormatter.ofPattern("dd MMMM yyyy",Locale("id", "ID")).format(zoned)
|
||||||
|
|
||||||
val date = inputFormat.parse(dateString)
|
"$time\n$date"
|
||||||
|
|
||||||
date?.let {
|
|
||||||
val calendar = Calendar.getInstance()
|
|
||||||
calendar.time = it
|
|
||||||
calendar.set(Calendar.HOUR_OF_DAY, 23)
|
|
||||||
calendar.set(Calendar.MINUTE, 59)
|
|
||||||
|
|
||||||
val timePart = timeFormat.format(calendar.time)
|
|
||||||
val datePart = dateFormat.format(calendar.time)
|
|
||||||
|
|
||||||
val formatted = "$timePart\n$datePart"
|
|
||||||
Log.d(TAG, "formatDate: Formatted date: $formatted")
|
|
||||||
formatted
|
|
||||||
} ?: dateString
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "formatDate: Error formatting date: ${e.message}", e)
|
Log.e(TAG, "formatDate: $e")
|
||||||
dateString
|
dateString
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,9 @@ class RegisterViewModel(private val repository: UserRepository, private val orde
|
|||||||
private val _registeredUser = MutableLiveData<User>()
|
private val _registeredUser = MutableLiveData<User>()
|
||||||
val registeredUser: LiveData<User> = _registeredUser
|
val registeredUser: LiveData<User> = _registeredUser
|
||||||
|
|
||||||
|
private val _toastMessage = MutableLiveData<com.alya.ecommerce_serang.utils.viewmodel.Event<String>>()
|
||||||
|
val toastMessage: LiveData<com.alya.ecommerce_serang.utils.viewmodel.Event<String>> = _toastMessage
|
||||||
|
|
||||||
// For address data
|
// For address data
|
||||||
var selectedProvinceId: Int? = null
|
var selectedProvinceId: Int? = null
|
||||||
var selectedCityId: String? = null
|
var selectedCityId: String? = null
|
||||||
@ -224,9 +227,16 @@ class RegisterViewModel(private val repository: UserRepository, private val orde
|
|||||||
Log.d("RegisterViewModel", "OTP Response: ${response.available}")
|
Log.d("RegisterViewModel", "OTP Response: ${response.available}")
|
||||||
_checkValue.value = Result.Success(response.available)// Store the message for UI feedback
|
_checkValue.value = Result.Success(response.available)// Store the message for UI feedback
|
||||||
|
|
||||||
|
val msg = if (response.available)
|
||||||
|
"${request.fieldRegis.capitalize()} dapat digunakan"
|
||||||
|
else
|
||||||
|
"${request.fieldRegis.capitalize()} sudah terdaftar"
|
||||||
|
_toastMessage.value = Event(msg)
|
||||||
|
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
// Handle any errors and update state
|
// Handle any errors and update state
|
||||||
_checkValue.value = Result.Error(exception)
|
_checkValue.value = Result.Error(exception)
|
||||||
|
_toastMessage.value = Event("Gagal memeriksa ${request.fieldRegis}")
|
||||||
|
|
||||||
// Log the error for debugging
|
// Log the error for debugging
|
||||||
Log.e("RegisterViewModel", "Error:", exception)
|
Log.e("RegisterViewModel", "Error:", exception)
|
||||||
@ -375,4 +385,10 @@ class RegisterViewModel(private val repository: UserRepository, private val orde
|
|||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "RegisterViewModel"
|
private const val TAG = "RegisterViewModel"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Event<out T>(private val data: T) {
|
||||||
|
private var handled = false
|
||||||
|
fun getContentIfNotHandled(): T? = if (handled) null else { handled = true; data }
|
||||||
}
|
}
|
@ -21,6 +21,18 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/header"/>
|
app:layout_constraintTop_toBottomOf="@+id/header"/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBarCart"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/bottomCheckoutLayout"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/header"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvWholesaleWarning"
|
android:id="@+id/tvWholesaleWarning"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
android:id="@+id/main"
|
android:id="@+id/main"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/black_800"
|
android:background="@color/white"
|
||||||
android:theme="@style/Theme.Ecommerce_serang"
|
android:theme="@style/Theme.Ecommerce_serang"
|
||||||
tools:context=".ui.order.CheckoutActivity">
|
tools:context=".ui.order.CheckoutActivity">
|
||||||
|
|
||||||
@ -75,7 +75,7 @@
|
|||||||
android:id="@+id/tv_places_address"
|
android:id="@+id/tv_places_address"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Rumah"
|
android:text="-"
|
||||||
android:textColor="#5A5A5A"
|
android:textColor="#5A5A5A"
|
||||||
android:paddingHorizontal="8dp"
|
android:paddingHorizontal="8dp"
|
||||||
android:paddingVertical="2dp"
|
android:paddingVertical="2dp"
|
||||||
@ -94,7 +94,7 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="Jl. Pegangasan Timur"
|
android:text="-"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:layout_marginStart="32dp" />
|
android:layout_marginStart="32dp" />
|
||||||
|
|
||||||
@ -179,9 +179,11 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/card_shipment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
app:cardCornerRadius="8dp"
|
app:cardCornerRadius="8dp"
|
||||||
app:cardElevation="0dp"
|
app:cardElevation="0dp"
|
||||||
app:cardBackgroundColor="#F5F5F5">
|
app:cardBackgroundColor="#F5F5F5">
|
||||||
|
@ -3,38 +3,48 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
|
android:theme="@style/Theme.Ecommerce_serang"
|
||||||
tools:context=".ui.product.listproduct.ListProductActivity">
|
tools:context=".ui.product.listproduct.ListProductActivity">
|
||||||
|
|
||||||
<include
|
<LinearLayout
|
||||||
android:id="@+id/searchContainerList"
|
|
||||||
layout="@layout/view_search_back"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:orientation="vertical"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintBottom_toTopOf="@id/rvProductsList"/>
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
<include
|
||||||
|
android:id="@+id/searchContainerList"
|
||||||
|
layout="@layout/view_search_back"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"/>
|
||||||
|
|
||||||
|
<!-- <com.google.android.material.divider.MaterialDivider-->
|
||||||
|
<!-- android:id="@+id/divider_product"-->
|
||||||
|
<!-- android:layout_width="match_parent"-->
|
||||||
|
<!-- android:layout_height="wrap_content"-->
|
||||||
|
<!-- android:layout_marginTop="2dp"-->
|
||||||
|
<!-- app:layout_constraintTop_toBottomOf="@id/searchContainer"/>-->
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rvProductsList"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="23dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/searchContainerList"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
app:spanCount="2"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
tools:listitem="@layout/item_product_grid"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- <com.google.android.material.divider.MaterialDivider-->
|
|
||||||
<!-- android:id="@+id/divider_product"-->
|
|
||||||
<!-- android:layout_width="match_parent"-->
|
|
||||||
<!-- android:layout_height="wrap_content"-->
|
|
||||||
<!-- android:layout_marginTop="2dp"-->
|
|
||||||
<!-- app:layout_constraintTop_toBottomOf="@id/searchContainer"/>-->
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/rvProductsList"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="23dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/searchContainerList"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
app:spanCount="2"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
tools:listitem="@layout/item_product_grid"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"/>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,97 +1,136 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/main"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:paddingHorizontal="32dp"
|
||||||
android:layout_margin="16dp"
|
android:paddingVertical="16dp"
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginVertical="16dp"
|
|
||||||
tools:context=".ui.auth.LoginActivity">
|
tools:context=".ui.auth.LoginActivity">
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/tv_login_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/login"
|
android:text="@string/login"
|
||||||
|
android:textAlignment="center"
|
||||||
android:textSize="24sp"
|
android:textSize="24sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textAlignment="center"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:layout_marginBottom="24dp"/>
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/tv_email_label"
|
||||||
|
android:layout_marginBottom="48dp"
|
||||||
|
android:paddingBottom="24dp"/>
|
||||||
|
|
||||||
|
<!-- Email label -->
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/tv_email_label"
|
||||||
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:fontFamily="@font/dmsans_medium"
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:text="@string/login_email"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:text="@string/login_email"/>
|
android:layout_marginVertical="8dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tv_login_title"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
|
<!-- Email input -->
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/til_login_email"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tv_email_label"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/et_login_email"
|
android:id="@+id/et_login_email"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/hint_login_email"
|
android:hint="@string/hint_login_email"
|
||||||
android:inputType="textEmailAddress"/>
|
android:inputType="textEmailAddress" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- Password label-->
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/tv_password_label"
|
||||||
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:fontFamily="@font/dmsans_medium"
|
android:fontFamily="@font/dmsans_medium"
|
||||||
|
android:text="@string/password"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:text="@string/password"/>
|
android:layout_marginVertical="8dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/til_login_email"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
|
<!-- Password input -->
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/til_login_password"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
app:passwordToggleEnabled="true"
|
||||||
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
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/et_login_password"
|
android:id="@+id/et_login_password"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/hint_login_password"
|
android:hint="@string/hint_login_password"
|
||||||
android:inputType="textPassword"/>
|
android:inputType="textPassword" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- “Forgot password” link -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_forgetPassword"
|
android:id="@+id/tv_forgetPassword"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/forget_password"
|
android:text="@string/forget_password"
|
||||||
android:textColor="@android:color/holo_red_light"
|
|
||||||
android:textAlignment="textEnd"
|
android:textAlignment="textEnd"
|
||||||
android:layout_marginBottom="16dp"/>
|
android:textColor="@android:color/holo_red_light"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/til_login_password" />
|
||||||
|
|
||||||
|
<!-- Login button -->
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btn_login"
|
android:id="@+id/btn_login"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/login"
|
android:text="@string/login"
|
||||||
app:cornerRadius="8dp"/>
|
app:cornerRadius="8dp"
|
||||||
|
android:layout_marginVertical="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tv_forgetPassword" />
|
||||||
|
|
||||||
|
<!-- “Don’t have an account?” row (kept as LinearLayout) -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/ll_signup_row"
|
||||||
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:layout_marginTop="16dp">
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/btn_login">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/no_account"/>
|
android:text="@string/no_account" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_registrasi"
|
android:id="@+id/tv_registrasi"
|
||||||
@ -99,7 +138,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/signup"
|
android:text="@string/signup"
|
||||||
android:textColor="@color/blue1"
|
android:textColor="@color/blue1"
|
||||||
android:textStyle="bold"/>
|
android:textStyle="bold" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -38,5 +38,6 @@
|
|||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintTop_toBottomOf="@id/linear_shipment"
|
app:layout_constraintTop_toBottomOf="@id/linear_shipment"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -33,4 +33,23 @@
|
|||||||
tools:listitem="@layout/item_chat"
|
tools:listitem="@layout/item_chat"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBarChat"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_empty_chat"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="Keranjang Anda kosong"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -75,7 +75,7 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Didn't receive the code? " />
|
android:text="Belum menerima kode? " />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_resend_otp"
|
android:id="@+id/tv_resend_otp"
|
||||||
|
@ -1,6 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
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"/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Reference in New Issue
Block a user