mirror of
https://github.com/shaulascr/ecommerce_serang.git
synced 2025-12-15 15:41:02 +00:00
fix progress bar loading
This commit is contained in:
@ -86,19 +86,72 @@ class RegisterActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
// In RegisterActivity, add debug to navigateToStep:
|
||||
|
||||
fun navigateToStep(step: Int, userData: RegisterRequest?) {
|
||||
val fragment = when (step) {
|
||||
1 -> RegisterStep1Fragment.newInstance()
|
||||
2 -> RegisterStep2Fragment.newInstance(userData)
|
||||
3 -> RegisterStep3Fragment.newInstance()
|
||||
else -> null
|
||||
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})")
|
||||
}
|
||||
|
||||
fragment?.let {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment_container, it)
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
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
|
||||
@ -32,6 +33,9 @@ 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 {
|
||||
@ -42,8 +46,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 {
|
||||
|
||||
@ -112,13 +116,23 @@ class RegisterStep2Fragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
binding.btnBack.setOnClickListener {
|
||||
parentFragmentManager.popBackStack()
|
||||
}
|
||||
|
||||
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?) {
|
||||
@ -172,37 +186,9 @@ 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) {
|
||||
@ -314,9 +300,117 @@ class RegisterStep2Fragment : Fragment() {
|
||||
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
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()
|
||||
|
||||
_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()
|
||||
// }
|
||||
@ -6,6 +6,7 @@ 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
|
||||
@ -140,12 +141,12 @@ class HomeFragment : Fragment() {
|
||||
viewModel.uiState.collect { state ->
|
||||
when (state) {
|
||||
is HomeUiState.Loading -> {
|
||||
binding.loading.root.isVisible = true
|
||||
binding.loadingAll.visibility = View.VISIBLE
|
||||
binding.error.root.isVisible = false
|
||||
binding.home.isVisible = false
|
||||
}
|
||||
is HomeUiState.Success -> {
|
||||
binding.loading.root.isVisible = false
|
||||
binding.loadingAll.visibility = View.GONE
|
||||
binding.error.root.isVisible = false
|
||||
binding.home.isVisible = true
|
||||
val products = state.products
|
||||
@ -154,10 +155,12 @@ class HomeFragment : Fragment() {
|
||||
productAdapter?.updateLimitedProducts(products)
|
||||
}
|
||||
is HomeUiState.Error -> {
|
||||
binding.loading.root.isVisible = false
|
||||
binding.loadingAll.visibility = View.GONE
|
||||
binding.error.root.isVisible = true
|
||||
binding.home.isVisible = false
|
||||
binding.error.errorMessage.text = state.message
|
||||
// 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.retryButton.setOnClickListener {
|
||||
viewModel.retry()
|
||||
}
|
||||
|
||||
@ -90,6 +90,8 @@ class DetailProfileActivity : AppCompatActivity() {
|
||||
Log.e("DetailProfileActivity", "Error from ViewModel: $error")
|
||||
Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun setupClickListeners() {
|
||||
|
||||
@ -222,4 +222,11 @@ class ProfileFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewModel.loadUserProfile()
|
||||
viewModel.checkStoreUser()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -2,6 +2,7 @@ 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
|
||||
@ -24,7 +25,6 @@ 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,7 +33,6 @@ 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
|
||||
@ -41,9 +40,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 {
|
||||
@ -54,7 +53,7 @@ class EditProfileCustActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private val getContent = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
val data: Intent? = result.data
|
||||
data?.data?.let {
|
||||
selectedImageUri = it
|
||||
@ -105,8 +104,8 @@ class EditProfileCustActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
userProfile?.let {
|
||||
currentUser = it
|
||||
populateFields(it)
|
||||
|
||||
setupClickListeners()
|
||||
observeViewModel()
|
||||
}
|
||||
@ -118,7 +117,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))
|
||||
}
|
||||
|
||||
@ -156,7 +155,7 @@ class EditProfileCustActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
binding.btnSave.setOnClickListener {
|
||||
saveProfile()
|
||||
if (hasChanged()) confirmUpdate() else finish()
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,25 +212,38 @@ 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
|
||||
@ -242,82 +254,10 @@ class EditProfileCustActivity : AppCompatActivity() {
|
||||
phone = phone,
|
||||
birthDate = serverBirthDate,
|
||||
email = email,
|
||||
imageUri = selectedImageUri
|
||||
imageUri = imgProfile
|
||||
)
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
<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>
|
||||
@ -3,6 +3,6 @@
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid android:color="@color/blue_500" />
|
||||
<corners android:radius="5dp" />
|
||||
<corners android:radius="24dp" />
|
||||
|
||||
</shape>
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
android:id="@+id/profile_image"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:src="@drawable/baseline_account_circle_24"
|
||||
android:src="@drawable/baseline_account_circle_100"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
@ -87,6 +87,7 @@
|
||||
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"
|
||||
|
||||
@ -61,7 +61,7 @@
|
||||
android:id="@+id/profile_image"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:src="@drawable/baseline_account_circle_24"
|
||||
android:src="@drawable/baseline_account_circle_100"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
@ -188,6 +188,7 @@
|
||||
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"
|
||||
|
||||
@ -167,9 +167,15 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/searchContainer" />
|
||||
|
||||
<include
|
||||
android:id="@+id/loading"
|
||||
layout="@layout/view_loading"/>
|
||||
<ProgressBar
|
||||
android:id="@+id/loadingAll"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<include
|
||||
android:id="@+id/error"
|
||||
|
||||
@ -71,7 +71,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
|
||||
android:text="Kembali"
|
||||
app:cornerRadius="8dp"/>
|
||||
|
||||
@ -22,7 +22,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Retry"
|
||||
android:text="Muat Ulang"
|
||||
style="@style/Widget.Material3.FloatingActionButton.Large.Surface"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
@ -6,11 +6,10 @@
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
|
||||
@ -269,7 +269,7 @@
|
||||
</style>
|
||||
|
||||
<style name="button.small.active.short">
|
||||
<item name="android:layout_width">144dp</item>
|
||||
<item name="android:layout_width">100dp</item>
|
||||
</style>
|
||||
|
||||
<style name="button.small.active.short.only_icon">
|
||||
|
||||
Reference in New Issue
Block a user