Address view created.

Address selection in adapter.

EDD api integration and caching.

order creation api integration.

PaymentActivity created to load payment url.

AddressActivity creation and api integration for edd on pincode check screen
This commit is contained in:
2024-07-26 21:22:40 +05:30
parent 0cc0d94935
commit 78c309e046
37 changed files with 904 additions and 89 deletions

View File

@@ -17,11 +17,20 @@
android:supportsRtl="true"
android:theme="@style/Theme.Woka"
tools:targetApi="31">
<activity
android:name=".shop.views.AddressActivity"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".shop.views.PaymentActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode|fontScale|fontWeightAdjustment|screenLayout"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".shop.views.CartActivity"
android:exported="false"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan"/>
android:windowSoftInputMode="adjustPan" />
<activity
android:name=".shop.views.ShopActivity"
android:exported="false"

View File

@@ -1,11 +1,16 @@
package com.woka.shop
import com.woka.networking.ApiResponse
import com.woka.shop.models.addresslisting.ParentAddress
import com.woka.shop.models.addaddress.AddAddressRequestData
import com.woka.shop.models.addaddress.AddAddressResponseData
import com.woka.shop.models.addresslisting.ParentAddressData
import com.woka.shop.models.applycoupon.ApplyCouponResponse
import com.woka.shop.models.cartlisting.CartResponse
import com.woka.shop.models.categorylisting.CategoryResponse
import com.woka.shop.models.couponlisting.CouponsResponse
import com.woka.shop.models.createorder.CreateOrderRequestData
import com.woka.shop.models.createorder.CreateOrderResponse
import com.woka.shop.models.edd.EDDResponse
import com.woka.shop.models.subcategorylisting.SubCategoryResponse
import com.woka.shop.models.superlisting.SuperCategoryResponse
import okhttp3.FormBody
@@ -16,6 +21,7 @@ import retrofit2.http.POST
interface ShopApiService {
// shop
@POST("super_category_listing")
suspend fun superCategoryListing(@Body formBody: FormBody): Response<ApiResponse<SuperCategoryResponse>>
@@ -25,6 +31,7 @@ interface ShopApiService {
@POST("sub_category_listing")
suspend fun subcategoryListing(@Body formBody: FormBody): Response<ApiResponse<SubCategoryResponse>>
// cart
@GET("cart_listing")
suspend fun cartListing(): Response<ApiResponse<CartResponse>>
@@ -38,5 +45,17 @@ interface ShopApiService {
suspend fun applyCoupon(@Body formBody: FormBody): Response<ApiResponse<ApplyCouponResponse>>
@GET("parent_address_listing")
suspend fun parentAddressListing(): Response<ApiResponse<MutableList<ParentAddress>>>
suspend fun parentAddressListing(): Response<ApiResponse<MutableList<ParentAddressData>>>
@POST("add_parent_address")
suspend fun addAddress(@Body addAddressRequestData: AddAddressRequestData): Response<ApiResponse<AddAddressResponseData>>
@POST("pincode_serviceability_check_edd")
suspend fun getEDD(@Body formBody: FormBody): Response<ApiResponse<EDDResponse?>>
@POST("create_new_order")
suspend fun createOrder(@Body withCoupon: CreateOrderRequestData.WithCoupon): Response<ApiResponse<CreateOrderResponse>>
@POST("create_new_order")
suspend fun createOrder(@Body withCoupon: CreateOrderRequestData.WithoutCoupon): Response<ApiResponse<CreateOrderResponse>>
}

View File

@@ -3,11 +3,16 @@ package com.woka.shop
import com.woka.networking.ApiResult
import com.woka.networking.RetrofitHelper
import com.woka.networking.RetrofitHelper.handleApiCall
import com.woka.shop.models.addresslisting.ParentAddress
import com.woka.shop.models.addaddress.AddAddressRequestData
import com.woka.shop.models.addaddress.AddAddressResponseData
import com.woka.shop.models.addresslisting.ParentAddressData
import com.woka.shop.models.applycoupon.ApplyCouponResponse
import com.woka.shop.models.cartlisting.CartResponse
import com.woka.shop.models.categorylisting.CategoryResponse
import com.woka.shop.models.couponlisting.CouponsResponse
import com.woka.shop.models.createorder.CreateOrderRequestData
import com.woka.shop.models.createorder.CreateOrderResponse
import com.woka.shop.models.edd.EDDResponse
import com.woka.shop.models.subcategorylisting.SubCategoryResponse
import com.woka.shop.models.superlisting.SuperCategoryResponse
import okhttp3.FormBody
@@ -120,9 +125,39 @@ object ShopRepository {
}
}
suspend fun parentAddressListing(): ApiResult<MutableList<ParentAddress>> {
// address
suspend fun parentAddressListing(): ApiResult<MutableList<ParentAddressData>> {
return handleApiCall {
apiService.parentAddressListing()
}
}
suspend fun addAddress(addAddressRequestData: AddAddressRequestData): ApiResult<AddAddressResponseData> {
return handleApiCall {
apiService.addAddress(addAddressRequestData)
}
}
suspend fun getEDD(pinCode: String): ApiResult<EDDResponse?> {
return handleApiCall {
apiService.getEDD(
FormBody.Builder()
.add("pincode", pinCode)
.build()
)
}
}
// create order
suspend fun createOrder(withCoupon: CreateOrderRequestData.WithCoupon): ApiResult<CreateOrderResponse> {
return handleApiCall {
apiService.createOrder(withCoupon)
}
}
suspend fun createOrder(withoutCoupon: CreateOrderRequestData.WithoutCoupon): ApiResult<CreateOrderResponse> {
return handleApiCall {
apiService.createOrder(withoutCoupon)
}
}
}

View File

@@ -55,7 +55,10 @@ class CouponAdapter(private var selectedCouponId: Int?) :
textView.text = finalTxt
textView.setBackgroundResource(
if (selectedCouponId == coupon.id) R.color.coupon_selection
if (selectedCouponId == coupon.id){
selectedCouponPos = holder.absoluteAdapterPosition
R.color.coupon_selection
}
else R.color.white
)

View File

@@ -0,0 +1,123 @@
package com.woka.shop.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.lifecycle.viewModelScope
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.woka.R
import com.woka.databinding.CartAddressViewHolderBinding
import com.woka.shop.models.addresslisting.ParentAddressData
import com.woka.shop.viewmodels.CartViewModel
import com.woka.utils.hide
import com.woka.utils.show
import kotlinx.coroutines.launch
import java.util.concurrent.Executors
class ParentAddressAdapter (private val viewModel: CartViewModel) :
ListAdapter<ParentAddressData, ParentAddressAdapter.AddressViewHolder>(ASYNC_DIFF_UTIL) {
companion object {
private val DIFF_UTIL = object : DiffUtil.ItemCallback<ParentAddressData>() {
override fun areItemsTheSame(
oldItem: ParentAddressData, newItem: ParentAddressData
): Boolean = oldItem.id == newItem.id
override fun areContentsTheSame(
oldItem: ParentAddressData, newItem: ParentAddressData
): Boolean = oldItem == newItem
}
private val ASYNC_DIFF_UTIL = AsyncDifferConfig.Builder(DIFF_UTIL)
.setBackgroundThreadExecutor(Executors.newSingleThreadExecutor()).build()
}
inner class AddressViewHolder(val binding: CartAddressViewHolderBinding) :
ViewHolder(binding.root)
var addressSelectListener: ((Int?) -> Unit)? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddressViewHolder {
return AddressViewHolder(
CartAddressViewHolderBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
)
}
override fun onBindViewHolder(holder: AddressViewHolder, position: Int) {
val address = getItem(holder.absoluteAdapterPosition)
with(holder.binding) {
name.text = "${address.address_name}"
val fullAddress = StringBuilder("${address.address}")
address.city?.let {
fullAddress.append(", ").append(it)
}
address.state?.let {
fullAddress.append(", ").append(it)
}
address.country?.let {
fullAddress.append(", ").append(it)
}
address.pincode?.let {
fullAddress.append("\nPinCode: ").append(it)
}
address.phone_no?.let {
fullAddress.append("\nPhone no: ").append(it)
}
addressTxt.text = fullAddress
selectBtn.isChecked = viewModel.selectedAddressPos == holder.absoluteAdapterPosition
if (selectBtn.isChecked){
expectedDelivery.show()
expectedDelivery.text = viewModel.eddMap.getOrDefault(address.id, null)
}else{
expectedDelivery.hide()
}
root.setOnClickListener {
selectBtn.performClick()
}
selectBtn.setOnClickListener {
if (viewModel.selectedAddressPos != holder.absoluteAdapterPosition) {
val lastSelectedPos = viewModel.selectedAddressPos
viewModel.selectedAddressPos = holder.absoluteAdapterPosition
if (lastSelectedPos >= 0 && lastSelectedPos < currentList.size) {
notifyItemChanged(lastSelectedPos)
}
selectBtn.isChecked = true
addressSelectListener?.invoke(address.id)
viewModel.viewModelScope.launch {
address.id?.let {id ->
if (viewModel.eddMap.containsKey(id)){
expectedDelivery.show()
expectedDelivery.text = viewModel.eddMap[id]
}else{
address.pincode?.let {pin ->
viewModel.getEDD(pin)?.let {edd ->
viewModel.eddMap[id] = "${root.context.getString(R.string.expected_delivery_by)}$edd"
expectedDelivery.show()
expectedDelivery.text = viewModel.eddMap[id]
}
}
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,10 @@
package com.woka.shop.models.addaddress
data class AddAddressRequestData(
val address_name: String,
val address: String,
val city: String,
val state: String,
val pincode: String,
val mobile_number: String
)

View File

@@ -0,0 +1,16 @@
package com.woka.shop.models.addaddress
data class AddAddressResponseData(
val address: String?,
val address_name: String?,
val city: String?,
val country: String?,
val created_at: String?,
val email: String?,
val id: Int?,
val phone_no: String?,
val pincode: String?,
val state: String?,
val updated_at: String?,
val user_id: String?
)

View File

@@ -1,6 +1,6 @@
package com.woka.shop.models.addresslisting
data class ParentAddress(
data class ParentAddressData(
val address: String?,
val address_name: String?,
val address_type: String?,

View File

@@ -0,0 +1,14 @@
package com.woka.shop.models.createorder
class CreateOrderRequestData{
data class WithCoupon(
val product_ids: ArrayList<Int>,
val coupon_code: String,
val address_id: String
)
data class WithoutCoupon(
val product_ids: ArrayList<Int>,
val address_id: String
)
}

View File

@@ -0,0 +1,5 @@
package com.woka.shop.models.createorder
data class CreateOrderResponse(
val url: String?
)

View File

@@ -0,0 +1,5 @@
package com.woka.shop.models.edd
data class EDDResponse(
val result: Result?
)

View File

@@ -0,0 +1,9 @@
package com.woka.shop.models.edd
data class Result(
val EDD: String?,
val fm_message: String?,
val fm_pincode: String?,
val lm_message: String?,
val lm_pincode: String?
)

View File

@@ -0,0 +1,22 @@
package com.woka.shop.viewmodels
import androidx.lifecycle.ViewModel
import com.woka.networking.ApiResult
import com.woka.shop.ShopRepository
import com.woka.shop.models.addaddress.AddAddressRequestData
import com.woka.shop.models.addaddress.AddAddressResponseData
import com.woka.shop.models.edd.EDDResponse
class AddressViewModel: ViewModel() {
private val repository = ShopRepository
suspend fun addAddress(addressRequestData: AddAddressRequestData): ApiResult<AddAddressResponseData> {
return repository.addAddress(addressRequestData)
}
suspend fun getEDD(pinCode: String): ApiResult<EDDResponse?> {
return repository.getEDD(pinCode)
}
}

View File

@@ -6,20 +6,31 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.woka.networking.ApiResult
import com.woka.shop.ShopRepository
import com.woka.shop.models.addresslisting.ParentAddress
import com.woka.shop.models.addresslisting.ParentAddressData
import com.woka.shop.models.applycoupon.ApplyCouponResponse
import com.woka.shop.models.cartlisting.CartResponse
import com.woka.shop.models.couponlisting.CouponsResponse
import com.woka.shop.models.createorder.CreateOrderRequestData
import com.woka.shop.models.createorder.CreateOrderResponse
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
class CartViewModel: ViewModel() {
// ui callbacks
// coupons
var onToolBarTitleChange: ((String) -> Unit)? = null
var appliedCoupon: String? = null
var selectedCouponId: Int? = null
var selectedCouponCode: String? = null
// address
var selectedAddressPos: Int = -1
var selectedAddressId: Int? = null
val eddMap = HashMap<Int, String>()
// data callbacks
private val repository = ShopRepository
@@ -61,7 +72,60 @@ class CartViewModel: ViewModel() {
selectedCouponId = null
}
suspend fun parentAddressListing(): ApiResult<MutableList<ParentAddress>> {
return repository.parentAddressListing()
// addresses
private val _addressesLiveData = MutableLiveData<ApiResult<MutableList<ParentAddressData>>>()
val addressesLiveData: LiveData<ApiResult<MutableList<ParentAddressData>>>
get() = _addressesLiveData
fun loadParentAddresses(){
if (_addressesLiveData.isInitialized && _addressesLiveData.value is ApiResult.Success){
return
}
viewModelScope.launch {
_addressesLiveData.postValue(ApiResult.Loading())
_addressesLiveData.postValue(repository.parentAddressListing())
}
}
fun clearAddressSelection(){
selectedAddressPos = -1
selectedAddressId = null
eddMap.clear()
_createOrderLiveData.postValue(null)
}
suspend fun getEDD(pinCode: String): String? {
return viewModelScope.async {
when (val response = repository.getEDD(pinCode)){
is ApiResult.Error -> null
is ApiResult.Loading -> null
is ApiResult.Success -> response.data?.result?.EDD
}
}.await()
}
// creating order
private val _createOrderLiveData = MutableLiveData<ApiResult<CreateOrderResponse>?>()
val createOrderLiveData: LiveData<ApiResult<CreateOrderResponse>?>
get() = _createOrderLiveData
fun createOrder(productIds: ArrayList<Int>, couponCode: String?, addressId: String) {
viewModelScope.launch {
_createOrderLiveData.postValue(ApiResult.Loading())
_createOrderLiveData.postValue(
if (couponCode == null){
// no coupon code
repository.createOrder(CreateOrderRequestData.WithoutCoupon(
productIds, addressId
))
}else{
// coupon code applied
repository.createOrder(CreateOrderRequestData.WithCoupon(
productIds, couponCode, addressId
))
}
)
}
}
}

View File

@@ -0,0 +1,33 @@
package com.woka.shop.views
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.woka.R
import com.woka.databinding.ActivityAddressBinding
import com.woka.shop.views.fragments.address.PinCodeFragment
import com.woka.utils.WokaBaseActivity
class AddressActivity : WokaBaseActivity() {
private lateinit var binding: ActivityAddressBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityAddressBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
binding.toolbar.title.text = getString(R.string.address_details)
supportFragmentManager.beginTransaction()
.add(R.id.fcv_address, PinCodeFragment.newInstance())
.commit()
}
}

View File

@@ -0,0 +1,74 @@
package com.woka.shop.views
import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.webkit.WebSettings
import android.webkit.WebViewClient
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.woka.R
import com.woka.databinding.ActivityPaymentBinding
import com.woka.utils.WokaBaseActivity
import com.woka.utils.lightStatusBar
import com.woka.utils.toast
class PaymentActivity : WokaBaseActivity() {
companion object{
const val EXTRA_PAYMENT_LINK = "payment_link"
}
private lateinit var binding: ActivityPaymentBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityPaymentBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
intent.getStringExtra(EXTRA_PAYMENT_LINK)?.let {
with(window){
lightStatusBar()
statusBarColor = Color.BLACK
navigationBarColor = Color.BLACK
}
initWebView(it)
}?:{
toast(getString(R.string.couldn_t_load_payment_page))
finish()
}
}
override fun onDestroy() {
super.onDestroy()
binding.webView.destroy()
}
@SuppressLint("SetJavaScriptEnabled")
private fun initWebView(it: String){
val webSettings: WebSettings = binding.webView.getSettings()
webSettings.javaScriptEnabled = true
webSettings.allowFileAccess = false
webSettings.allowContentAccess = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
webSettings.safeBrowsingEnabled = true
}
binding.webView.setWebViewClient(WebViewClient())
binding.webView.loadUrl(it)
}
}

View File

@@ -7,7 +7,7 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.woka.R
import com.woka.databinding.ActivityShopBinding
import com.woka.shop.views.fragments.ShopFragment1
import com.woka.shop.views.fragments.shop.ShopFragment1
import com.woka.utils.WokaBaseActivity
class ShopActivity : WokaBaseActivity() {

View File

@@ -1,38 +0,0 @@
package com.woka.shop.views.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.woka.R
import com.woka.databinding.FragmentParentAddressBinding
import com.woka.shop.viewmodels.CartViewModel
class ParentAddressFragment : Fragment() {
private lateinit var binding: FragmentParentAddressBinding
private lateinit var viewModel: CartViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentParentAddressBinding.inflate(inflater, container, false)
viewModel = ViewModelProvider(requireActivity())[CartViewModel::class.java]
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
}
private fun initViews(){
binding.apply {
viewModel.onToolBarTitleChange?.invoke(getString(R.string.address_details))
}
}
}

View File

@@ -0,0 +1,99 @@
package com.woka.shop.views.fragments.address
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.widget.addTextChangedListener
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.woka.R
import com.woka.databinding.FragmentPinCodeBinding
import com.woka.networking.ApiResult
import com.woka.shop.viewmodels.AddressViewModel
import com.woka.utils.ProgressView
import com.woka.utils.toast
import kotlinx.coroutines.launch
class PinCodeFragment private constructor(): Fragment() {
private lateinit var binding: FragmentPinCodeBinding
private lateinit var progressView: ProgressView
private lateinit var viewModel: AddressViewModel
private var selectedPinCode: String = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentPinCodeBinding.inflate(inflater, container, false)
progressView = ProgressView(requireContext(), getString(R.string.please_wait))
viewModel = ViewModelProvider(requireActivity())[AddressViewModel::class.java]
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
clickEvents()
setObservers()
}
private fun clickEvents() {
binding.apply {
btn.setOnClickListener {
if (selectedPinCode.length == 6){
toast(selectedPinCode)
return@setOnClickListener
}
if (pincode.text.length < 6){
pincode.error = getString(R.string.enter_a_valid_pincode)
return@setOnClickListener
}
lifecycleScope.launch {
binding.apply {
val pinCode = pincode.text.toString()
progressView.show()
when (val response = viewModel.getEDD(pinCode)){
is ApiResult.Error -> {
progressView.hide()
textView.text = response.errorMessage
}
is ApiResult.Loading -> {}
is ApiResult.Success -> {
progressView.hide()
val finalText = "${response.message}\nExpected delivery by ${response.data?.result?.EDD}"
textView.text = finalText
selectedPinCode = pinCode
btn.text = getString(R.string.proceed)
}
}
}
}
}
}
}
private fun setObservers(){
binding.pincode.addTextChangedListener {
if (selectedPinCode.length == 6){
selectedPinCode = ""
binding.btn.text = getString(R.string.check_now)
binding.textView.text = null
}
}
}
companion object {
@JvmStatic
fun newInstance() = PinCodeFragment()
}
}

View File

@@ -1,4 +1,4 @@
package com.woka.shop.views.fragments
package com.woka.shop.views.fragments.cart
import android.os.Bundle
import android.view.LayoutInflater

View File

@@ -1,4 +1,4 @@
package com.woka.shop.views.fragments
package com.woka.shop.views.fragments.cart
import android.os.Bundle
import android.view.LayoutInflater
@@ -17,6 +17,7 @@ import com.woka.shop.adapters.SummaryCartAdapter
import com.woka.shop.viewmodels.CartViewModel
import com.woka.utils.ProgressView
import com.woka.utils.hide
import com.woka.utils.setVisibility
import com.woka.utils.show
import com.woka.utils.toast
import kotlinx.coroutines.launch
@@ -66,6 +67,7 @@ class OrderSummaryFragment : Fragment() {
rvCoupons.itemAnimator = null
couponCode.setText(viewModel.selectedCouponCode)
discountView.setVisibility(viewModel.appliedCoupon != null)
}
}
@@ -96,6 +98,7 @@ class OrderSummaryFragment : Fragment() {
}
confirm.setOnClickListener {
viewModel.clearAddressSelection()
findNavController().navigate(R.id.action_orderSummaryFragment_to_parentAddressFragment)
}
}

View File

@@ -0,0 +1,182 @@
package com.woka.shop.views.fragments.cart
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.woka.R
import com.woka.databinding.FragmentParentAddressBinding
import com.woka.networking.ApiResult
import com.woka.shop.adapters.ParentAddressAdapter
import com.woka.shop.models.cartlisting.CartResponse
import com.woka.shop.viewmodels.CartViewModel
import com.woka.shop.views.AddressActivity
import com.woka.shop.views.PaymentActivity
import com.woka.shop.views.PaymentActivity.Companion.EXTRA_PAYMENT_LINK
import com.woka.utils.ProgressView
import com.woka.utils.hide
import com.woka.utils.setVisibility
import com.woka.utils.show
import com.woka.utils.toast
class ParentAddressFragment : Fragment() {
private lateinit var binding: FragmentParentAddressBinding
private lateinit var viewModel: CartViewModel
private lateinit var adapter: ParentAddressAdapter
private lateinit var progressView: ProgressView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentParentAddressBinding.inflate(inflater, container, false)
viewModel = ViewModelProvider(requireActivity())[CartViewModel::class.java]
adapter = ParentAddressAdapter(viewModel)
progressView = ProgressView(requireContext(), getString(R.string.please_wait))
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
clickEvents()
setObservers()
viewModel.loadParentAddresses()
}
private fun initViews() {
binding.apply {
viewModel.onToolBarTitleChange?.invoke(getString(R.string.address_details))
rvAddresses.adapter = adapter
selectAddress.setVisibility(viewModel.selectedAddressId != null)
}
}
private fun clickEvents(){
binding.apply {
selectAddress.setOnClickListener {
val productIds = ArrayList<Int>()
if (viewModel.cartListLiveData.value is ApiResult.Success){
(viewModel.cartListLiveData.value as ApiResult.Success<CartResponse>).data?.result?.let {
for (cartItem in it){
cartItem?.id?.let {id ->
productIds.add(id)
}
}
}
}
if (productIds.isEmpty()){
toast(getString(R.string.no_products_added_to_cart))
return@setOnClickListener
}
if (viewModel.selectedAddressId == null){
toast(getString(R.string.no_address_selected))
return@setOnClickListener
}
viewModel.createOrder(productIds, viewModel.appliedCoupon, "${viewModel.selectedAddressId}")
}
addNewAddress.setOnClickListener {
activity?.let {
it.startActivity(Intent(it, AddressActivity::class.java))
}
}
}
}
private fun setObservers() {
adapter.addressSelectListener = { addressId ->
binding.selectAddress.show()
viewModel.selectedAddressId = addressId
}
viewModel.createOrderLiveData.observe(viewLifecycleOwner){
when(it){
is ApiResult.Error -> {
progressView.hide()
toast(it.errorMessage)
}
is ApiResult.Loading -> {
progressView.show()
}
is ApiResult.Success -> {
progressView.hide()
it.data?.url?.let {paymentUrl ->
activity?.let {activity ->
activity.startActivity(
Intent(activity, PaymentActivity::class.java).apply {
putExtra(EXTRA_PAYMENT_LINK, paymentUrl)
}
)
}
}
}
null -> {}
}
}
viewModel.addressesLiveData.observe(viewLifecycleOwner){
binding.apply {
when (it) {
is ApiResult.Error -> {
rvAddresses.hide()
noDataView.show()
shimmer.hide()
addNewAddress.show()
}
is ApiResult.Loading -> {
// loading
rvAddresses.hide()
noDataView.hide()
shimmer.show()
addNewAddress.hide()
}
is ApiResult.Success -> {
it.data?.let {
if (it.isNotEmpty()) {
adapter.submitList(it) {
rvAddresses.show()
noDataView.hide()
shimmer.hide()
addNewAddress.show()
}
return@observe
}
}
rvAddresses.hide()
noDataView.show()
shimmer.hide()
addNewAddress.show()
}
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
package com.woka.shop.views.fragments
package com.woka.shop.views.fragments.shop
import android.os.Bundle
import android.view.LayoutInflater

View File

@@ -1,4 +1,4 @@
package com.woka.shop.views.fragments
package com.woka.shop.views.fragments.shop
import android.os.Bundle
import android.view.LayoutInflater

View File

@@ -1,4 +1,4 @@
package com.woka.shop.views.fragments
package com.woka.shop.views.fragments.shop
import android.os.Bundle
import android.view.LayoutInflater

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/grad_my_list"
tools:context=".shop.views.AddressActivity">
<include android:id="@+id/toolbar"
layout="@layout/layout_toolbar"/>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fcv_address"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:background="@color/white"
tools:context=".shop.views.PaymentActivity">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>

View File

@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_marginHorizontal="15dp"
android:layout_marginBottom="10dp">
android:layout_marginBottom="5dp">
<RadioButton
android:id="@+id/button"
android:id="@+id/select_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:buttonTint="@color/color_primary"
@@ -37,28 +37,14 @@
/>
<TextView
android:id="@+id/address"
android:id="@+id/address_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Palm Spring, New Link Raod\nMalad, Mumbai, Maharashtra\n400001"
android:fontFamily="@font/exo_2"
android:textColor="@color/color_primary"
android:textSize="@dimen/_10ssp"
android:layout_marginTop="2dp"
/>
<TextView
android:id="@+id/phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Phone no: 828282827"
android:fontFamily="@font/exo_2"
android:textColor="@color/color_primary"
android:textSize="@dimen/_10ssp"
android:textSize="@dimen/_12ssp"
android:layout_marginTop="2dp"
@@ -68,11 +54,12 @@
android:id="@+id/expected_delivery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
tools:text="Expected delivery by:\n2024-22-02"
android:fontFamily="@font/exo_2_medium"
android:textColor="@android:color/holo_red_light"
android:textSize="@dimen/_10ssp"
android:textSize="@dimen/_12ssp"
android:layout_marginTop="2dp"

View File

@@ -5,7 +5,7 @@
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/grad_my_list"
tools:context=".shop.views.fragments.CartFragment">
tools:context=".shop.views.fragments.cart.CartFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_cart"

View File

@@ -5,7 +5,7 @@
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/grad_my_list"
tools:context=".shop.views.fragments.OrderSummaryFragment">
tools:context=".shop.views.fragments.cart.OrderSummaryFragment">
<LinearLayout
android:id="@+id/main_layout"

View File

@@ -5,7 +5,7 @@
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/grad_my_list"
tools:context=".shop.views.fragments.ParentAddressFragment">
tools:context=".shop.views.fragments.cart.ParentAddressFragment">
<RelativeLayout
android:layout_width="match_parent"
@@ -25,16 +25,19 @@
android:id="@+id/rv_addresses"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/cart_address_view_holder"
tools:itemCount="3"
android:orientation="vertical"
android:layout_marginTop="15dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@id/buttons"/>
app:layout_constraintBottom_toTopOf="@id/buttons"/>
<LinearLayout
android:id="@+id/no_data_view"
@@ -46,7 +49,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@id/buttons">
app:layout_constraintBottom_toTopOf="@id/buttons">
<ImageView
android:layout_width="100dp"
@@ -109,9 +112,9 @@
<Button
android:id="@+id/select_address"
android:visibility="visible"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="@dimen/_30sdp"
android:layout_height="@dimen/_32sdp"
android:text="@string/use_selected_address"
android:fontFamily="@font/exo_2_bold"
@@ -128,7 +131,7 @@
android:id="@+id/add_new_address"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="@dimen/_30sdp"
android:layout_height="@dimen/_32sdp"
android:text="@string/add_new_address"
android:fontFamily="@font/exo_2_bold"
@@ -139,7 +142,8 @@
android:background="@drawable/gradient_btn_bg_2"
android:layout_marginHorizontal="15dp"
android:layout_marginVertical="10dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="10dp"
/>
</LinearLayout>

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/grad_my_list"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="15dp"
tools:context=".shop.views.fragments.address.PinCodeFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/please_enter_your_pincode_below_to_check_service_availability_in_your_area"
android:fontFamily="@font/exo_2_medium"
android:textColor="@color/color_primary"
android:textSize="@dimen/_14ssp"
android:textAlignment="center"
android:layout_marginTop="10dp"
/>
<EditText
android:id="@+id/pincode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:fontFamily="@font/exo_2"
android:textSize="@dimen/_12ssp"
android:textAlignment="center"
android:hint="@string/enter_your_pincode"
android:textColorHint="@android:color/darker_gray"
android:autofillHints="postalAddress"
android:inputType="number"
android:singleLine="true"
android:background="@drawable/round_25_shadow"
android:layout_marginTop="40dp"
android:layout_marginBottom="15dp"
android:elevation="5dp"
android:paddingHorizontal="20dp"
android:paddingVertical="12dp"
android:maxLength="6"
/>
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/exo_2"
android:textColor="@color/color_primary"
android:textSize="@dimen/_12ssp"
android:textAlignment="center"
android:layout_marginTop="10dp"
/>
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="45dp"
android:text="@string/check_now"
android:fontFamily="@font/exo_2_bold"
android:textColor="@color/white"
android:textSize="@dimen/_10ssp"
android:layout_marginBottom="15dp"
android:layout_marginTop="50dp"
android:background="@drawable/round_bg_25"
android:backgroundTint="@color/color_primary"
/>
</LinearLayout>

View File

@@ -5,7 +5,7 @@
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/orders_bg"
tools:context=".shop.views.fragments.ShopFragment2">
tools:context=".shop.views.fragments.shop.ShopFragment2">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_super_category"

View File

@@ -5,7 +5,7 @@
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/orders_bg"
tools:context=".shop.views.fragments.ShopFragment2">
tools:context=".shop.views.fragments.shop.ShopFragment2">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_category"

View File

@@ -5,7 +5,7 @@
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/orders_bg"
tools:context=".shop.views.fragments.ShopFragment2">
tools:context=".shop.views.fragments.shop.ShopFragment2">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_category"

View File

@@ -7,7 +7,7 @@
<fragment
android:id="@+id/cartFragment"
android:name="com.woka.shop.views.fragments.CartFragment"
android:name="com.woka.shop.views.fragments.cart.CartFragment"
android:label="fragment_cart"
tools:layout="@layout/fragment_cart" >
<action
@@ -16,7 +16,7 @@
</fragment>
<fragment
android:id="@+id/orderSummaryFragment"
android:name="com.woka.shop.views.fragments.OrderSummaryFragment"
android:name="com.woka.shop.views.fragments.cart.OrderSummaryFragment"
android:label="fragment_order_summary"
tools:layout="@layout/fragment_order_summary" >
<action
@@ -25,7 +25,7 @@
</fragment>
<fragment
android:id="@+id/parentAddressFragment"
android:name="com.woka.shop.views.fragments.ParentAddressFragment"
android:name="com.woka.shop.views.fragments.cart.ParentAddressFragment"
android:label="fragment_parent_address"
tools:layout="@layout/fragment_parent_address" />
</navigation>

View File

@@ -246,4 +246,13 @@
<string name="add_new_address">Add New Address</string>
<string name="use_selected_address">Use Selected Address</string>
<string name="no_addresses_added">No Addresses added</string>
<string name="expected_delivery_by">Expected delivery by\n</string>
<string name="no_products_added_to_cart">No products added to cart</string>
<string name="no_address_selected">No address selected</string>
<string name="couldn_t_load_payment_page">Couldn\'t load payment page</string>
<string name="please_enter_your_pincode_below_to_check_service_availability_in_your_area">Please Enter Your Pincode Below to Check Service Availability in Your Area</string>
<string name="enter_your_pincode">Enter your pincode</string>
<string name="check_now">Check Now</string>
<string name="enter_a_valid_pincode">Enter a valid pincode</string>
<string name="proceed">Proceed</string>
</resources>