add registerstoreuser

This commit is contained in:
shaulascr
2025-05-15 03:41:38 +07:00
parent b988a2e4bc
commit e71a39747c
11 changed files with 1751 additions and 10 deletions

View File

@ -29,6 +29,9 @@
android:theme="@style/Theme.Ecommerce_serang"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".ui.auth.RegisterStoreActivity"
android:exported="false" />
<activity
android:name=".ui.profile.editprofile.EditProfileCustActivity"
android:exported="false" />
@ -64,7 +67,7 @@
<activity
android:name=".ui.profile.mystore.profile.shipping_service.ShippingServiceActivity"
android:exported="false"/>
android:exported="false" />
<activity
android:name=".ui.notif.NotificationActivity"
android:exported="false" />
@ -157,6 +160,7 @@
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/outline_notifications_24" />
@ -168,6 +172,4 @@
android:value="fcm_default_channel" />
</application>
</manifest>

View File

@ -0,0 +1,9 @@
package com.alya.ecommerce_serang.data.api.response.auth
import com.google.gson.annotations.SerializedName
data class HasStoreResponse(
@field:SerializedName("hasStore")
val hasStore: Boolean
)

View File

@ -0,0 +1,21 @@
package com.alya.ecommerce_serang.data.api.response.auth
import com.google.gson.annotations.SerializedName
data class ListStoreTypeResponse(
@field:SerializedName("storeTypes")
val storeTypes: List<StoreTypesItem>,
@field:SerializedName("message")
val message: String
)
data class StoreTypesItem(
@field:SerializedName("name")
val name: String,
@field:SerializedName("id")
val id: Int
)

View File

@ -0,0 +1,57 @@
package com.alya.ecommerce_serang.data.api.response.auth
import com.google.gson.annotations.SerializedName
data class RegisterStoreResponse(
@field:SerializedName("store")
val store: Store,
@field:SerializedName("message")
val message: String
)
data class Store(
@field:SerializedName("image")
val image: String,
@field:SerializedName("ktp")
val ktp: String,
@field:SerializedName("nib")
val nib: String,
@field:SerializedName("npwp")
val npwp: String,
@field:SerializedName("address_id")
val addressId: Int,
@field:SerializedName("description")
val description: String,
@field:SerializedName("store_type_id")
val storeTypeId: Int,
@field:SerializedName("is_on_leave")
val isOnLeave: Boolean,
@field:SerializedName("balance")
val balance: String,
@field:SerializedName("user_id")
val userId: Int,
@field:SerializedName("name")
val name: String,
@field:SerializedName("persetujuan")
val persetujuan: String,
@field:SerializedName("id")
val id: Int,
@field:SerializedName("status")
val status: String
)

View File

@ -21,9 +21,12 @@ import com.alya.ecommerce_serang.data.api.dto.StoreAddressResponse
import com.alya.ecommerce_serang.data.api.dto.UpdateCart
import com.alya.ecommerce_serang.data.api.dto.UpdateChatRequest
import com.alya.ecommerce_serang.data.api.response.auth.CheckStoreResponse
import com.alya.ecommerce_serang.data.api.response.auth.HasStoreResponse
import com.alya.ecommerce_serang.data.api.response.auth.ListStoreTypeResponse
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
import com.alya.ecommerce_serang.data.api.response.auth.RegisterStoreResponse
import com.alya.ecommerce_serang.data.api.response.chat.ChatHistoryResponse
import com.alya.ecommerce_serang.data.api.response.chat.ChatListResponse
import com.alya.ecommerce_serang.data.api.response.chat.SendChatResponse
@ -73,6 +76,7 @@ import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Part
import retrofit2.http.PartMap
import retrofit2.http.Path
import retrofit2.http.Query
@ -85,17 +89,41 @@ interface ApiService {
@GET("checkstore")
suspend fun checkStore (): Response<CheckStoreResponse>
// @Multipart
// @POST("registerstore")
// suspend fun registerStore(
//
// ): Response<>
@Multipart
@POST("registerstore")
suspend fun registerStore(
@Part("description") description: RequestBody,
@Part("store_type_id") storeTypeId: RequestBody,
@Part("latitude") latitude: RequestBody,
@Part("longitude") longitude: RequestBody,
@Part("street") street: RequestBody,
@Part("subdistrict") subdistrict: RequestBody,
@Part("city_id") cityId: RequestBody,
@Part("province_id") provinceId: RequestBody,
@Part("postal_code") postalCode: RequestBody,
@Part("detail") detail: RequestBody,
@Part("bank_name") bankName: RequestBody,
@Part("bank_num") bankNum: RequestBody,
@Part("store_name") storeName: RequestBody,
@Part storeimg: MultipartBody.Part?,
@Part ktp: MultipartBody.Part?,
@Part npwp: MultipartBody.Part?,
@Part nib: MultipartBody.Part?,
@Part persetujuan: MultipartBody.Part?,
@PartMap couriers: Map<String, @JvmSuppressWildcards RequestBody>,
@Part qris: MultipartBody.Part?,
@Part("account_name") accountName: RequestBody,
): Response<RegisterStoreResponse>
@POST("otp")
suspend fun getOTP(
@Body otpRequest: OtpRequest
):OtpResponse
@GET("checkstore")
suspend fun checkStoreUser(
): HasStoreResponse
@POST("login")
suspend fun login(
@Body loginRequest: LoginRequest
@ -105,6 +133,10 @@ interface ApiService {
suspend fun allCategory(
): Response<CategoryResponse>
@GET("storetype")
suspend fun listTypeStore(
): Response<ListStoreTypeResponse>
@GET("product")
suspend fun getAllProduct(): Response<AllProductResponse>

View File

@ -7,13 +7,22 @@ import com.alya.ecommerce_serang.data.api.dto.LoginRequest
import com.alya.ecommerce_serang.data.api.dto.OtpRequest
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
import com.alya.ecommerce_serang.data.api.dto.UserProfile
import com.alya.ecommerce_serang.data.api.response.auth.HasStoreResponse
import com.alya.ecommerce_serang.data.api.response.auth.ListStoreTypeResponse
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.RegisterStoreResponse
import com.alya.ecommerce_serang.data.api.response.customer.order.ListCityResponse
import com.alya.ecommerce_serang.data.api.response.customer.order.ListProvinceResponse
import com.alya.ecommerce_serang.data.api.response.customer.profile.EditProfileResponse
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
import com.alya.ecommerce_serang.utils.FileUtils
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
class UserRepository(private val apiService: ApiService) {
//post data without message/response
@ -21,6 +30,31 @@ class UserRepository(private val apiService: ApiService) {
return apiService.getOTP(OtpRequest(email))
}
suspend fun listStoreType(): Result<ListStoreTypeResponse>{
return try{
val response = apiService.listTypeStore()
if (response.isSuccessful) {
response.body()?.let {
Result.Success(it)
} ?: Result.Error(Exception("No store type"))
} else {
throw Exception("No response ${response.errorBody()?.string()}")
}
} catch (e:Exception){
Result.Error(e)
}
}
suspend fun getListProvinces(): ListProvinceResponse? {
val response = apiService.getListProv()
return if (response.isSuccessful) response.body() else null
}
suspend fun getListCities(provId : Int): ListCityResponse? {
val response = apiService.getCityProvId(provId)
return if (response.isSuccessful) response.body() else null
}
suspend fun registerUser(request: RegisterRequest): String {
val response = apiService.register(request) // API call
@ -32,6 +66,169 @@ class UserRepository(private val apiService: ApiService) {
}
}
suspend fun registerStoreUser(
context: Context,
description: String,
storeTypeId: Int,
latitude: String,
longitude: String,
street: String,
subdistrict: String,
cityId: Int,
provinceId: Int,
postalCode: Int,
detail: String?,
bankName: String,
bankNum: Int,
storeName: String,
storeImg: Uri?,
ktp: Uri?,
npwp: Uri?,
nib: Uri?,
persetujuan: Uri?,
couriers: List<String>,
qris: Uri?,
accountName: String
): Result<RegisterStoreResponse> {
return try {
val descriptionPart = description.toRequestBody("text/plain".toMediaTypeOrNull())
val storeTypeIdPart = storeTypeId.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val latitudePart = latitude.toRequestBody("text/plain".toMediaTypeOrNull())
val longitudePart = longitude.toRequestBody("text/plain".toMediaTypeOrNull())
val streetPart = street.toRequestBody("text/plain".toMediaTypeOrNull())
val subdistrictPart = subdistrict.toRequestBody("text/plain".toMediaTypeOrNull())
val cityIdPart = cityId.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val provinceIdPart = provinceId.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val postalCodePart = postalCode.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val detailPart = detail?.toRequestBody("text/plain".toMediaTypeOrNull())
val bankNamePart = bankName.toRequestBody("text/plain".toMediaTypeOrNull())
val bankNumPart = bankNum.toString().toRequestBody("text/plain".toMediaTypeOrNull())
val storeNamePart = storeName.toRequestBody("text/plain".toMediaTypeOrNull())
val accountNamePart = accountName.toRequestBody("text/plain".toMediaTypeOrNull())
// Create a Map for courier values
val courierMap = HashMap<String, RequestBody>()
couriers.forEach { courier ->
courierMap["couriers[]"] = courier.toRequestBody("text/plain".toMediaTypeOrNull())
}
// Convert URIs to MultipartBody.Part
val storeImgPart = storeImg?.let {
val inputStream = context.contentResolver.openInputStream(it)
val file = File(context.cacheDir, "store_img_${System.currentTimeMillis()}")
inputStream?.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
val mimeType = context.contentResolver.getType(it) ?: "application/octet-stream"
val requestFile = file.asRequestBody(mimeType.toMediaTypeOrNull())
MultipartBody.Part.createFormData("storeimg", file.name, requestFile)
}
val ktpPart = ktp?.let {
val inputStream = context.contentResolver.openInputStream(it)
val file = File(context.cacheDir, "ktp_${System.currentTimeMillis()}")
inputStream?.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
val mimeType = context.contentResolver.getType(it) ?: "application/octet-stream"
val requestFile = file.asRequestBody(mimeType.toMediaTypeOrNull())
MultipartBody.Part.createFormData("ktp", file.name, requestFile)
}
val npwpPart = npwp?.let {
val inputStream = context.contentResolver.openInputStream(it)
val file = File(context.cacheDir, "npwp_${System.currentTimeMillis()}")
inputStream?.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
val mimeType = context.contentResolver.getType(it) ?: "application/octet-stream"
val requestFile = file.asRequestBody(mimeType.toMediaTypeOrNull())
MultipartBody.Part.createFormData("npwp", file.name, requestFile)
}
val nibPart = nib?.let {
val inputStream = context.contentResolver.openInputStream(it)
val file = File(context.cacheDir, "nib_${System.currentTimeMillis()}")
inputStream?.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
val mimeType = context.contentResolver.getType(it) ?: "application/octet-stream"
val requestFile = file.asRequestBody(mimeType.toMediaTypeOrNull())
MultipartBody.Part.createFormData("nib", file.name, requestFile)
}
val persetujuanPart = persetujuan?.let {
val inputStream = context.contentResolver.openInputStream(it)
val file = File(context.cacheDir, "persetujuan_${System.currentTimeMillis()}")
inputStream?.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
val mimeType = context.contentResolver.getType(it) ?: "application/octet-stream"
val requestFile = file.asRequestBody(mimeType.toMediaTypeOrNull())
MultipartBody.Part.createFormData("persetujuan", file.name, requestFile)
}
val qrisPart = qris?.let {
val inputStream = context.contentResolver.openInputStream(it)
val file = File(context.cacheDir, "qris_${System.currentTimeMillis()}")
inputStream?.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
val mimeType = context.contentResolver.getType(it) ?: "application/octet-stream"
val requestFile = file.asRequestBody(mimeType.toMediaTypeOrNull())
MultipartBody.Part.createFormData("qris", file.name, requestFile)
}
// Make the API call
val response = apiService.registerStore(
descriptionPart,
storeTypeIdPart,
latitudePart,
longitudePart,
streetPart,
subdistrictPart,
cityIdPart,
provinceIdPart,
postalCodePart,
detailPart ?: "".toRequestBody("text/plain".toMediaTypeOrNull()),
bankNamePart,
bankNumPart,
storeNamePart,
storeImgPart,
ktpPart,
npwpPart,
nibPart,
persetujuanPart,
courierMap,
qrisPart,
accountNamePart
)
// Check if response is successful
if (response.isSuccessful) {
Result.Success(response.body() ?: throw Exception("Response body is null"))
} else {
Result.Error(Exception("Registration failed with code: ${response.code()}"))
}
} catch (e: Exception) {
Result.Error(e)
}
}
suspend fun login(email: String, password: String): Result<LoginResponse> {
return try {
val response = apiService.login(LoginRequest(email, password))
@ -130,6 +327,10 @@ class UserRepository(private val apiService: ApiService) {
Result.Error(e)
}
}
suspend fun checkStore(): HasStoreResponse{
return apiService.checkStoreUser()
}
companion object{
private const val TAG = "UserRepository"

View File

@ -0,0 +1,601 @@
package com.alya.ecommerce_serang.ui.auth
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
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.Result
import com.alya.ecommerce_serang.data.repository.UserRepository
import com.alya.ecommerce_serang.databinding.ActivityRegisterStoreBinding
import com.alya.ecommerce_serang.ui.order.address.CityAdapter
import com.alya.ecommerce_serang.ui.order.address.ProvinceAdapter
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
import com.alya.ecommerce_serang.utils.SessionManager
class RegisterStoreActivity : AppCompatActivity() {
private lateinit var binding: ActivityRegisterStoreBinding
private lateinit var sessionManager: SessionManager
private lateinit var provinceAdapter: ProvinceAdapter
private lateinit var cityAdapter: CityAdapter
// Request codes for file picking
private val PICK_STORE_IMAGE_REQUEST = 1001
private val PICK_KTP_REQUEST = 1002
private val PICK_NPWP_REQUEST = 1003
private val PICK_NIB_REQUEST = 1004
private val PICK_PERSETUJUAN_REQUEST = 1005
private val PICK_QRIS_REQUEST = 1006
// Location request code
private val LOCATION_PERMISSION_REQUEST = 2001
private val viewModel: RegisterStoreViewModel by viewModels {
BaseViewModelFactory {
val apiService = ApiConfig.getApiService(sessionManager)
val orderRepository = UserRepository(apiService)
RegisterStoreViewModel(orderRepository)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRegisterStoreBinding.inflate(layoutInflater)
setContentView(binding.root)
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
}
provinceAdapter = ProvinceAdapter(this)
cityAdapter = CityAdapter(this)
setupDataBinding()
setupSpinners() // Location spinners
// Setup observers
setupStoreTypesObserver() // Store type observer
setupObservers()
setupMap()
setupDocumentUploads()
setupCourierSelection()
viewModel.fetchStoreTypes()
viewModel.getProvinces()
// Setup register button
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 setupObservers() {
// Observe province state
viewModel.provincesState.observe(this) { state ->
when (state) {
is Result.Loading -> {
Log.d(TAG, "Loading provinces...")
binding.provinceProgressBar?.visibility = View.VISIBLE
binding.spinnerProvince.isEnabled = false
}
is Result.Success -> {
Log.d(TAG, "Provinces loaded: ${state.data.size}")
binding.provinceProgressBar?.visibility = View.GONE
binding.spinnerProvince.isEnabled = true
// Update adapter with data
provinceAdapter.updateData(state.data)
}
is Result.Error -> {
// Log.e(TAG, "Error loading provinces: ${state.}")
binding.provinceProgressBar?.visibility = View.GONE
binding.spinnerProvince.isEnabled = true
// Toast.makeText(this, "Gagal memuat provinsi: ${state.message}", Toast.LENGTH_SHORT).show()
}
}
}
// Observe city state
viewModel.citiesState.observe(this) { state ->
when (state) {
is Result.Loading -> {
Log.d(TAG, "Loading cities...")
binding.cityProgressBar?.visibility = View.VISIBLE
binding.spinnerCity.isEnabled = false
}
is Result.Success -> {
Log.d(TAG, "Cities loaded: ${state.data.size}")
binding.cityProgressBar?.visibility = View.GONE
binding.spinnerCity.isEnabled = true
// Update adapter with data
cityAdapter.updateData(state.data)
}
is Result.Error -> {
// Log.e(TAG, "Error loading cities: ${state.message}")
binding.cityProgressBar?.visibility = View.GONE
binding.spinnerCity.isEnabled = true
// Toast.makeText(this, "Gagal memuat kota: ${state.message}", Toast.LENGTH_SHORT).show()
}
}
}
// Observe registration state
viewModel.registerState.observe(this) { result ->
when (result) {
is Result.Loading -> {
showLoading(true)
}
is Result.Success -> {
showLoading(false)
Toast.makeText(this, "Toko berhasil didaftarkan", Toast.LENGTH_SHORT).show()
finish() // Return to previous screen
}
is Result.Error -> {
showLoading(false)
Toast.makeText(this, "Gagal mendaftarkan toko: ${result.exception.message}", Toast.LENGTH_SHORT).show()
}
}
}
}
private fun setupStoreTypesObserver() {
// Observe loading state
viewModel.isLoadingType.observe(this) { isLoading ->
if (isLoading) {
// Show loading indicator for store types spinner
binding.spinnerStoreType.isEnabled = false
binding.storeTypeProgressBar?.visibility = View.VISIBLE
} else {
binding.spinnerStoreType.isEnabled = true
binding.storeTypeProgressBar?.visibility = View.GONE
}
}
// Observe error messages
viewModel.errorMessage.observe(this) { errorMsg ->
if (errorMsg.isNotEmpty()) {
Toast.makeText(this, "Error loading store types: $errorMsg", Toast.LENGTH_SHORT).show()
}
}
// Observe store types data
viewModel.storeTypes.observe(this) { storeTypes ->
Log.d(TAG, "Store types loaded: ${storeTypes.size}")
if (storeTypes.isNotEmpty()) {
// Add "Pilih Jenis UMKM" as the first item if it's not already there
val displayList = if (storeTypes.any { it.name == "Pilih Jenis UMKM" || it.id == 0 }) {
storeTypes
} else {
val defaultItem = StoreTypesItem(name = "Pilih Jenis UMKM", id = 0)
listOf(defaultItem) + storeTypes
}
// Setup spinner with API data
setupStoreTypeSpinner(displayList)
}
}
}
private fun setupStoreTypeSpinner(storeTypes: List<StoreTypesItem>) {
Log.d(TAG, "Setting up store type spinner with ${storeTypes.size} items")
// Create a custom adapter to display just the name but hold the whole object
val adapter = object : ArrayAdapter<StoreTypesItem>(
this,
android.R.layout.simple_spinner_item,
storeTypes
) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = super.getView(position, convertView, parent)
(view as TextView).text = getItem(position)?.name ?: ""
return view
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = super.getDropDownView(position, convertView, parent)
(view as TextView).text = getItem(position)?.name ?: ""
return view
}
// Override toString to ensure proper display
override fun getItem(position: Int): StoreTypesItem? {
return super.getItem(position)
}
}
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
// Set adapter to spinner
binding.spinnerStoreType.adapter = adapter
// Set item selection listener
binding.spinnerStoreType.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val selectedItem = adapter.getItem(position)
Log.d(TAG, "Store type selected: position=$position, item=${selectedItem?.name}, id=${selectedItem?.id}")
if (selectedItem != null && selectedItem.id > 0) {
// Store the actual ID from the API, not just position
viewModel.storeTypeId.value = selectedItem.id
Log.d(TAG, "Set storeTypeId to ${selectedItem.id}")
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
Log.d(TAG, "No store type selected")
}
}
// Hide progress bar after setup
binding.storeTypeProgressBar?.visibility = View.GONE
}
private fun setupSpinners() {
// Setup province spinner
binding.spinnerProvince.adapter = provinceAdapter
binding.spinnerProvince.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
Log.d(TAG, "Province selected at position: $position")
val provinceId = provinceAdapter.getProvinceId(position)
if (provinceId != null) {
Log.d(TAG, "Setting province ID: $provinceId")
viewModel.provinceId.value = provinceId
viewModel.getCities(provinceId)
// Reset city selection when province changes
cityAdapter.clear()
binding.spinnerCity.setSelection(0)
} else {
Log.e(TAG, "Invalid province ID for position: $position")
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
// Do nothing
}
}
// Setup city spinner
binding.spinnerCity.adapter = cityAdapter
binding.spinnerCity.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
Log.d(TAG, "City selected at position: $position")
val cityId = cityAdapter.getCityId(position)
if (cityId != null) {
Log.d(TAG, "Setting city ID: $cityId")
viewModel.cityId.value = cityId
viewModel.selectedCityId = cityId
} else {
Log.e(TAG, "Invalid city ID for position: $position")
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
// Do nothing
}
}
// Add initial hints to the spinners
if (provinceAdapter.isEmpty) {
provinceAdapter.add("Pilih Provinsi")
}
if (cityAdapter.isEmpty) {
cityAdapter.add("Pilih Kabupaten/Kota")
}
}
// private fun setupSubdistrictSpinner(cityId: Int) {
// // This would typically be populated from API based on cityId
// val subdistricts = listOf("Pilih Kecamatan", "Kecamatan 1", "Kecamatan 2", "Kecamatan 3")
// val subdistrictAdapter = ArrayAdapter(this, R.layout.simple_spinner_dropdown_item, subdistricts)
// binding.spinnerSubdistrict.adapter = subdistrictAdapter
// binding.spinnerSubdistrict.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
// override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
// if (position > 0) {
// viewModel.subdistrict.value = subdistricts[position]
// }
// }
// override fun onNothingSelected(parent: AdapterView<*>?) {}
// }
// }
private fun setupDocumentUploads() {
// Store Image
binding.containerStoreImg.setOnClickListener {
pickImage(PICK_STORE_IMAGE_REQUEST)
}
// KTP
binding.containerKtp.setOnClickListener {
pickImage(PICK_KTP_REQUEST)
}
// NIB
binding.containerNib.setOnClickListener {
pickDocument(PICK_NIB_REQUEST)
}
// NPWP
binding.containerNpwp?.setOnClickListener {
pickImage(PICK_NPWP_REQUEST)
}
// SPPIRT
binding.containerSppirt.setOnClickListener {
pickDocument(PICK_PERSETUJUAN_REQUEST)
}
// Halal
binding.containerHalal.setOnClickListener {
pickDocument(PICK_QRIS_REQUEST)
}
}
private fun pickImage(requestCode: Int) {
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intent, requestCode)
}
private fun pickDocument(requestCode: Int) {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "*/*"
val mimeTypes = arrayOf("application/pdf", "image/jpeg", "image/png")
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
startActivityForResult(intent, requestCode)
}
private fun setupCourierSelection() {
binding.checkboxJne.setOnCheckedChangeListener { _, isChecked ->
handleCourierSelection("jne", isChecked)
}
binding.checkboxJnt.setOnCheckedChangeListener { _, isChecked ->
handleCourierSelection("jnt", isChecked)
}
binding.checkboxPos.setOnCheckedChangeListener { _, isChecked ->
handleCourierSelection("pos", isChecked)
}
}
private fun handleCourierSelection(courier: String, isSelected: Boolean) {
if (isSelected) {
if (!viewModel.selectedCouriers.contains(courier)) {
viewModel.selectedCouriers.add(courier)
}
} else {
viewModel.selectedCouriers.remove(courier)
}
}
private fun setupMap() {
// This would typically integrate with Google Maps SDK
// For simplicity, we're just using a placeholder
binding.mapContainer.setOnClickListener {
// Request location permission if not granted
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
LOCATION_PERMISSION_REQUEST
)
viewModel.latitude.value = "-6.2088"
viewModel.longitude.value = "106.8456"
Toast.makeText(this, "Lokasi dipilih", Toast.LENGTH_SHORT).show()
} else {
// Show map selection UI
// This would typically launch Maps UI for location selection
// For now, we'll just set some dummy coordinates
viewModel.latitude.value = "-6.2088"
viewModel.longitude.value = "106.8456"
Toast.makeText(this, "Lokasi dipilih", Toast.LENGTH_SHORT).show()
}
}
}
private fun setupDataBinding() {
// Two-way data binding for text fields
binding.etStoreName.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
viewModel.storeName.value = s.toString()
}
})
binding.etStoreDescription.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
viewModel.storeDescription.value = s.toString()
}
})
binding.etStreet.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
viewModel.street.value = s.toString()
}
})
binding.etPostalCode.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
try {
viewModel.postalCode.value = s.toString().toInt()
} catch (e: NumberFormatException) {
// Handle invalid input
//show toast
}
}
})
binding.etAddressDetail.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
viewModel.addressDetail.value = s.toString()
}
})
binding.etBankNumber.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
viewModel.bankNumber.value = s.toString().toInt()
}
})
binding.etSubdistrict.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
viewModel.subdistrict.value = s.toString()
}
})
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && data != null) {
val uri = data.data
when (requestCode) {
PICK_STORE_IMAGE_REQUEST -> {
viewModel.storeImageUri = uri
updateImagePreview(uri, binding.imgStore, binding.layoutUploadStoreImg)
}
PICK_KTP_REQUEST -> {
viewModel.ktpUri = uri
updateImagePreview(uri, binding.imgKtp, binding.layoutUploadKtp)
}
PICK_NPWP_REQUEST -> {
viewModel.npwpUri = uri
updateDocumentPreview(binding.layoutUploadNpwp)
}
PICK_NIB_REQUEST -> {
viewModel.nibUri = uri
updateDocumentPreview(binding.layoutUploadNib)
}
PICK_PERSETUJUAN_REQUEST -> {
viewModel.persetujuanUri = uri
updateDocumentPreview(binding.layoutUploadSppirt)
}
PICK_QRIS_REQUEST -> {
viewModel.qrisUri = uri
updateDocumentPreview(binding.layoutUploadHalal)
}
}
}
}
private fun updateImagePreview(uri: Uri?, imageView: ImageView, uploadLayout: LinearLayout) {
uri?.let {
imageView.setImageURI(it)
imageView.visibility = View.VISIBLE
uploadLayout.visibility = View.GONE
}
}
private fun updateDocumentPreview(uploadLayout: LinearLayout) {
// For documents, we just show a success indicator
val checkIcon = ImageView(this)
checkIcon.setImageResource(android.R.drawable.ic_menu_gallery)
val successText = TextView(this)
successText.text = "Dokumen berhasil diunggah"
uploadLayout.removeAllViews()
uploadLayout.addView(checkIcon)
uploadLayout.addView(successText)
}
//later implement get location form gps
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == LOCATION_PERMISSION_REQUEST) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, proceed with location selection
viewModel.latitude.value = "-6.2088"
viewModel.longitude.value = "106.8456"
Toast.makeText(this, "Lokasi dipilih", Toast.LENGTH_SHORT).show()
} else {
viewModel.latitude.value = "-6.2088"
viewModel.longitude.value = "106.8456"
}
}
}
private fun showLoading(isLoading: Boolean) {
if (isLoading) {
// Show loading indicator
binding.btnRegister.isEnabled = false
binding.btnRegister.text = "Mendaftar..."
} else {
// Hide loading indicator
binding.btnRegister.isEnabled = true
binding.btnRegister.text = "Daftar"
}
}
companion object {
private const val TAG = "RegisterStoreActivity"
}
}

View File

@ -0,0 +1,202 @@
package com.alya.ecommerce_serang.ui.auth
import android.content.Context
import android.net.Uri
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alya.ecommerce_serang.data.api.response.auth.RegisterStoreResponse
import com.alya.ecommerce_serang.data.api.response.auth.StoreTypesItem
import com.alya.ecommerce_serang.data.api.response.customer.order.CitiesItem
import com.alya.ecommerce_serang.data.api.response.customer.order.ProvincesItem
import com.alya.ecommerce_serang.data.repository.Result
import com.alya.ecommerce_serang.data.repository.UserRepository
import kotlinx.coroutines.launch
class RegisterStoreViewModel(
private val repository: UserRepository
) : ViewModel() {
// LiveData for UI state
private val _registerState = MutableLiveData<com.alya.ecommerce_serang.data.repository.Result<RegisterStoreResponse>>()
val registerState: LiveData<com.alya.ecommerce_serang.data.repository.Result<RegisterStoreResponse>> = _registerState
private val _storeTypes = MutableLiveData<List<StoreTypesItem>>()
val storeTypes: LiveData<List<StoreTypesItem>> = _storeTypes
// LiveData for error messages
private val _errorMessage = MutableLiveData<String>()
val errorMessage: LiveData<String> = _errorMessage
// LiveData for loading state
private val _isLoadingType = MutableLiveData<Boolean>()
val isLoadingType: LiveData<Boolean> = _isLoadingType
private val _provincesState = MutableLiveData<Result<List<ProvincesItem>>>()
val provincesState: LiveData<Result<List<ProvincesItem>>> = _provincesState
private val _citiesState = MutableLiveData<Result<List<CitiesItem>>>()
val citiesState: LiveData<Result<List<CitiesItem>>> = _citiesState
var selectedProvinceId: Int? = null
var selectedCityId: Int? = null
// Form fields
val storeName = MutableLiveData<String>()
val storeDescription = MutableLiveData<String>()
val storeTypeId = MutableLiveData<Int>()
val latitude = MutableLiveData<String>()
val longitude = MutableLiveData<String>()
val street = MutableLiveData<String>()
val subdistrict = MutableLiveData<String>()
val cityId = MutableLiveData<Int>()
val provinceId = MutableLiveData<Int>()
val postalCode = MutableLiveData<Int>()
val addressDetail = MutableLiveData<String>()
val bankName = MutableLiveData<String>()
val bankNumber = MutableLiveData<Int>()
val accountName = MutableLiveData<String>()
// Files
var storeImageUri: Uri? = null
var ktpUri: Uri? = null
var npwpUri: Uri? = null
var nibUri: Uri? = null
var persetujuanUri: Uri? = null
var qrisUri: Uri? = null
// Selected couriers
val selectedCouriers = mutableListOf<String>()
fun registerStore(context: Context) {
viewModelScope.launch {
try {
_registerState.value = Result.Loading
val result = repository.registerStoreUser(
context = context,
description = storeDescription.value ?: "",
storeTypeId = storeTypeId.value ?: 0,
latitude = latitude.value ?: "",
longitude = longitude.value ?: "",
street = street.value ?: "",
subdistrict = subdistrict.value ?: "",
cityId = cityId.value ?: 0,
provinceId = provinceId.value ?: 0,
postalCode = postalCode.value ?: 0,
detail = addressDetail.value,
bankName = bankName.value ?: "",
bankNum = bankNumber.value ?: 0,
storeName = storeName.value ?: "",
storeImg = storeImageUri,
ktp = ktpUri,
npwp = npwpUri,
nib = nibUri,
persetujuan = persetujuanUri,
couriers = selectedCouriers,
qris = qrisUri,
accountName = accountName.value ?: ""
)
_registerState.value = result
} catch (e: Exception) {
_registerState.value = com.alya.ecommerce_serang.data.repository.Result.Error(e)
}
}
}
// // Helper function to convert Uri to File
// private fun getFileFromUri(context: Context, uri: Uri): File {
// val inputStream = context.contentResolver.openInputStream(uri)
// val tempFile = File(context.cacheDir, "temp_file_${System.currentTimeMillis()}")
// inputStream?.use { input ->
// tempFile.outputStream().use { output ->
// input.copyTo(output)
// }
// }
// return tempFile
// }
fun validateForm(): Boolean {
// Implement form validation logic
return !(storeName.value.isNullOrEmpty() ||
storeTypeId.value == null ||
street.value.isNullOrEmpty() ||
subdistrict.value.isNullOrEmpty() ||
cityId.value == null ||
provinceId.value == null ||
postalCode.value == null ||
bankName.value.isNullOrEmpty() ||
bankNumber.value == null ||
selectedCouriers.isEmpty() ||
ktpUri == null ||
nibUri == null)
}
// Function to fetch store types
fun fetchStoreTypes() {
_isLoadingType.value = true
viewModelScope.launch {
when (val result = repository.listStoreType()) {
is Result.Success -> {
_storeTypes.value = result.data.storeTypes
_isLoadingType.value = false
}
is Result.Error -> {
_errorMessage.value = result.exception.message ?: "Unknown error occurred"
_isLoadingType.value = false
}
is Result.Loading -> {
_isLoadingType.value = true
}
}
}
}
fun getProvinces() {
_provincesState.value = Result.Loading
viewModelScope.launch {
try {
val result = repository.getListProvinces()
if (result?.provinces != null) {
_provincesState.postValue(Result.Success(result.provinces))
Log.d(TAG, "Provinces loaded: ${result.provinces.size}")
} else {
_provincesState.postValue(Result.Error(Exception("Failed to load provinces")))
Log.e(TAG, "Province result was null or empty")
}
} catch (e: Exception) {
_provincesState.postValue(Result.Error(Exception(e.message ?: "Error loading provinces")))
Log.e(TAG, "Error fetching provinces", e)
}
}
}
fun getCities(provinceId: Int){
_citiesState.value = Result.Loading
viewModelScope.launch {
try {
selectedProvinceId = provinceId
val result = repository.getListCities(provinceId)
result?.let {
_citiesState.postValue(Result.Success(it.cities))
Log.d(TAG, "Cities loaded for province $provinceId: ${it.cities.size}")
} ?: run {
_citiesState.postValue(Result.Error(Exception("Failed to load cities")))
Log.e(TAG, "City result was null for province $provinceId")
}
} catch (e: Exception) {
_citiesState.postValue(Result.Error(Exception(e.message ?: "Error loading cities")))
Log.e(TAG, "Error fetching cities for province $provinceId", e)
}
}
}
companion object {
private const val TAG = "RegisterStoreUserViewModel"
}
}

View File

@ -15,6 +15,7 @@ import com.alya.ecommerce_serang.data.api.dto.UserProfile
import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.repository.UserRepository
import com.alya.ecommerce_serang.databinding.FragmentProfileBinding
import com.alya.ecommerce_serang.ui.auth.RegisterStoreActivity
import com.alya.ecommerce_serang.ui.order.history.HistoryActivity
import com.alya.ecommerce_serang.ui.profile.mystore.MyStoreActivity
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
@ -53,10 +54,21 @@ class ProfileFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
observeUserProfile()
viewModel.loadUserProfile()
viewModel.checkStoreUser()
binding.cardBukaToko.setOnClickListener{
val intentBuka = Intent(requireContext(), MyStoreActivity::class.java)
startActivity(intentBuka)
val hasStore = viewModel.checkStore.value
// val hasStore = false
Log.d("Profile Fragment", "Check store $hasStore")
if (hasStore == true){
val intentBuka = Intent(requireContext(), MyStoreActivity::class.java)
startActivity(intentBuka)
} else {
val intentBuka = Intent(requireContext(), RegisterStoreActivity::class.java)
startActivity(intentBuka)
}
}
binding.btnDetailProfile.setOnClickListener{

View File

@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alya.ecommerce_serang.data.api.dto.UserProfile
import com.alya.ecommerce_serang.data.api.response.auth.HasStoreResponse
import com.alya.ecommerce_serang.data.api.response.customer.profile.EditProfileResponse
import com.alya.ecommerce_serang.data.repository.Result
import com.alya.ecommerce_serang.data.repository.UserRepository
@ -23,6 +24,9 @@ class ProfileViewModel(private val userRepository: UserRepository) : ViewModel()
private val _editProfileResult = MutableLiveData<Result<EditProfileResponse>>()
val editProfileResult: LiveData<Result<EditProfileResponse>> = _editProfileResult
private val _checkStore = MutableLiveData<Boolean>()
val checkStore: LiveData<Boolean> = _checkStore
fun loadUserProfile(){
viewModelScope.launch {
when (val result = userRepository.fetchUserProfile()){
@ -33,6 +37,28 @@ class ProfileViewModel(private val userRepository: UserRepository) : ViewModel()
}
}
fun checkStoreUser(){
viewModelScope.launch {
try {
// Call the repository function to request OTP
val response: HasStoreResponse = userRepository.checkStore()
// Log and store success message
Log.d("RegisterViewModel", "OTP Response: ${response.hasStore}")
_checkStore.value = response.hasStore // Store the message for UI feedback
} catch (exception: Exception) {
// Handle any errors and update state
_checkStore.value = false
// Log the error for debugging
Log.e("RegisterViewModel", "Error:", exception)
}
}
}
fun editProfileDirect(
context: Context,
username: String,

View File

@ -0,0 +1,578 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.auth.RegisterStoreActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#334583"
android:padding="16dp"
android:text="Buka Toko"
android:textColor="@android:color/white"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#334583"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp"
android:text="Mohon untuk melengkapi formulir pendaftaran ini agar dapat mengakses fitur penjual pada aplikasi."
android:textColor="@android:color/white" />
</LinearLayout>
<!-- Main content in ScrollView -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="* Wajib diisi"
android:textColor="#777777" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="1. Nama Toko *"
android:textColor="@android:color/black" />
<EditText
android:id="@+id/et_store_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background"
android:hint="Isi jawaban Anda di sini"
android:inputType="text"
android:padding="12dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="2. Deskripsi Toko"
android:textColor="@android:color/black" />
<EditText
android:id="@+id/et_store_description"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background"
android:gravity="top"
android:hint="Isi jawaban Anda di sini"
android:inputType="textMultiLine"
android:padding="12dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="3. Jenis UMKM *"
android:textColor="@android:color/black" />
<Spinner
android:id="@+id/spinner_store_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:drawable/btn_dropdown"
android:hint="Pilih jawaban Anda di sini"
android:padding="12dp" />
<ProgressBar
android:id="@+id/storeTypeProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:visibility="gone" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="4. Provinsi *"
android:textColor="@android:color/black" />
<Spinner
android:id="@+id/spinner_province"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:drawable/btn_dropdown"
android:hint="Pilih jawaban Anda di sini"
android:padding="12dp" />
<ProgressBar
android:id="@+id/provinceProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:visibility="gone" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="5. Kabupaten/Kota *"
android:textColor="@android:color/black" />
<Spinner
android:id="@+id/spinner_city"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:drawable/btn_dropdown"
android:hint="Pilih jawaban Anda di sini"
android:padding="12dp" />
<ProgressBar
android:id="@+id/cityProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:visibility="gone" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="6. Kecamatan *"
android:textColor="@android:color/black" />
<EditText
android:id="@+id/et_subdistrict"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background"
android:hint="Isi jawaban Anda di sini"
android:inputType="text"
android:padding="12dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="7. Jalan *"
android:textColor="@android:color/black" />
<EditText
android:id="@+id/et_street"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background"
android:hint="Isi jawaban Anda di sini"
android:inputType="text"
android:padding="12dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="8. Kode Pos *"
android:textColor="@android:color/black" />
<EditText
android:id="@+id/et_postal_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background"
android:hint="Isi jawaban Anda di sini"
android:inputType="number"
android:padding="12dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="9. Detail Alamat"
android:textColor="@android:color/black" />
<EditText
android:id="@+id/et_address_detail"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background"
android:gravity="top"
android:hint="Isi jawaban Anda di sini"
android:inputType="textMultiLine"
android:padding="12dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="10. Bank *"
android:textColor="@android:color/black" />
<Spinner
android:id="@+id/spinner_bank"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:drawable/btn_dropdown"
android:hint="Pilih jawaban Anda di sini"
android:padding="12dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="11. Nomor Rekening *"
android:textColor="@android:color/black" />
<EditText
android:id="@+id/et_bank_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background"
android:hint="Isi jawaban Anda di sini"
android:inputType="number"
android:padding="12dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="12. Pilih Kurir *"
android:textColor="@android:color/black" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<CheckBox
android:id="@+id/checkbox_jne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="JNE" />
<CheckBox
android:id="@+id/checkbox_jnt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="J&amp;T" />
<CheckBox
android:id="@+id/checkbox_pos"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="POS" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="13. Foto Profil Toko"
android:textColor="@android:color/black" />
<FrameLayout
android:id="@+id/container_store_img"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background">
<ImageView
android:id="@+id/img_store"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:visibility="gone" />
<LinearLayout
android:id="@+id/layout_upload_store_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@android:drawable/ic_menu_upload" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Unggah dokumen Anda di sini"
android:textColor="#777777" />
</LinearLayout>
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="14. Dokumen KTP *"
android:textColor="@android:color/black" />
<FrameLayout
android:id="@+id/container_ktp"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background">
<ImageView
android:id="@+id/img_ktp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:visibility="gone" />
<LinearLayout
android:id="@+id/layout_upload_ktp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@android:drawable/ic_menu_upload" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Unggah dokumen Anda di sini"
android:textColor="#777777" />
</LinearLayout>
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="15. Dokumen NIB *"
android:textColor="@android:color/black" />
<FrameLayout
android:id="@+id/container_nib"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background">
<ImageView
android:id="@+id/img_nib"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:visibility="gone" />
<LinearLayout
android:id="@+id/layout_upload_nib"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@android:drawable/ic_menu_upload" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Unggah dokumen Anda di sini"
android:textColor="#777777" />
</LinearLayout>
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="16. Dokumen NPWP *"
android:textColor="@android:color/black" />
<FrameLayout
android:id="@+id/container_npwp"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background">
<ImageView
android:id="@+id/img_npwp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:visibility="gone" />
<LinearLayout
android:id="@+id/layout_upload_npwp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@android:drawable/ic_menu_upload" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Unggah dokumen Anda di sini"
android:textColor="#777777" />
</LinearLayout>
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="16. Dokumen SPPIRT"
android:textColor="@android:color/black" />
<FrameLayout
android:id="@+id/container_sppirt"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background">
<ImageView
android:id="@+id/img_sppirt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:visibility="gone" />
<LinearLayout
android:id="@+id/layout_upload_sppirt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@android:drawable/ic_menu_upload" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Unggah dokumen Anda di sini"
android:textColor="#777777" />
</LinearLayout>
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="17. Dokumen Sertifikat Halal"
android:textColor="@android:color/black" />
<FrameLayout
android:id="@+id/container_halal"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="8dp"
android:background="@android:drawable/editbox_background">
<ImageView
android:id="@+id/img_halal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:visibility="gone" />
<LinearLayout
android:id="@+id/layout_upload_halal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@android:drawable/ic_menu_upload" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Unggah dokumen Anda di sini"
android:textColor="#777777" />
</LinearLayout>
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="18. Pilih Titik Lokasi Usaha *"
android:textColor="@android:color/black" />
<FrameLayout
android:id="@+id/map_container"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="8dp"
android:background="@android:color/darker_gray">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/placeholder_image" />
</FrameLayout>
<Button
android:id="@+id/btn_register"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="16dp"
android:background="#3F9CE8"
android:text="Daftar"
android:textColor="@android:color/white" />
</LinearLayout>
</ScrollView>
</LinearLayout>