diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml
new file mode 100644
index 0000000..c1edb42
--- /dev/null
+++ b/.idea/androidTestResultsUserPreferences.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
index b86bc65..1e366c2 100644
--- a/.idea/deploymentTargetSelector.xml
+++ b/.idea/deploymentTargetSelector.xml
@@ -13,6 +13,9 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/other.xml b/.idea/other.xml
index f72681f..d1de606 100644
--- a/.idea/other.xml
+++ b/.idea/other.xml
@@ -240,6 +240,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 2093198..2d7fced 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -110,4 +110,15 @@ dependencies {
// Bottom sheet
implementation(libs.input)
+
+ // Test
+ androidTestImplementation("androidx.test.ext:junit:1.1.3")
+ androidTestImplementation("com.linkedin.dexmaker:dexmaker-mockito-inline:2.28.1")
+
+ testImplementation("junit:junit:4.13.2")
+ testImplementation("androidx.test:core:1.4.0")
+ testImplementation("org.mockito:mockito-android:4.2.0")
+ testImplementation("org.mockito:mockito-inline:4.2.0")
+ testImplementation("org.mockito:mockito-core:4.2.0")
+ testImplementation ("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0")
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 04141f8..19a4019 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,12 +11,15 @@
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/nike"
- tools:replace="android:label"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
+ tools:replace="android:label"
tools:targetApi="31">
+
diff --git a/app/src/main/java/com/nqmgaming/shoseshop/data/remote/ShoesApi.kt b/app/src/main/java/com/nqmgaming/shoseshop/data/remote/ShoesApi.kt
index 9c4e9ba..3cc0edc 100644
--- a/app/src/main/java/com/nqmgaming/shoseshop/data/remote/ShoesApi.kt
+++ b/app/src/main/java/com/nqmgaming/shoseshop/data/remote/ShoesApi.kt
@@ -122,4 +122,8 @@ interface ShoesApi {
@Header("Authorization") token: String,
@Path("id") id: String
)
+
+ /**
+ * This part is for order
+ */
}
\ No newline at end of file
diff --git a/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/checkout/CheckoutActivity.kt b/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/checkout/CheckoutActivity.kt
new file mode 100644
index 0000000..4138fc1
--- /dev/null
+++ b/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/checkout/CheckoutActivity.kt
@@ -0,0 +1,159 @@
+package com.nqmgaming.shoseshop.ui.activities.checkout
+
+import android.os.Bundle
+import android.text.InputType
+import android.widget.Toast
+import androidx.activity.enableEdgeToEdge
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import com.maxkeppeler.sheets.input.InputSheet
+import com.maxkeppeler.sheets.input.ValidationResult
+import com.maxkeppeler.sheets.input.type.InputEditText
+import com.nqmgaming.shoseshop.R
+import com.nqmgaming.shoseshop.databinding.ActivityCheckoutBinding
+import com.nqmgaming.shoseshop.util.SharedPrefUtils
+import com.wajahatkarim3.easyvalidation.core.view_ktx.validEmail
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class CheckoutActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityCheckoutBinding
+ private val viewModel: CheckoutViewModel by viewModels()
+ private lateinit var email: String
+ private lateinit var phoneNumber: String
+ private lateinit var address: String
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ binding = ActivityCheckoutBinding.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
+ }
+
+ email = SharedPrefUtils.getString(this, "email") ?: ""
+ phoneNumber = SharedPrefUtils.getString(this, "phoneNumber") ?: ""
+ address = SharedPrefUtils.getString(this, "address") ?: ""
+ binding.apply {
+ emailTv.text = email
+ phoneTv.text = phoneNumber
+ addressTv.text = address
+ editEmailIv.setOnClickListener {
+ var isEmailValid = false
+ val oldEmail: String = email
+ InputSheet().show(this@CheckoutActivity) {
+ title("Edit Email")
+ with(InputEditText {
+ required()
+ label("Email")
+ hint("Enter your email")
+ defaultValue(email)
+ inputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
+ maxLines(1)
+ startIconDrawable(R.drawable.ic_email)
+ validationListener { value ->
+ isEmailValid = value.toString().validEmail()
+ ValidationResult(isEmailValid, "Invalid email")
+ }
+ changeListener { value ->
+ email = value.toString()
+ }
+ resultListener {
+ emailTv.text = email
+ }
+ onPositive {
+ if (isEmailValid) {
+ SharedPrefUtils.saveString(this@CheckoutActivity, "email", email)
+ } else {
+ email = oldEmail
+ Toast.makeText(
+ this@CheckoutActivity,
+ "Invalid email",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ onNegative {
+ email = oldEmail
+ emailTv.text = email
+ }
+ })
+ }
+ }
+
+ editAddressIv.setOnClickListener {
+ var isAddressValid = false
+ val oldAddress: String = address
+ InputSheet().show(this@CheckoutActivity) {
+ title("Edit Address")
+ with(InputEditText {
+ required()
+ label("Address")
+ hint("Enter your address")
+ defaultValue(address)
+ maxLines(1)
+ startIconDrawable(R.drawable.ic_location)
+ validationListener { value ->
+ isAddressValid = value.toString().isNotEmpty()
+ ValidationResult(isAddressValid, "Address cannot be empty")
+ }
+ changeListener { value ->
+ address = value.toString()
+ }
+ resultListener {
+ addressTv.text = address
+ }
+ onPositive {
+ SharedPrefUtils.saveString(this@CheckoutActivity, "address", address)
+ }
+ onNegative {
+ address = oldAddress
+ addressTv.text = address
+ }
+ })
+ }
+ }
+
+ editPhoneIv.setOnClickListener {
+ var isPhoneValid = false
+ val oldPhone: String = phoneNumber
+ InputSheet().show(this@CheckoutActivity) {
+ title("Edit Phone Number")
+ with(InputEditText {
+ required()
+ label("Phone Number")
+ hint("Enter your phone number")
+ defaultValue(phoneNumber)
+ maxLines(1)
+ startIconDrawable(R.drawable.ic_telephone)
+ validationListener { value ->
+ isPhoneValid = value.toString().isNotEmpty()
+ ValidationResult(isPhoneValid, "Phone number cannot be empty")
+ }
+ changeListener { value ->
+ phoneNumber = value.toString()
+ }
+ resultListener {
+ phoneTv.text = phoneNumber
+ }
+ onPositive {
+ SharedPrefUtils.saveString(
+ this@CheckoutActivity,
+ "phoneNumber",
+ phoneNumber
+ )
+ }
+ onNegative {
+ phoneNumber = oldPhone
+ phoneTv.text = phoneNumber
+ }
+ })
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/checkout/CheckoutViewModel.kt b/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/checkout/CheckoutViewModel.kt
new file mode 100644
index 0000000..48a3bb1
--- /dev/null
+++ b/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/checkout/CheckoutViewModel.kt
@@ -0,0 +1,12 @@
+package com.nqmgaming.shoseshop.ui.activities.checkout
+
+import androidx.lifecycle.ViewModel
+import com.nqmgaming.shoseshop.data.repository.ShoesRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+@HiltViewModel
+class CheckoutViewModel @Inject constructor(
+ private val shoesRepository: ShoesRepository
+):ViewModel(){
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/signIn/SignInActivity.kt b/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/signIn/SignInActivity.kt
index 3955a14..d82ddfd 100644
--- a/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/signIn/SignInActivity.kt
+++ b/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/signIn/SignInActivity.kt
@@ -48,10 +48,8 @@ class SignInActivity : AppCompatActivity() {
viewModel.signInUser(email!!, password) { response ->
if (response != null) {
// navigate to main activity
- Log.d("SignInActivity", "User signed in successfully")
SharedPrefUtils.saveString(this, "id", response.data.id)
SharedPrefUtils.saveString(this, "email", response.data.email)
- SharedPrefUtils.saveString(this, "avatar", response.data.avatar)
SharedPrefUtils.saveString(this, "firstName", response.data.firstName)
SharedPrefUtils.saveString(this, "lastName", response.data.lastName)
SharedPrefUtils.saveString(this, "birthDate", response.data.birthDate)
@@ -65,6 +63,7 @@ class SignInActivity : AppCompatActivity() {
.setHeading("Sign in success!")
.setDescription("Welcome back to shoesshop")
.setCancelable(false)
+ .setDismissButtonText("OK")
.showDialog(object : OnDialogButtonClickListener() {
override fun onDismissClicked(dialog: Dialog) {
super.onDismissClicked(dialog)
diff --git a/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/signUp/SignUpActivity.kt b/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/signUp/SignUpActivity.kt
index 0633d4d..cf76d7a 100644
--- a/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/signUp/SignUpActivity.kt
+++ b/app/src/main/java/com/nqmgaming/shoseshop/ui/activities/signUp/SignUpActivity.kt
@@ -89,7 +89,7 @@ class SignUpActivity : AppCompatActivity() {
}.addSuccessCallback {
binding.passwordEt.error = null
}.check()
- address.validator().nonEmpty().addErrorCallback {
+ address.validator().nonEmpty().minLength(10).addErrorCallback {
binding.addressEt.error = it
binding.addressEt.requestFocus()
error = true
diff --git a/app/src/main/java/com/nqmgaming/shoseshop/ui/fragments/cart/CartFragment.kt b/app/src/main/java/com/nqmgaming/shoseshop/ui/fragments/cart/CartFragment.kt
index a3b0bd4..27344f9 100644
--- a/app/src/main/java/com/nqmgaming/shoseshop/ui/fragments/cart/CartFragment.kt
+++ b/app/src/main/java/com/nqmgaming/shoseshop/ui/fragments/cart/CartFragment.kt
@@ -13,6 +13,7 @@ import com.nqmgaming.shoseshop.adapter.cart.CartAdapter
import com.nqmgaming.shoseshop.data.model.cart.Cart
import com.nqmgaming.shoseshop.data.model.product.Product
import com.nqmgaming.shoseshop.databinding.FragmentCartBinding
+import com.nqmgaming.shoseshop.ui.activities.checkout.CheckoutActivity
import com.nqmgaming.shoseshop.ui.activities.productDetail.ProductDetailActivity
import com.nqmgaming.shoseshop.util.SharedPrefUtils
import dagger.hilt.android.AndroidEntryPoint
@@ -37,6 +38,12 @@ class CartFragment : Fragment() {
val bearerToken = "Bearer $token"
val userId = SharedPrefUtils.getString(requireContext(), "id", "") ?: ""
+ binding.paymentBtn.setOnClickListener {
+ Intent(requireContext(), CheckoutActivity::class.java).apply {
+ startActivity(this)
+ }
+ }
+
viewModel.getAllCartsMain(bearerToken, userId) { carts ->
if (carts != null) {
binding.cartRv.adapter = CartAdapter(viewModel, bearerToken).apply {
diff --git a/app/src/main/res/drawable/ic_edit.xml b/app/src/main/res/drawable/ic_edit.xml
new file mode 100644
index 0000000..308c3ae
--- /dev/null
+++ b/app/src/main/res/drawable/ic_edit.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/rounded_border.xml b/app/src/main/res/drawable/rounded_border.xml
new file mode 100644
index 0000000..70ca090
--- /dev/null
+++ b/app/src/main/res/drawable/rounded_border.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_checkout.xml b/app/src/main/res/layout/activity_checkout.xml
new file mode 100644
index 0000000..8fca800
--- /dev/null
+++ b/app/src/main/res/layout/activity_checkout.xml
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_product_checkout_review.xml b/app/src/main/res/layout/item_product_checkout_review.xml
new file mode 100644
index 0000000..737e464
--- /dev/null
+++ b/app/src/main/res/layout/item_product_checkout_review.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/test/java/com/nqmgaming/shoseshop/splash/SplashViewModelTest.kt b/app/src/test/java/com/nqmgaming/shoseshop/splash/SplashViewModelTest.kt
new file mode 100644
index 0000000..0507d4c
--- /dev/null
+++ b/app/src/test/java/com/nqmgaming/shoseshop/splash/SplashViewModelTest.kt
@@ -0,0 +1,27 @@
+import com.nqmgaming.shoseshop.data.repository.ShoesRepository
+import com.nqmgaming.shoseshop.ui.activities.splash.SplashViewModel
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runBlockingTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.junit.MockitoJUnitRunner
+
+@RunWith(MockitoJUnitRunner::class)
+class SplashViewModelTest {
+
+ @Mock
+ private lateinit var repository: ShoesRepository
+
+ private lateinit var viewModel: SplashViewModel
+
+ @Before
+ fun setup() {
+ viewModel = SplashViewModel(repository)
+ }
+
+ // Simple test to check
+
+}
\ No newline at end of file