From 0c843f74f664f35b1859a044a3685df3c1ecab9d Mon Sep 17 00:00:00 2001 From: MarkNjunge Date: Mon, 1 Jul 2019 18:54:06 +0300 Subject: [PATCH 01/20] Update dependencies --- .../ui/drinkdetails/DrinkDetailsActivity.kt | 3 +- .../justjava/ui/main/CatalogAdapter.kt | 2 +- .../marknjunge/core/mpesa/MpesaInteractor.kt | 2 +- .../com/marknjunge/core/mpesa/MpesaService.kt | 4 +- dependencies.gradle | 42 +++++++++---------- gradle/wrapper/gradle-wrapper.properties | 4 +- 6 files changed, 28 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsActivity.kt index a8a0e41..d4a7974 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsActivity.kt @@ -40,8 +40,7 @@ class DrinkDetailsActivity : BaseActivity(), DrinkDetailsView, View.OnClickListe tvSubtotal.text = resources.getString(R.string.price_listing, drink.drinkPrice.toInt()) val drinkImage = "file:///android_asset/" + drink.drinkImage - val picasso = Picasso.with(this) - picasso.load(drinkImage).noFade().into(imgDrinkImage) + Picasso.get().load(drinkImage).noFade().into(imgDrinkImage) quantity = 1 diff --git a/app/src/main/java/com/marknkamau/justjava/ui/main/CatalogAdapter.kt b/app/src/main/java/com/marknkamau/justjava/ui/main/CatalogAdapter.kt index 1741c97..3d58381 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/main/CatalogAdapter.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/main/CatalogAdapter.kt @@ -33,7 +33,7 @@ class CatalogAdapter(private val context: Context, private val onClick: (CoffeeD itemView.tvDrinkName.text = context.resources.getString(R.string.price_listing, drink.drinkPrice.toInt()) val drinkImage = "file:///android_asset/" + drink.drinkImage - Picasso.with(context).load(drinkImage).placeholder(R.drawable.plain_brown).into(itemView.imgDrinkImage) + Picasso.get().load(drinkImage).placeholder(R.drawable.plain_brown).into(itemView.imgDrinkImage) itemView.catalogItem.setOnClickListener { onClick(drink) diff --git a/core/src/main/java/com/marknjunge/core/mpesa/MpesaInteractor.kt b/core/src/main/java/com/marknjunge/core/mpesa/MpesaInteractor.kt index 44c1e1a..56c95b1 100644 --- a/core/src/main/java/com/marknjunge/core/mpesa/MpesaInteractor.kt +++ b/core/src/main/java/com/marknjunge/core/mpesa/MpesaInteractor.kt @@ -20,6 +20,6 @@ internal class MpesaInteractorImpl : MpesaInteractor { override suspend fun makeLnmoRequest(amount: Int, phoneNumber: String, customerId: String, accountRef: String, fcmToken: String): ApiResponse { val lnmoRequest = LnmoRequest(amount.toString(), Utils.sanitizePhoneNumber(phoneNumber), customerId, accountRef, fcmToken) - return mpesaService.makeRequest(BuildConfig.FunctionsApiKey, lnmoRequest).await() + return mpesaService.makeRequest(BuildConfig.FunctionsApiKey, lnmoRequest) } } \ No newline at end of file diff --git a/core/src/main/java/com/marknjunge/core/mpesa/MpesaService.kt b/core/src/main/java/com/marknjunge/core/mpesa/MpesaService.kt index 6cb0323..4144572 100644 --- a/core/src/main/java/com/marknjunge/core/mpesa/MpesaService.kt +++ b/core/src/main/java/com/marknjunge/core/mpesa/MpesaService.kt @@ -7,7 +7,7 @@ import retrofit2.http.* internal interface MpesaService { @POST("request") - fun makeRequest(@Header("ApiKey") apiKeyHeader: String, + suspend fun makeRequest(@Header("ApiKey") apiKeyHeader: String, @Body lnmoRequest: LnmoRequest - ): Deferred + ): ApiResponse } diff --git a/dependencies.gradle b/dependencies.gradle index 8295606..97fdf41 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,39 +7,39 @@ ext { ] versions = [ - kotlin : '1.3.30', - coroutines : '1.2.1', - material : '1.0.0', + kotlin : '1.3.40', + coroutines : '1.3.0-M2', + material : '1.1.0-alpha07', cardview : '1.0.0', legacySupport : '1.0.0', - appCompat : '1.0.2', - recyclerview : '1.0.0', - 'retrofit' : '2.4.0', + appCompat : '1.1.0-beta01', + recyclerview : '1.1.0-alpha06', + 'retrofit' : '2.6.0', retrofitCoroutinesAdapter: '0.9.2', - 'okhttpLogging' : '3.11.0', + 'okhttpLogging' : '4.0.0', 'gson' : '2.8.5', 'timber' : '4.7.1', - 'room' : '2.1.0-alpha07', - 'constraintLayout' : '1.1.2', - 'picasso' : '2.5.2', - 'crashlytics' : '2.9.8', - 'junit' : '4.12', - 'testRunner' : '1.1.0-alpha4', - 'espresso' : '3.1.0-alpha4', - 'testRules' : '1.1.0-alpha4', + 'room' : '2.1.0', + 'constraintLayout' : '2.0.0-beta2', + 'picasso' : '2.71828', + 'crashlytics' : '2.10.1', + 'junit' : '4.13-beta-3', + 'testRunner' : '1.3.0-alpha01', + 'espresso' : '3.3.0-alpha01', + 'testRules' : '1.3.0-alpha01', 'koin' : '2.0.0-rc-1', 'firebase' : [ - 'core' : '16.0.6', - 'auth' : '16.1.0', - 'firestore': '18.0.0', - 'messaging': '17.3.4', - 'database' : '16.0.6' + 'core' : '17.0.0', + 'auth' : '18.0.0', + 'firestore': '20.1.0', + 'messaging': '19.0.1', + 'database' : '18.0.0' ], 'mockk' : '1.9.3' ] deps = [ - androidGradlePlugin : "com.android.tools.build:gradle:3.4.0", + androidGradlePlugin : "com.android.tools.build:gradle:3.4.1", kotlinGradlePlugin : "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}", googleServices : "com.google.gms:google-services:4.2.0", fabric : "io.fabric.tools:gradle:1.28.0", diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4b516db..d71150a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue May 07 18:25:50 EAT 2019 +#Mon Jul 01 17:24:41 EAT 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip \ No newline at end of file From a91e5ce43433d2209c4f65272d0486bb7d076fbd Mon Sep 17 00:00:00 2001 From: MarkNjunge Date: Tue, 2 Jul 2019 09:20:33 +0300 Subject: [PATCH 02/20] Revert Material and AppCompat versions --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 97fdf41..f216b52 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -9,10 +9,10 @@ ext { versions = [ kotlin : '1.3.40', coroutines : '1.3.0-M2', - material : '1.1.0-alpha07', + material : '1.0.0', cardview : '1.0.0', legacySupport : '1.0.0', - appCompat : '1.1.0-beta01', + appCompat : '1.0.2', recyclerview : '1.1.0-alpha06', 'retrofit' : '2.6.0', retrofitCoroutinesAdapter: '0.9.2', From e88ce16759dd9e0967d809724366b4e2bf58ecde Mon Sep 17 00:00:00 2001 From: MarkNjunge Date: Tue, 2 Jul 2019 09:31:38 +0300 Subject: [PATCH 03/20] Update main activity, toolbar, fonts, icons --- app/src/main/AndroidManifest.xml | 13 +- .../marknkamau/justjava/ui/BaseActivity.kt | 18 +- .../justjava/ui/cart/CartActivity.kt | 2 + .../justjava/ui/checkout/CheckoutActivity.kt | 2 + .../ui/drinkdetails/DrinkDetailsActivity.kt | 4 +- .../justjava/ui/main/MainActivity.kt | 31 +- ...CatalogAdapter.kt => OldCatalogAdapter.kt} | 3 +- .../justjava/ui/profile/ProfileActivity.kt | 2 + .../justjava/utils/BaseReyclerviewAdapter.kt | 37 ++ .../main/res/drawable-mdpi/ic_github_mark.xml | 30 -- .../main/res/drawable-mdpi/ic_linkedin_tm.xml | 15 - app/src/main/res/drawable-mdpi/ic_mail.xml | 9 - .../main/res/drawable/custom_item_divider.xml | 10 + app/src/main/res/drawable/ic_add.xml | 19 +- app/src/main/res/drawable/ic_add_circle.xml | 9 - app/src/main/res/drawable/ic_cart.xml | 17 +- app/src/main/res/drawable/ic_cart_light.xml | 14 + app/src/main/res/drawable/ic_delete.xml | 19 +- app/src/main/res/drawable/ic_github_mark.xml | 49 +++ .../ic_just_java_logo_black.xml | 0 app/src/main/res/drawable/ic_linkedin.xml | 24 ++ app/src/main/res/drawable/ic_mail.xml | 14 + app/src/main/res/drawable/ic_minus.xml | 14 + app/src/main/res/drawable/ic_minus_circle.xml | 9 - app/src/main/res/drawable/ic_profile.xml | 24 +- .../main/res/drawable/ic_profile_light.xml | 19 + app/src/main/res/drawable/ic_remove.xml | 9 - app/src/main/res/drawable/ic_visibility.xml | 19 +- app/src/main/res/drawable/ic_website.xml | 17 +- .../plain_brown.xml | 0 .../topping_on.xml | 0 app/src/main/res/font/bree_serif.xml | 7 + app/src/main/res/font/{arimo.xml => lato.xml} | 2 +- app/src/main/res/layout/activity_about.xml | 4 +- app/src/main/res/layout/activity_cart.xml | 8 +- app/src/main/res/layout/activity_checkout.xml | 341 ++++++++-------- .../res/layout/activity_drink_details.xml | 4 +- app/src/main/res/layout/activity_log_in.xml | 2 +- app/src/main/res/layout/activity_main.xml | 19 +- app/src/main/res/layout/activity_profile.xml | 372 +++++++++--------- app/src/main/res/layout/activity_sign_up.xml | 2 +- .../main/res/layout/content_drink_details.xml | 2 +- app/src/main/res/layout/content_toolbar.xml | 15 + .../main/res/layout/dialog_edit_cart_item.xml | 2 +- app/src/main/res/layout/edit_fragment.xml | 4 +- app/src/main/res/layout/item_catalog.xml | 103 +++-- app/src/main/res/menu/overflow_menu.xml | 7 +- app/src/main/res/values/colors.xml | 8 +- app/src/main/res/values/preloaded_fonts.xml | 3 +- app/src/main/res/values/styles.xml | 11 +- .../core/data/local/DrinksProvider.kt | 16 +- 51 files changed, 795 insertions(+), 589 deletions(-) rename app/src/main/java/com/marknkamau/justjava/ui/main/{CatalogAdapter.kt => OldCatalogAdapter.kt} (88%) create mode 100644 app/src/main/java/com/marknkamau/justjava/utils/BaseReyclerviewAdapter.kt delete mode 100644 app/src/main/res/drawable-mdpi/ic_github_mark.xml delete mode 100644 app/src/main/res/drawable-mdpi/ic_linkedin_tm.xml delete mode 100644 app/src/main/res/drawable-mdpi/ic_mail.xml create mode 100644 app/src/main/res/drawable/custom_item_divider.xml delete mode 100644 app/src/main/res/drawable/ic_add_circle.xml create mode 100644 app/src/main/res/drawable/ic_cart_light.xml create mode 100644 app/src/main/res/drawable/ic_github_mark.xml rename app/src/main/res/{drawable-xhdpi => drawable}/ic_just_java_logo_black.xml (100%) create mode 100644 app/src/main/res/drawable/ic_linkedin.xml create mode 100644 app/src/main/res/drawable/ic_mail.xml create mode 100644 app/src/main/res/drawable/ic_minus.xml delete mode 100644 app/src/main/res/drawable/ic_minus_circle.xml create mode 100644 app/src/main/res/drawable/ic_profile_light.xml delete mode 100644 app/src/main/res/drawable/ic_remove.xml rename app/src/main/res/{drawable-xhdpi => drawable}/plain_brown.xml (100%) rename app/src/main/res/{drawable-xhdpi => drawable}/topping_on.xml (100%) create mode 100644 app/src/main/res/font/bree_serif.xml rename app/src/main/res/font/{arimo.xml => lato.xml} (89%) create mode 100644 app/src/main/res/layout/content_toolbar.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6df302c..173970c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,7 +16,7 @@ tools:ignore="GoogleAppIndexingWarning"> + android:theme="@style/AppTheme.SplashTheme"> @@ -26,39 +26,44 @@ + android:theme="@style/AppTheme.NoBar" /> + android:theme="@style/AppTheme.NoBar" /> { - startActivity(Intent(this, LogInActivity::class.java)) - return true - } R.id.menu_profile -> { if (authService.isSignedIn()) { startActivity(Intent(this, ProfileActivity::class.java)) @@ -71,7 +61,7 @@ abstract class BaseActivity : AppCompatActivity() { invalidateOptionsMenu() preferencesRepository.clearUserDetails() authService.logOut() - // If this is ProfileActivity + // If this is ProfileActivity, leave it (this as? ProfileActivity)?.finish() Toast.makeText(this, "Logged out", Toast.LENGTH_SHORT).show() return true diff --git a/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt index 6e89f37..52d79fc 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt @@ -14,6 +14,7 @@ import com.marknkamau.justjava.data.models.CartItem import com.marknkamau.justjava.ui.BaseActivity import com.marknkamau.justjava.ui.checkout.CheckoutActivity import kotlinx.android.synthetic.main.activity_cart.* +import kotlinx.android.synthetic.main.content_toolbar.* import kotlinx.coroutines.Dispatchers import org.koin.android.ext.android.inject import org.koin.core.parameter.parametersOf @@ -25,6 +26,7 @@ class CartActivity : BaseActivity(), CartView { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_cart) + setSupportActionBar(toolbar) presenter.loadItems() diff --git a/app/src/main/java/com/marknkamau/justjava/ui/checkout/CheckoutActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/checkout/CheckoutActivity.kt index 18642e3..2a439a5 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/checkout/CheckoutActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/checkout/CheckoutActivity.kt @@ -18,6 +18,7 @@ import com.marknkamau.justjava.ui.main.MainActivity import com.marknkamau.justjava.ui.previousOrder.PreviousOrderActivity import com.marknkamau.justjava.utils.trimmedText import kotlinx.android.synthetic.main.activity_checkout.* +import kotlinx.android.synthetic.main.content_toolbar.* import org.koin.android.ext.android.inject import org.koin.core.parameter.parametersOf import java.util.* @@ -36,6 +37,7 @@ class CheckoutActivity : BaseActivity(), CheckoutView { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_checkout) + setSupportActionBar(toolbar) supportActionBar?.title = "Checkout" rgPayment.setOnCheckedChangeListener { _, checkedId -> diff --git a/app/src/main/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsActivity.kt index d4a7974..1e95ef1 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsActivity.kt @@ -3,6 +3,7 @@ package com.marknkamau.justjava.ui.drinkdetails import android.os.Bundle import android.view.View import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity import com.marknkamau.justjava.R import com.marknjunge.core.model.CoffeeDrink @@ -13,11 +14,12 @@ import com.squareup.picasso.Picasso import kotlinx.android.synthetic.main.activity_drink_details.* import kotlinx.android.synthetic.main.content_drink_details.* +import kotlinx.android.synthetic.main.content_toolbar.* import kotlinx.coroutines.Dispatchers import org.koin.android.ext.android.inject import org.koin.core.parameter.parametersOf -class DrinkDetailsActivity : BaseActivity(), DrinkDetailsView, View.OnClickListener { +class DrinkDetailsActivity : AppCompatActivity(), DrinkDetailsView, View.OnClickListener { companion object { const val DRINK_KEY = "drink_key" diff --git a/app/src/main/java/com/marknkamau/justjava/ui/main/MainActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/main/MainActivity.kt index a2eb088..eb421d6 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/main/MainActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/main/MainActivity.kt @@ -2,32 +2,49 @@ package com.marknkamau.justjava.ui.main import android.content.Intent import android.os.Bundle +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.marknkamau.justjava.R import com.marknjunge.core.model.CoffeeDrink +import com.marknkamau.justjava.R import com.marknkamau.justjava.ui.BaseActivity import com.marknkamau.justjava.ui.drinkdetails.DrinkDetailsActivity - +import com.marknkamau.justjava.utils.BaseRecyclerViewAdapter +import com.squareup.picasso.Picasso import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.android.synthetic.main.content_toolbar.* +import kotlinx.android.synthetic.main.item_catalog.view.* import org.koin.android.ext.android.inject import org.koin.core.parameter.parametersOf class MainActivity : BaseActivity(), MainView { private val presenter: MainPresenter by inject { parametersOf(this) } - private lateinit var catalogAdapter: CatalogAdapter + private lateinit var catalogAdapter: BaseRecyclerViewAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + setSupportActionBar(toolbar) + + catalogAdapter = BaseRecyclerViewAdapter(R.layout.item_catalog) { drink -> + tvItemName.text = drink.drinkName + tvShortDesc.text = drink.drinkContents + tvDrinkName.text = context.resources.getString(R.string.price_listing, drink.drinkPrice.toInt()) + + val drinkImage = "file:///android_asset/" + drink.drinkImage + Picasso.get().load(drinkImage).placeholder(R.drawable.plain_brown).into(imgDrinkImage) - catalogAdapter = CatalogAdapter(this) { coffeeDrink -> - val i = Intent(this, DrinkDetailsActivity::class.java) - i.putExtra(DrinkDetailsActivity.DRINK_KEY, coffeeDrink) - startActivity(i) + catalogItem.setOnClickListener { + val i = Intent(this@MainActivity, DrinkDetailsActivity::class.java) + i.putExtra(DrinkDetailsActivity.DRINK_KEY, drink) + startActivity(i) + } } rvCatalog.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) + val dividerItemDecoration = DividerItemDecoration(this, RecyclerView.VERTICAL) + dividerItemDecoration.setDrawable(getDrawable(R.drawable.custom_item_divider)!!) + rvCatalog.addItemDecoration(dividerItemDecoration) rvCatalog.adapter = catalogAdapter presenter.getCatalogItems() diff --git a/app/src/main/java/com/marknkamau/justjava/ui/main/CatalogAdapter.kt b/app/src/main/java/com/marknkamau/justjava/ui/main/OldCatalogAdapter.kt similarity index 88% rename from app/src/main/java/com/marknkamau/justjava/ui/main/CatalogAdapter.kt rename to app/src/main/java/com/marknkamau/justjava/ui/main/OldCatalogAdapter.kt index 3d58381..0d1d5a0 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/main/CatalogAdapter.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/main/OldCatalogAdapter.kt @@ -1,7 +1,6 @@ package com.marknkamau.justjava.ui.main import android.content.Context -import androidx.recyclerview.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -10,7 +9,7 @@ import com.marknjunge.core.model.CoffeeDrink import com.squareup.picasso.Picasso import kotlinx.android.synthetic.main.item_catalog.view.* -class CatalogAdapter(private val context: Context, private val onClick: (CoffeeDrink) -> Unit) : androidx.recyclerview.widget.RecyclerView.Adapter() { +class OldCatalogAdapter(private val context: Context, private val onClick: (CoffeeDrink) -> Unit) : androidx.recyclerview.widget.RecyclerView.Adapter() { private val items by lazy { mutableListOf() } diff --git a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt index 6dcb86d..6c54d57 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt @@ -15,6 +15,7 @@ import com.marknkamau.justjava.ui.previousOrder.PreviousOrderActivity import com.marknkamau.justjava.utils.trimmedText import kotlinx.android.synthetic.main.activity_profile.* +import kotlinx.android.synthetic.main.content_toolbar.* import org.koin.android.ext.android.inject import org.koin.core.parameter.parametersOf @@ -29,6 +30,7 @@ class ProfileActivity : BaseActivity(), ProfileView { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_profile) + setSupportActionBar(toolbar) adapter = PreviousOrderAdapter(this) { order -> PreviousOrderActivity.start(this, order) diff --git a/app/src/main/java/com/marknkamau/justjava/utils/BaseReyclerviewAdapter.kt b/app/src/main/java/com/marknkamau/justjava/utils/BaseReyclerviewAdapter.kt new file mode 100644 index 0000000..1eb1022 --- /dev/null +++ b/app/src/main/java/com/marknkamau/justjava/utils/BaseReyclerviewAdapter.kt @@ -0,0 +1,37 @@ +package com.marknkamau.justjava.utils + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.LayoutRes +import androidx.recyclerview.widget.RecyclerView + +open class BaseRecyclerViewAdapter( + @LayoutRes + private val layoutRes: Int, + private val bind: View.(item: T) -> Unit +) : RecyclerView.Adapter.ViewHolder>() { + private val items by lazy { mutableListOf() } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(parent.inflate(layoutRes)) + + override fun getItemCount() = items.size + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(items[position]) + } + + fun setItems(newItems: List) { + items.clear() + items.addAll(newItems) + notifyDataSetChanged() + } + + inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + fun bind(item: T) = bind(itemView, item) + } + + private fun ViewGroup.inflate(layoutRes: Int): View { + return LayoutInflater.from(context).inflate(layoutRes, this, false) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-mdpi/ic_github_mark.xml b/app/src/main/res/drawable-mdpi/ic_github_mark.xml deleted file mode 100644 index 014d4b5..0000000 --- a/app/src/main/res/drawable-mdpi/ic_github_mark.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/drawable-mdpi/ic_linkedin_tm.xml b/app/src/main/res/drawable-mdpi/ic_linkedin_tm.xml deleted file mode 100644 index 4490649..0000000 --- a/app/src/main/res/drawable-mdpi/ic_linkedin_tm.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable-mdpi/ic_mail.xml b/app/src/main/res/drawable-mdpi/ic_mail.xml deleted file mode 100644 index 5b0b46c..0000000 --- a/app/src/main/res/drawable-mdpi/ic_mail.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/custom_item_divider.xml b/app/src/main/res/drawable/custom_item_divider.xml new file mode 100644 index 0000000..4016c66 --- /dev/null +++ b/app/src/main/res/drawable/custom_item_divider.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add.xml b/app/src/main/res/drawable/ic_add.xml index 0258249..ec3d105 100644 --- a/app/src/main/res/drawable/ic_add.xml +++ b/app/src/main/res/drawable/ic_add.xml @@ -1,9 +1,14 @@ - + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + diff --git a/app/src/main/res/drawable/ic_add_circle.xml b/app/src/main/res/drawable/ic_add_circle.xml deleted file mode 100644 index 900f227..0000000 --- a/app/src/main/res/drawable/ic_add_circle.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_cart.xml b/app/src/main/res/drawable/ic_cart.xml index 38955dc..6069a54 100644 --- a/app/src/main/res/drawable/ic_cart.xml +++ b/app/src/main/res/drawable/ic_cart.xml @@ -1,5 +1,14 @@ - - + + + diff --git a/app/src/main/res/drawable/ic_cart_light.xml b/app/src/main/res/drawable/ic_cart_light.xml new file mode 100644 index 0000000..6618d0f --- /dev/null +++ b/app/src/main/res/drawable/ic_cart_light.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml index 39e64d6..5658026 100644 --- a/app/src/main/res/drawable/ic_delete.xml +++ b/app/src/main/res/drawable/ic_delete.xml @@ -1,9 +1,14 @@ - + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + diff --git a/app/src/main/res/drawable/ic_github_mark.xml b/app/src/main/res/drawable/ic_github_mark.xml new file mode 100644 index 0000000..eb5be6c --- /dev/null +++ b/app/src/main/res/drawable/ic_github_mark.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable-xhdpi/ic_just_java_logo_black.xml b/app/src/main/res/drawable/ic_just_java_logo_black.xml similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_just_java_logo_black.xml rename to app/src/main/res/drawable/ic_just_java_logo_black.xml diff --git a/app/src/main/res/drawable/ic_linkedin.xml b/app/src/main/res/drawable/ic_linkedin.xml new file mode 100644 index 0000000..e3c70a2 --- /dev/null +++ b/app/src/main/res/drawable/ic_linkedin.xml @@ -0,0 +1,24 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_mail.xml b/app/src/main/res/drawable/ic_mail.xml new file mode 100644 index 0000000..476ccdd --- /dev/null +++ b/app/src/main/res/drawable/ic_mail.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_minus.xml b/app/src/main/res/drawable/ic_minus.xml new file mode 100644 index 0000000..a1ba00d --- /dev/null +++ b/app/src/main/res/drawable/ic_minus.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/drawable/ic_minus_circle.xml b/app/src/main/res/drawable/ic_minus_circle.xml deleted file mode 100644 index 9af9456..0000000 --- a/app/src/main/res/drawable/ic_minus_circle.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_profile.xml b/app/src/main/res/drawable/ic_profile.xml index ba54ffd..6d2597f 100644 --- a/app/src/main/res/drawable/ic_profile.xml +++ b/app/src/main/res/drawable/ic_profile.xml @@ -1,9 +1,19 @@ - + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + + diff --git a/app/src/main/res/drawable/ic_profile_light.xml b/app/src/main/res/drawable/ic_profile_light.xml new file mode 100644 index 0000000..f79e682 --- /dev/null +++ b/app/src/main/res/drawable/ic_profile_light.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_remove.xml b/app/src/main/res/drawable/ic_remove.xml deleted file mode 100644 index a541177..0000000 --- a/app/src/main/res/drawable/ic_remove.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_visibility.xml b/app/src/main/res/drawable/ic_visibility.xml index 9a4b28c..ded970b 100644 --- a/app/src/main/res/drawable/ic_visibility.xml +++ b/app/src/main/res/drawable/ic_visibility.xml @@ -1,9 +1,14 @@ - + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + diff --git a/app/src/main/res/drawable/ic_website.xml b/app/src/main/res/drawable/ic_website.xml index 8324aee..475f7b4 100644 --- a/app/src/main/res/drawable/ic_website.xml +++ b/app/src/main/res/drawable/ic_website.xml @@ -1,5 +1,14 @@ - - + + + diff --git a/app/src/main/res/drawable-xhdpi/plain_brown.xml b/app/src/main/res/drawable/plain_brown.xml similarity index 100% rename from app/src/main/res/drawable-xhdpi/plain_brown.xml rename to app/src/main/res/drawable/plain_brown.xml diff --git a/app/src/main/res/drawable-xhdpi/topping_on.xml b/app/src/main/res/drawable/topping_on.xml similarity index 100% rename from app/src/main/res/drawable-xhdpi/topping_on.xml rename to app/src/main/res/drawable/topping_on.xml diff --git a/app/src/main/res/font/bree_serif.xml b/app/src/main/res/font/bree_serif.xml new file mode 100644 index 0000000..feec39b --- /dev/null +++ b/app/src/main/res/font/bree_serif.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/font/arimo.xml b/app/src/main/res/font/lato.xml similarity index 89% rename from app/src/main/res/font/arimo.xml rename to app/src/main/res/font/lato.xml index 109cd02..015fa0c 100644 --- a/app/src/main/res/font/arimo.xml +++ b/app/src/main/res/font/lato.xml @@ -2,6 +2,6 @@ diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 5211936..51165d1 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -53,7 +53,7 @@ android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" - android:fontFamily="@font/arimo" + android:fontFamily="@font/bree_serif" android:text="@string/app_name" android:textColor="@android:color/white" android:textSize="48sp" @@ -147,7 +147,7 @@ app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/imgMail" app:layout_constraintTop_toBottomOf="@+id/textView10" - app:srcCompat="@drawable/ic_linkedin_tm" /> + app:srcCompat="@drawable/ic_linkedin" /> + + + app:layout_constraintTop_toBottomOf="@+id/toolbar" /> - + android:orientation="vertical" + tools:context="com.marknkamau.justjava.ui.checkout.CheckoutActivity"> - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + android:focusable="true" + android:focusableInTouchMode="true" + android:orientation="vertical" + tools:context="com.marknkamau.justjava.ui.checkout.CheckoutActivity"> - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - \ No newline at end of file + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + android:text="@string/payment" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tilComments" /> + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_drink_details.xml b/app/src/main/res/layout/activity_drink_details.xml index ea90224..3e76881 100644 --- a/app/src/main/res/layout/activity_drink_details.xml +++ b/app/src/main/res/layout/activity_drink_details.xml @@ -7,9 +7,11 @@ android:orientation="vertical" tools:context="com.marknkamau.justjava.ui.drinkdetails.DrinkDetailsActivity"> + + + android:layout_height="wrap_content"> - + + - + android:layout_weight="1" + tools:itemCount="8" + tools:listitem="@layout/item_catalog" /> + + diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index 57ddd42..cc0a940 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -1,201 +1,209 @@ - - + + - - + + - - + + - - + + + android:layout_height="match_parent" + android:layout_margin="8dp" + android:orientation="vertical"> - - - - - - - - + + - - - - - + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - \ No newline at end of file + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_sign_up.xml b/app/src/main/res/layout/activity_sign_up.xml index 2d457e1..16f5a4d 100644 --- a/app/src/main/res/layout/activity_sign_up.xml +++ b/app/src/main/res/layout/activity_sign_up.xml @@ -22,7 +22,7 @@ android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" - android:fontFamily="@font/arimo" + android:fontFamily="@font/bree_serif" android:text="@string/app_name" android:textColor="@android:color/white" android:textSize="48sp" diff --git a/app/src/main/res/layout/content_drink_details.xml b/app/src/main/res/layout/content_drink_details.xml index d36d321..ab1f6bb 100644 --- a/app/src/main/res/layout/content_drink_details.xml +++ b/app/src/main/res/layout/content_drink_details.xml @@ -75,7 +75,7 @@ app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView3" - app:srcCompat="@drawable/ic_remove" /> + app:srcCompat="@drawable/ic_minus" /> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_edit_cart_item.xml b/app/src/main/res/layout/dialog_edit_cart_item.xml index 387aef2..f0286e5 100644 --- a/app/src/main/res/layout/dialog_edit_cart_item.xml +++ b/app/src/main/res/layout/dialog_edit_cart_item.xml @@ -61,7 +61,7 @@ android:contentDescription="@string/minus_quantity_button_content_desc" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/cbMarshmallows" - app:srcCompat="@drawable/ic_remove" /> + app:srcCompat="@drawable/ic_minus" /> + app:srcCompat="@drawable/ic_minus" /> + app:srcCompat="@drawable/ic_add" /> - + android:layout_height="wrap_content"> - + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" + android:layout_marginBottom="8dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + - - - + - + - - \ No newline at end of file + + diff --git a/app/src/main/res/menu/overflow_menu.xml b/app/src/main/res/menu/overflow_menu.xml index 35b60e8..f3ec3f2 100644 --- a/app/src/main/res/menu/overflow_menu.xml +++ b/app/src/main/res/menu/overflow_menu.xml @@ -4,17 +4,14 @@ - - #E8E5E4 - #4e342e + #946D66 + #4F332E #3E2723 #F57C00 + #F4AF69 + #212121 + #757575 + #E0E0E0 #E0E0E0 #676767 #FFFFFF diff --git a/app/src/main/res/values/preloaded_fonts.xml b/app/src/main/res/values/preloaded_fonts.xml index 211400f..ee87b6c 100644 --- a/app/src/main/res/values/preloaded_fonts.xml +++ b/app/src/main/res/values/preloaded_fonts.xml @@ -1,6 +1,7 @@ - @font/arimo + @font/bree_serif + @font/lato diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 1b2deb6..19f727c 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -7,22 +7,29 @@ @color/colorAccent true true + @font/lato - - + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/app/src/test/java/com/marknkamau/justjava/ui/cart/CartPresenterTest.kt b/app/src/test/java/com/marknkamau/justjava/ui/cart/CartPresenterTest.kt index 9e24e03..b7598fd 100644 --- a/app/src/test/java/com/marknkamau/justjava/ui/cart/CartPresenterTest.kt +++ b/app/src/test/java/com/marknkamau/justjava/ui/cart/CartPresenterTest.kt @@ -1,9 +1,14 @@ package com.marknkamau.justjava.ui.cart +import com.marknjunge.core.auth.AuthService +import com.marknjunge.core.data.firebase.OrderService +import com.marknjunge.core.model.UserDetails import com.marknkamau.justjava.data.local.CartDao +import com.marknkamau.justjava.data.local.PreferencesRepository import com.marknkamau.justjava.data.models.CartItem import io.mockk.MockKAnnotations import io.mockk.coEvery +import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.verify import kotlinx.coroutines.Dispatchers @@ -23,6 +28,12 @@ class CartPresenterTest { private lateinit var view: CartView @MockK private lateinit var cartDao: CartDao + @MockK + private lateinit var auth: AuthService + @MockK + private lateinit var preferences: PreferencesRepository + @MockK + private lateinit var orderService: OrderService private lateinit var presenter: CartPresenter private val cartItem = CartItem(1, "itemName", 1, false, false, false, 10) @@ -32,7 +43,27 @@ class CartPresenterTest { fun setup() { MockKAnnotations.init(this, relaxUnitFun = true) - presenter = CartPresenter(view, cartDao, Dispatchers.Unconfined) + presenter = CartPresenter(view, auth, preferences, cartDao, orderService, Dispatchers.Unconfined) + } + + @Test + fun getSignInStatus_signedIn() { + val userDetails = UserDetails("", "", "", "", "") + every { auth.isSignedIn() } returns true + every { preferences.getUserDetails() } returns userDetails + + presenter.getSignInStatus() + + verify { view.setDisplayToLoggedIn(userDetails) } + } + + @Test + fun getSignInStatus_notSignedIn() { + every { auth.isSignedIn() } returns false + + presenter.getSignInStatus() + + verify { view.setDisplayToLoggedOut() } } @Test diff --git a/app/src/test/java/com/marknkamau/justjava/ui/checkout/CheckoutPresenterTest.kt b/app/src/test/java/com/marknkamau/justjava/ui/checkout/CheckoutPresenterTest.kt deleted file mode 100644 index 654790c..0000000 --- a/app/src/test/java/com/marknkamau/justjava/ui/checkout/CheckoutPresenterTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.marknkamau.justjava.ui.checkout - -import com.marknkamau.justjava.data.local.CartDao -import com.marknkamau.justjava.data.local.PreferencesRepository -import com.marknjunge.core.model.UserDetails -import com.marknjunge.core.auth.AuthService -import com.marknjunge.core.data.firebase.OrderService -import io.mockk.MockKAnnotations -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.verify -import kotlinx.coroutines.Dispatchers -import org.junit.Before -import org.junit.Test - -/** - * Created by Mark Njung'e. - * mark.kamau@outlook.com - * https://github.com/MarkNjunge - */ - -class CheckoutPresenterTest { - - @MockK - private lateinit var view: CheckoutView - @MockK - private lateinit var auth: AuthService - @MockK - private lateinit var preferences: PreferencesRepository - @MockK - private lateinit var orderService: OrderService - @MockK - private lateinit var cartDao: CartDao - - private lateinit var presenter: CheckoutPresenter - - @Before - fun setup() { - MockKAnnotations.init(this, relaxUnitFun = true) - presenter = CheckoutPresenter(view, auth, preferences, orderService, cartDao, Dispatchers.Unconfined) - } - - @Test - fun getSignInStatus_signedIn() { - val userDetails = UserDetails("", "", "", "", "") - every { auth.isSignedIn() } returns true - every { preferences.getUserDetails() } returns userDetails - - presenter.getSignInStatus() - - verify { view.setDisplayToLoggedIn(userDetails) } - } - - @Test - fun getSignInStatus_notSignedIn() { - every { auth.isSignedIn() } returns false - - presenter.getSignInStatus() - - verify { view.setDisplayToLoggedOut() } - } - -} \ No newline at end of file diff --git a/core/src/main/java/com/marknjunge/core/model/Order.kt b/core/src/main/java/com/marknjunge/core/model/Order.kt index 8cdde22..bcec67a 100644 --- a/core/src/main/java/com/marknjunge/core/model/Order.kt +++ b/core/src/main/java/com/marknjunge/core/model/Order.kt @@ -8,8 +8,8 @@ import java.util.* @Parcelize data class Order(val orderId: String, val customerId: String, - var itemsCount: Int, - var totalPrice: Int, + val itemsCount: Int, + val totalPrice: Int, val deliveryAddress: String, val additionalComments: String, val status: OrderStatus = OrderStatus.PENDING, From c5cb6d4989f6d6ea78b6d7f43d84eebaabc68141 Mon Sep 17 00:00:00 2001 From: MarkNjunge Date: Wed, 3 Jul 2019 14:19:39 +0300 Subject: [PATCH 06/20] Update about activity --- app/src/main/AndroidManifest.xml | 7 +- .../justjava/data/models/Library.kt | 21 - .../justjava/ui/about/AboutActivity.kt | 40 +- .../justjava/ui/cart/CartActivity.kt | 1 - .../ui/libraries/LibrariesActivity.kt | 39 -- .../justjava/ui/libraries/LibrariesAdapter.kt | 38 -- app/src/main/res/layout/activity_about.xml | 405 +++++++++--------- app/src/main/res/values/strings.xml | 8 + 8 files changed, 237 insertions(+), 322 deletions(-) delete mode 100644 app/src/main/java/com/marknkamau/justjava/data/models/Library.kt delete mode 100644 app/src/main/java/com/marknkamau/justjava/ui/libraries/LibrariesActivity.kt delete mode 100644 app/src/main/java/com/marknkamau/justjava/ui/libraries/LibrariesAdapter.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b2aafa2..85f1b4a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,12 +57,9 @@ android:screenOrientation="portrait" /> + android:theme="@style/AppTheme.NoBar" + android:screenOrientation="portrait"/> - - diff --git a/app/src/main/java/com/marknkamau/justjava/data/models/Library.kt b/app/src/main/java/com/marknkamau/justjava/data/models/Library.kt deleted file mode 100644 index c0c9371..0000000 --- a/app/src/main/java/com/marknkamau/justjava/data/models/Library.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.marknkamau.justjava.data.models - -/** - * Created by MarkNjunge. - * mark.kamau@outlook.com - * https://github.com/MarkNjunge - */ - -data class Library(val name: String, val author: String, val license: Int, val link: String) { - companion object { - const val MIT = 1 - const val APACHE2 = 2 - } - - val licenseText: String - get() = when (license) { - MIT -> "MIT" - APACHE2 -> "Apache-2.0" - else -> "Unknown" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/marknkamau/justjava/ui/about/AboutActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/about/AboutActivity.kt index 88c8807..8c6b7da 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/about/AboutActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/about/AboutActivity.kt @@ -1,43 +1,33 @@ package com.marknkamau.justjava.ui.about +import android.annotation.SuppressLint import android.content.Intent import android.net.Uri import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity import android.view.View +import androidx.appcompat.app.AppCompatActivity import com.marknkamau.justjava.BuildConfig import com.marknkamau.justjava.R -import com.marknkamau.justjava.ui.libraries.LibrariesActivity import kotlinx.android.synthetic.main.activity_about.* -class AboutActivity : AppCompatActivity(), View.OnClickListener { +class AboutActivity : AppCompatActivity() { + @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_about) - tvVersion.text = "v${BuildConfig.VERSION_NAME}" - - tvSource.setOnClickListener(this) - imgBack.setOnClickListener(this) - imgMail.setOnClickListener(this) - imgLinkedin.setOnClickListener(this) - imgGithub.setOnClickListener(this) - imgWebsite.setOnClickListener(this) - tvPrivacyPolicy.setOnClickListener(this) - tvLibraries.setOnClickListener { startActivity(Intent(this, LibrariesActivity::class.java)) } - } - - override fun onClick(view: View) { - when (view) { - tvSource -> openUrl("https://github.com/MarkNjunge/JustJava-Android") - imgBack -> finish() - imgMail -> sendEmail() - imgLinkedin -> openUrl("https://linkedin.com/in/marknjunge") - imgGithub -> openUrl("https://github.com/MarkNjunge") - imgWebsite -> openUrl("https://marknjunge.com") - tvPrivacyPolicy -> openUrl("https://marknjunge.com/justjava/privacy") - } + imgBackAbout.setOnClickListener { finish() } + tvAppVersionAbout.text = "v${BuildConfig.VERSION_NAME} ${if (BuildConfig.BUILD_TYPE == "debug") "(debug)" else ""}" + tvSourceCodeAbout.setOnClickListener { openUrl("https://github.com/MarkNjunge/JustJava-Android") } + imgEmailAbout.setOnClickListener { sendEmail() } + imgLinkedInAbout.setOnClickListener { openUrl("https://linkedin.com/in/marknjunge") } + imgWebsiteAbout.setOnClickListener { openUrl("https://marknjunge.com") } + imgGithubAbout.setOnClickListener { openUrl("https://github.com/MarkNjunge") } + tvPrivacyPolicyAbout.setOnClickListener { openUrl("https://marknjunge.com/justjava/privacy") } + + // See https://github.com/google/play-services-plugins/pull/62 + tvLicensesAbout.visibility = View.GONE } private fun openUrl(url: String) = startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) diff --git a/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt index bf4601a..e2a4afe 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt @@ -31,7 +31,6 @@ import org.koin.core.parameter.parametersOf class CartActivity : BaseActivity(), CartView { - private val presenter: CartPresenter by inject { parametersOf(this) } private lateinit var adapter: BaseRecyclerViewAdapter private var payMpesa = true diff --git a/app/src/main/java/com/marknkamau/justjava/ui/libraries/LibrariesActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/libraries/LibrariesActivity.kt deleted file mode 100644 index 0a32220..0000000 --- a/app/src/main/java/com/marknkamau/justjava/ui/libraries/LibrariesActivity.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.marknkamau.justjava.ui.libraries - -import android.content.Intent -import android.net.Uri -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle -import android.widget.LinearLayout -import androidx.recyclerview.widget.RecyclerView -import com.marknkamau.justjava.R -import com.marknkamau.justjava.data.models.Library -import kotlinx.android.synthetic.main.activity_libraries.* - -class LibrariesActivity : AppCompatActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_libraries) - - val libraries = mutableListOf( - Library("Retrofit", "Square", Library.APACHE2, "http://square.github.io/retrofit/"), - Library("Gson", "Google", Library.APACHE2, "https://github.com/google/gson"), - Library("RxJava", "ReactiveX", Library.APACHE2, "https://github.com/ReactiveX/RxJava"), - Library("RxAndroid", "ReactiveX", Library.APACHE2, "https://github.com/ReactiveX/RxAndroid"), - Library("RxKotlin", "ReactiveX", Library.APACHE2, "https://github.com/ReactiveX/RxKotlin"), - Library("Picasso", "Square", Library.APACHE2, "http://square.github.io/picasso/"), - Library("Timber", "Jake Wharton", Library.APACHE2, "https://github.com/JakeWharton/timber"), - Library("Mockito", "Mockito", Library.MIT, "https://github.com/mockito/mockito"), - Library("Mockito-Kotlin", "Niek Haarman", Library.MIT, "https://github.com/nhaarman/mockito-kotlin") - ).sortedBy { it.name } - - rvLibraries.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this, RecyclerView.VERTICAL, false) - rvLibraries.addItemDecoration(androidx.recyclerview.widget.DividerItemDecoration(this, LinearLayout.VERTICAL)) - rvLibraries.adapter = LibrariesAdapter(libraries) { library -> - openUrl(library.link) - } - } - - private fun openUrl(url: String) = startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) -} diff --git a/app/src/main/java/com/marknkamau/justjava/ui/libraries/LibrariesAdapter.kt b/app/src/main/java/com/marknkamau/justjava/ui/libraries/LibrariesAdapter.kt deleted file mode 100644 index 90eb6e1..0000000 --- a/app/src/main/java/com/marknkamau/justjava/ui/libraries/LibrariesAdapter.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.marknkamau.justjava.ui.libraries - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.marknkamau.justjava.R -import com.marknkamau.justjava.data.models.Library -import kotlinx.android.synthetic.main.item_library.view.* -import java.util.* - -/** - * Created by MarkNjunge. - * mark.kamau@outlook.com - * https://github.com/MarkNjunge - */ - -class LibrariesAdapter(private val data: List, private val onClick: (Library) -> Unit) : androidx.recyclerview.widget.RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_library, parent, false)) - - override fun getItemCount() = data.size - - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bind(data[position], onClick) - } - - class ViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) { - fun bind(library: Library, onClick: (Library) -> Unit) { - with(itemView) { - tvName.text = library.name - tvAuthor.text = library.author - tvLicense.text = library.licenseText - - rootLayout.setOnClickListener { onClick(library) } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 51165d1..d07eb10 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -1,233 +1,252 @@ - - + android:layout_height="wrap_content" + tools:context="com.marknkamau.justjava.ui.about.AboutActivity"> + android:layout_height="match_parent" + android:background="@color/colorPrimaryDark"> - - + android:textColor="#FFFFFF" + android:textSize="24sp" + app:layout_constraintBottom_toTopOf="@+id/tvSourceCodeAbout" + app:layout_constraintStart_toEndOf="@+id/imageView3" + app:layout_constraintTop_toTopOf="@+id/imageView3" + app:layout_constraintVertical_chainStyle="packed" /> + android:textColor="@color/colorPrimaryLight" + app:layout_constraintBaseline_toBaselineOf="@+id/textView5" + app:layout_constraintStart_toEndOf="@+id/textView5" + tools:text="1.6.0 (debug)" /> - - - - - - - - - - - - - - - - - - - - + android:text="@string/source_code" + android:textColor="#ffffff" + app:layout_constraintBottom_toBottomOf="@+id/imageView3" + app:layout_constraintStart_toEndOf="@+id/imageView3" + app:layout_constraintTop_toBottomOf="@+id/textView5" /> - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7684ade..1a59cfc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -96,6 +96,14 @@ Change Order details You need to log in to continue + Contact via email + View LinkedIn + View website + View Github profile + App Icon + Coffee by Nitikta from The Noun Project + Privacy policy + Open Source Licenses %1$d item for Ksh. %2$d From 4695304ab7b42e5fe66fb2fb626ce62c77427b7e Mon Sep 17 00:00:00 2001 From: MarkNjunge Date: Wed, 3 Jul 2019 19:38:48 +0300 Subject: [PATCH 07/20] Update profile activity --- .../ui/profile/PreviousOrderAdapter.kt | 48 --- .../justjava/ui/profile/ProfileActivity.kt | 93 +++-- .../justjava/ui/profile/ProfilePresenter.kt | 9 +- .../justjava/ui/profile/ProfileView.kt | 4 +- .../justjava/utils/DividerItemDecorator.kt | 2 +- .../justjava/utils/KeyboardUtils.kt | 17 + app/src/main/res/drawable/il_no_orders.xml | 53 +++ app/src/main/res/layout/activity_profile.xml | 342 ++++++++---------- .../main/res/layout/item_previous_order.xml | 57 +-- app/src/main/res/values/strings.xml | 6 +- 10 files changed, 316 insertions(+), 315 deletions(-) delete mode 100644 app/src/main/java/com/marknkamau/justjava/ui/profile/PreviousOrderAdapter.kt create mode 100644 app/src/main/java/com/marknkamau/justjava/utils/KeyboardUtils.kt create mode 100644 app/src/main/res/drawable/il_no_orders.xml diff --git a/app/src/main/java/com/marknkamau/justjava/ui/profile/PreviousOrderAdapter.kt b/app/src/main/java/com/marknkamau/justjava/ui/profile/PreviousOrderAdapter.kt deleted file mode 100644 index 4b204e1..0000000 --- a/app/src/main/java/com/marknkamau/justjava/ui/profile/PreviousOrderAdapter.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.marknkamau.justjava.ui.profile - -import android.annotation.SuppressLint -import android.content.Context -import androidx.recyclerview.widget.RecyclerView -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.marknkamau.justjava.R -import com.marknjunge.core.model.Order -import com.marknkamau.justjava.utils.formatForApp -import kotlinx.android.synthetic.main.item_previous_order.view.* - -class PreviousOrderAdapter(private val context: Context, private val onClick: (order: Order) -> Unit) : androidx.recyclerview.widget.RecyclerView.Adapter() { - private val items by lazy { mutableListOf() } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(parent.inflate(R.layout.item_previous_order)) - - override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(items[position], context, onClick) - - override fun getItemCount() = items.size - - fun setItems(items: MutableList) { - this.items.clear() - this.items.addAll(items) - notifyDataSetChanged() - } - - class ViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) { - - @SuppressLint("SetTextI18n") - fun bind(order: Order, context: Context, onClick: (order: Order) -> Unit) { - itemView.tvTimestamp.text = order.date.formatForApp() - itemView.tvStatus.text = order.status.name.toLowerCase().capitalize() - itemView.tvAddress.text = order.deliveryAddress - itemView.tvOrderInfo.text = context.resources.getQuantityString(R.plurals.order_info, order.itemsCount, order.itemsCount, order.totalPrice) - - itemView.rootLayout.setOnClickListener { - onClick(order) - } - } - } - - - private fun ViewGroup.inflate(layoutRes: Int): View { - return LayoutInflater.from(context).inflate(layoutRes, this, false) - } -} diff --git a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt index 6c54d57..a337077 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt @@ -1,29 +1,24 @@ package com.marknkamau.justjava.ui.profile import android.os.Bundle -import android.text.TextUtils import android.view.View -import android.widget.LinearLayout import android.widget.Toast +import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView - -import com.marknkamau.justjava.R import com.marknjunge.core.model.Order import com.marknjunge.core.model.UserDetails +import com.marknkamau.justjava.R import com.marknkamau.justjava.ui.BaseActivity import com.marknkamau.justjava.ui.previousOrder.PreviousOrderActivity - -import com.marknkamau.justjava.utils.trimmedText +import com.marknkamau.justjava.utils.* import kotlinx.android.synthetic.main.activity_profile.* import kotlinx.android.synthetic.main.content_toolbar.* +import kotlinx.android.synthetic.main.item_previous_order.view.* import org.koin.android.ext.android.inject import org.koin.core.parameter.parametersOf class ProfileActivity : BaseActivity(), ProfileView { - private var name: String? = null - private var phone: String? = null - private var address: String? = null - private lateinit var adapter: PreviousOrderAdapter + private lateinit var previousOrdersAdapter: BaseRecyclerViewAdapter private val presenter: ProfilePresenter by inject { parametersOf(this) } @@ -32,18 +27,30 @@ class ProfileActivity : BaseActivity(), ProfileView { setContentView(R.layout.activity_profile) setSupportActionBar(toolbar) - adapter = PreviousOrderAdapter(this) { order -> - PreviousOrderActivity.start(this, order) + previousOrdersAdapter = BaseRecyclerViewAdapter(R.layout.item_previous_order) { order -> + tvOrderTimeItem.text = order.date.formatForApp() + tvOrderStatusItem.text = order.status.name.toLowerCase().capitalize() + tvOrderQtyItem.text = order.itemsCount.toString() + tvOrderCountItem.text = resources.getQuantityString(R.plurals.order_info, order.itemsCount) + tvOrderTotalItem.text = resources.getString(R.string.price_listing, order.totalPrice) + + previousOrderItemRootLayout.setOnClickListener { + PreviousOrderActivity.start(this@ProfileActivity, order) + } } - rvPreviousOrders.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this, RecyclerView.VERTICAL, false) - rvPreviousOrders.addItemDecoration(androidx.recyclerview.widget.DividerItemDecoration(this, LinearLayout.VERTICAL)) - rvPreviousOrders.adapter = adapter + rvPreviousOrdersProfile.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) + rvPreviousOrdersProfile.addItemDecoration(DividerItemDecorator(getDrawable(R.drawable.custom_item_divider)!!)) + rvPreviousOrdersProfile.adapter = previousOrdersAdapter presenter.getUserDetails() presenter.getPreviousOrders() btnUpdateProfile.setOnClickListener { saveChanges() } + + etNameProfile.onTextChanged { tilNameProfile.error = null } + etPhoneProfile.onTextChanged { tilPhoneProfile.error = null } + etAddressProfile.onTextChanged { tilAddressProfile.error = null } } override fun onDestroy() { @@ -51,56 +58,62 @@ class ProfileActivity : BaseActivity(), ProfileView { presenter.cancel() } - override fun showOrdersProgressBar() { - pbLoadingOrders.visibility = View.VISIBLE - } - - override fun hideOrdersProgressBar() { - pbLoadingOrders.visibility = View.GONE - } - override fun showProfileProgressBar() { - pbUpdatingProject.visibility = View.VISIBLE + pbUpdatingProfile.visibility = View.VISIBLE } override fun hideProfileProgressBar() { - pbUpdatingProject.visibility = View.GONE + pbUpdatingProfile.visibility = View.GONE } override fun displayNoPreviousOrders() { - tvNoOrders.visibility = View.VISIBLE - rvPreviousOrders.visibility = View.GONE + pbLoadingOrdersProfile.visibility = View.GONE + contentNoOrdersProfile.visibility = View.VISIBLE + rvPreviousOrdersProfile.visibility = View.GONE } override fun displayPreviousOrders(orderList: MutableList) { - adapter.setItems(orderList) + pbLoadingOrdersProfile.visibility = View.GONE + contentNoOrdersProfile.visibility = View.GONE + rvPreviousOrdersProfile.visibility = View.VISIBLE + previousOrdersAdapter.setItems(orderList) } - override fun displayMessage(message: String?) { + override fun displayMessage(message: String) { Toast.makeText(this, message, Toast.LENGTH_SHORT).show() } private fun saveChanges() { if (fieldsOk()) { - presenter.updateUserDetails(name!!, phone!!, address!!) + hideKeyboard() + presenter.updateUserDetails(etNameProfile.trimmedText, etPhoneProfile.trimmedText, etAddressProfile.trimmedText) } } private fun fieldsOk(): Boolean { - name = etName.trimmedText - phone = etPhone.trimmedText - address = etDeliveryAddress.trimmedText + var isValid = true + + if (etNameProfile.trimmedText.isEmpty()) { + isValid = false + tilNameProfile.error = getString(R.string.required) + } - if (TextUtils.isEmpty(name) || TextUtils.isEmpty(phone) || TextUtils.isEmpty(address)) { - Toast.makeText(this, "All fields are required", Toast.LENGTH_SHORT).show() - return false + if (etPhoneProfile.trimmedText.isEmpty()) { + isValid = false + tilPhoneProfile.error = getString(R.string.required) } - return true + + if (etAddressProfile.trimmedText.isEmpty()) { + isValid = false + tilAddressProfile.error = getString(R.string.required) + } + + return isValid } override fun displayUserDetails(userDetails: UserDetails) { - etName.setText(userDetails.name) - etPhone.setText(userDetails.phone) - etDeliveryAddress.setText(userDetails.address) + etNameProfile.setText(userDetails.name) + etPhoneProfile.setText(userDetails.phone) + etAddressProfile.setText(userDetails.address) } } \ No newline at end of file diff --git a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfilePresenter.kt b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfilePresenter.kt index 56847dd..f545e62 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfilePresenter.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfilePresenter.kt @@ -26,20 +26,17 @@ internal class ProfilePresenter(private val view: ProfileView, } fun getPreviousOrders() { - view.showOrdersProgressBar() uiScope.launch { try { val previousOrders = orderService.getPreviousOrders(authenticationService.getCurrentUser().userId) - view.hideOrdersProgressBar() if (previousOrders.isEmpty()) { view.displayNoPreviousOrders() } else { - val sorted = previousOrders.sortedBy { it.date }.reversed().toMutableList() + val sorted = previousOrders.take(3).sortedBy { it.date }.reversed().toMutableList() view.displayPreviousOrders(sorted) } } catch (e: Exception) { - view.hideOrdersProgressBar() - view.displayMessage(e.message) + view.displayMessage(e.message ?: "Error getting previous orders") } } } @@ -58,7 +55,7 @@ internal class ProfilePresenter(private val view: ProfileView, } catch (e: Exception) { Timber.e(e) view.hideProfileProgressBar() - view.displayMessage(e.message) + view.displayMessage(e.message ?: "Error upating profile") } } } diff --git a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileView.kt b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileView.kt index d01c6d2..f53eaae 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileView.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileView.kt @@ -5,11 +5,9 @@ import com.marknjunge.core.model.UserDetails internal interface ProfileView { fun displayUserDetails(userDetails: UserDetails) - fun showOrdersProgressBar() - fun hideOrdersProgressBar() fun showProfileProgressBar() fun hideProfileProgressBar() fun displayNoPreviousOrders() fun displayPreviousOrders(orderList: MutableList) - fun displayMessage(message: String?) + fun displayMessage(message: String) } diff --git a/app/src/main/java/com/marknkamau/justjava/utils/DividerItemDecorator.kt b/app/src/main/java/com/marknkamau/justjava/utils/DividerItemDecorator.kt index d7d4bca..5eea497 100644 --- a/app/src/main/java/com/marknkamau/justjava/utils/DividerItemDecorator.kt +++ b/app/src/main/java/com/marknkamau/justjava/utils/DividerItemDecorator.kt @@ -1,8 +1,8 @@ package com.marknkamau.justjava.utils import android.graphics.Canvas -import androidx.recyclerview.widget.RecyclerView import android.graphics.drawable.Drawable +import androidx.recyclerview.widget.RecyclerView class DividerItemDecorator(private val mDivider: Drawable) : RecyclerView.ItemDecoration() { override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) { diff --git a/app/src/main/java/com/marknkamau/justjava/utils/KeyboardUtils.kt b/app/src/main/java/com/marknkamau/justjava/utils/KeyboardUtils.kt new file mode 100644 index 0000000..b11e29b --- /dev/null +++ b/app/src/main/java/com/marknkamau/justjava/utils/KeyboardUtils.kt @@ -0,0 +1,17 @@ +package com.marknkamau.justjava.utils + +import android.content.Context +import android.view.inputmethod.InputMethodManager +import androidx.appcompat.app.AppCompatActivity + +fun AppCompatActivity.hideKeyboard() { + this.currentFocus?.let { + val manager = this.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + manager.hideSoftInputFromWindow(it.windowToken, 0) + } +} + +fun AppCompatActivity.showKeyboard() { + val manager = this.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + manager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0) +} diff --git a/app/src/main/res/drawable/il_no_orders.xml b/app/src/main/res/drawable/il_no_orders.xml new file mode 100644 index 0000000..df32b02 --- /dev/null +++ b/app/src/main/res/drawable/il_no_orders.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index cc0a940..c3b760b 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -9,201 +9,155 @@ - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_gravity="center" + android:text="@string/you_do_not_have_any_previous_orders" /> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_previous_order.xml b/app/src/main/res/layout/item_previous_order.xml index 13c94a2..b15a39e 100644 --- a/app/src/main/res/layout/item_previous_order.xml +++ b/app/src/main/res/layout/item_previous_order.xml @@ -2,53 +2,68 @@ + app:layout_constraintTop_toBottomOf="@+id/tvOrderTimeItem" + tools:text="1" /> + android:layout_marginStart="4dp" + android:layout_marginTop="8dp" + android:text="@string/item_for" + app:layout_constraintStart_toEndOf="@+id/tvOrderQtyItem" + app:layout_constraintTop_toBottomOf="@+id/tvOrderTimeItem" /> + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1a59cfc..25f996f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -104,9 +104,11 @@ Coffee by Nitikta from The Noun Project Privacy policy Open Source Licenses + Account details + item for - %1$d item for Ksh. %2$d - %1$d items for Ksh. %2$d + item for + items for From 2df87edf8f040d795a62d12e3efb58a69eaf6d1f Mon Sep 17 00:00:00 2001 From: MarkNjunge Date: Thu, 4 Jul 2019 20:13:58 +0300 Subject: [PATCH 08/20] Remove unused theme --- app/src/main/AndroidManifest.xml | 13 ++++--------- app/src/main/res/values/styles.xml | 16 ++-------------- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 85f1b4a..38483f2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,6 +14,7 @@ android:supportsRtl="false" android:theme="@style/AppTheme" tools:ignore="GoogleAppIndexingWarning"> + @@ -26,38 +27,32 @@ + android:screenOrientation="portrait" + android:theme="@style/AppTheme.TranslucentStatus" /> + android:screenOrientation="portrait" /> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 954fd47..35f829f 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,17 +1,5 @@ - - - - - From 0c1cff9f75daecfddc4fe7532c5cf159d9b838bf Mon Sep 17 00:00:00 2001 From: MarkNjunge Date: Thu, 4 Jul 2019 20:46:28 +0300 Subject: [PATCH 09/20] Add previous orders activity --- app/src/main/AndroidManifest.xml | 7 +- .../com/marknkamau/justjava/di/Modules.kt | 3 + .../previousOrders/PreviousOrdersActivity.kt | 68 +++++++++++++++++++ .../previousOrders/PreviousOrdersPresenter.kt | 31 +++++++++ .../ui/previousOrders/PreviousOrdersView.kt | 9 +++ .../justjava/ui/profile/ProfileActivity.kt | 4 ++ .../res/layout/activity_previous_orders.xml | 52 ++++++++++++++ app/src/main/res/layout/activity_profile.xml | 16 ++++- app/src/main/res/values/strings.xml | 1 + 9 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersActivity.kt create mode 100644 app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersPresenter.kt create mode 100644 app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersView.kt create mode 100644 app/src/main/res/layout/activity_previous_orders.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 38483f2..6b626ce 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -53,8 +53,13 @@ android:screenOrientation="portrait" /> + android:screenOrientation="portrait" /> + + diff --git a/app/src/main/java/com/marknkamau/justjava/di/Modules.kt b/app/src/main/java/com/marknkamau/justjava/di/Modules.kt index 997d3ab..bd64acd 100644 --- a/app/src/main/java/com/marknkamau/justjava/di/Modules.kt +++ b/app/src/main/java/com/marknkamau/justjava/di/Modules.kt @@ -15,6 +15,8 @@ import com.marknkamau.justjava.ui.main.MainPresenter import com.marknkamau.justjava.ui.main.MainView import com.marknkamau.justjava.ui.previousOrder.PreviousOrderPresenter import com.marknkamau.justjava.ui.previousOrder.PreviousOrderView +import com.marknkamau.justjava.ui.previousOrders.PreviousOrdersPresenter +import com.marknkamau.justjava.ui.previousOrders.PreviousOrdersView import com.marknkamau.justjava.ui.profile.ProfilePresenter import com.marknkamau.justjava.ui.profile.ProfileView import com.marknkamau.justjava.ui.signup.SignUpPresenter @@ -36,4 +38,5 @@ val appModule = module { factory { (view: CartView) -> CartPresenter(view, get(), get(), get(), get(), Dispatchers.Main) } factory { (view: PreviousOrderView) -> PreviousOrderPresenter(view, get(), get(), get(), Dispatchers.Main) } factory { (view: ProfileView) -> ProfilePresenter(view, get(), get(), get(), get(), Dispatchers.Main) } + factory { (view: PreviousOrdersView) -> PreviousOrdersPresenter(view, get(), get(), Dispatchers.Main) } } \ No newline at end of file diff --git a/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersActivity.kt new file mode 100644 index 0000000..69c5741 --- /dev/null +++ b/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersActivity.kt @@ -0,0 +1,68 @@ +package com.marknkamau.justjava.ui.previousOrders + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.View +import android.widget.Toast +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.marknjunge.core.model.Order +import com.marknkamau.justjava.R +import com.marknkamau.justjava.ui.previousOrder.PreviousOrderActivity +import com.marknkamau.justjava.utils.BaseRecyclerViewAdapter +import com.marknkamau.justjava.utils.DividerItemDecorator +import com.marknkamau.justjava.utils.formatForApp +import kotlinx.android.synthetic.main.activity_previous_orders.* +import kotlinx.android.synthetic.main.content_toolbar.* +import kotlinx.android.synthetic.main.item_previous_order.view.* +import org.koin.android.ext.android.inject +import org.koin.core.parameter.parametersOf + +class PreviousOrdersActivity : AppCompatActivity(), PreviousOrdersView { + + private lateinit var previousOrdersAdapter: BaseRecyclerViewAdapter + private val presenter: PreviousOrdersPresenter by inject { parametersOf(this) } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_previous_orders) + setSupportActionBar(toolbar) + supportActionBar?.title = getString(R.string.previous_orders) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + + previousOrdersAdapter = BaseRecyclerViewAdapter(R.layout.item_previous_order) { order -> + tvOrderTimeItem.text = order.date.formatForApp() + tvOrderStatusItem.text = order.status.name.toLowerCase().capitalize() + tvOrderQtyItem.text = order.itemsCount.toString() + tvOrderCountItem.text = resources.getQuantityString(R.plurals.order_info, order.itemsCount) + tvOrderTotalItem.text = resources.getString(R.string.price_listing, order.totalPrice) + + previousOrderItemRootLayout.setOnClickListener { + PreviousOrderActivity.start(this@PreviousOrdersActivity, order) + } + } + + rvPreviousOrdersActivity.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) + rvPreviousOrdersActivity.addItemDecoration(DividerItemDecorator(getDrawable(R.drawable.custom_item_divider)!!)) + rvPreviousOrdersActivity.adapter = previousOrdersAdapter + + presenter.getPreviousOrders() + } + + override fun displayMessage(message: String) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show() + } + + override fun displayNoOrders() { + pbLoadingOrdersPreviousActivity.visibility = View.GONE + contentNoOrdersPreviousActivity.visibility = View.VISIBLE + rvPreviousOrdersActivity.visibility = View.GONE + } + + override fun displayOrders(orders: List) { + pbLoadingOrdersPreviousActivity.visibility = View.GONE + contentNoOrdersPreviousActivity.visibility = View.GONE + rvPreviousOrdersActivity.visibility = View.VISIBLE + previousOrdersAdapter.setItems(orders) + } +} diff --git a/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersPresenter.kt b/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersPresenter.kt new file mode 100644 index 0000000..c83cc62 --- /dev/null +++ b/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersPresenter.kt @@ -0,0 +1,31 @@ +package com.marknkamau.justjava.ui.previousOrders + +import com.marknjunge.core.auth.AuthService +import com.marknjunge.core.data.firebase.OrderService +import com.marknkamau.justjava.ui.BasePresenter +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.launch + +class PreviousOrdersPresenter(private val view: PreviousOrdersView, + private val authenticationService: AuthService, + private val orderService: OrderService, + mainDispatcher: CoroutineDispatcher +): BasePresenter(mainDispatcher){ + + fun getPreviousOrders() { + uiScope.launch { + try { + val previousOrders = orderService.getPreviousOrders(authenticationService.getCurrentUser().userId) + if (previousOrders.isEmpty()) { + view.displayNoOrders() + } else { + val sorted = previousOrders.sortedBy { it.date }.reversed().toMutableList() + view.displayOrders(sorted) + } + } catch (e: Exception) { + view.displayMessage(e.message ?: "Error getting previous orders") + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersView.kt b/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersView.kt new file mode 100644 index 0000000..ba1b9c4 --- /dev/null +++ b/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersView.kt @@ -0,0 +1,9 @@ +package com.marknkamau.justjava.ui.previousOrders + +import com.marknjunge.core.model.Order + +interface PreviousOrdersView { + fun displayMessage(message: String) + fun displayNoOrders() + fun displayOrders(orders: List) +} \ No newline at end of file diff --git a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt index a337077..fa4a2dc 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt @@ -1,5 +1,6 @@ package com.marknkamau.justjava.ui.profile +import android.content.Intent import android.os.Bundle import android.view.View import android.widget.Toast @@ -10,6 +11,7 @@ import com.marknjunge.core.model.UserDetails import com.marknkamau.justjava.R import com.marknkamau.justjava.ui.BaseActivity import com.marknkamau.justjava.ui.previousOrder.PreviousOrderActivity +import com.marknkamau.justjava.ui.previousOrders.PreviousOrdersActivity import com.marknkamau.justjava.utils.* import kotlinx.android.synthetic.main.activity_profile.* import kotlinx.android.synthetic.main.content_toolbar.* @@ -47,6 +49,7 @@ class ProfileActivity : BaseActivity(), ProfileView { presenter.getPreviousOrders() btnUpdateProfile.setOnClickListener { saveChanges() } + tvSeeMoreProfile.setOnClickListener { startActivity(Intent(this, PreviousOrdersActivity::class.java)) } etNameProfile.onTextChanged { tilNameProfile.error = null } etPhoneProfile.onTextChanged { tilPhoneProfile.error = null } @@ -76,6 +79,7 @@ class ProfileActivity : BaseActivity(), ProfileView { pbLoadingOrdersProfile.visibility = View.GONE contentNoOrdersProfile.visibility = View.GONE rvPreviousOrdersProfile.visibility = View.VISIBLE + tvSeeMoreProfile.visibility = View.VISIBLE previousOrdersAdapter.setItems(orderList) } diff --git a/app/src/main/res/layout/activity_previous_orders.xml b/app/src/main/res/layout/activity_previous_orders.xml new file mode 100644 index 0000000..c0a5167 --- /dev/null +++ b/app/src/main/res/layout/activity_previous_orders.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index c3b760b..42ca05e 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -126,12 +126,11 @@ android:indeterminate="true" /> @@ -160,4 +159,17 @@ tools:listitem="@layout/item_previous_order" tools:visibility="visible" /> + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 25f996f..871bca0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -106,6 +106,7 @@ Open Source Licenses Account details item for + See more... item for From 36dae08fa7b2d0d2b3907cd9c31ac152a4914d95 Mon Sep 17 00:00:00 2001 From: MarkNjunge Date: Thu, 4 Jul 2019 20:48:09 +0300 Subject: [PATCH 10/20] Fix class visibility --- core/src/main/java/com/marknjunge/core/model/DatabaseKeys.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/marknjunge/core/model/DatabaseKeys.kt b/core/src/main/java/com/marknjunge/core/model/DatabaseKeys.kt index 8bd5f0e..b783d9d 100644 --- a/core/src/main/java/com/marknjunge/core/model/DatabaseKeys.kt +++ b/core/src/main/java/com/marknjunge/core/model/DatabaseKeys.kt @@ -6,7 +6,7 @@ package com.marknjunge.core.model * https://github.com/MarkNjunge */ -object DatabaseKeys { +internal object DatabaseKeys { object User { const val userId = "id" const val name = "name" From 7bc4c02f13ad46d80c065f069fc916d3be28bc07 Mon Sep 17 00:00:00 2001 From: MarkNjunge Date: Thu, 4 Jul 2019 23:08:24 +0300 Subject: [PATCH 11/20] Fix recent orders in profile screen --- .../java/com/marknkamau/justjava/ui/profile/ProfilePresenter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfilePresenter.kt b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfilePresenter.kt index f545e62..86b70df 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfilePresenter.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfilePresenter.kt @@ -32,7 +32,7 @@ internal class ProfilePresenter(private val view: ProfileView, if (previousOrders.isEmpty()) { view.displayNoPreviousOrders() } else { - val sorted = previousOrders.take(3).sortedBy { it.date }.reversed().toMutableList() + val sorted = previousOrders.sortedBy { it.date }.reversed().take(3).toMutableList() view.displayPreviousOrders(sorted) } } catch (e: Exception) { From e08645ea0fc191b2bbe700947b0c7c73d14ae92d Mon Sep 17 00:00:00 2001 From: MarkNjunge Date: Thu, 4 Jul 2019 23:17:43 +0300 Subject: [PATCH 12/20] Update order screen --- app/src/main/AndroidManifest.xml | 3 +- .../com/marknkamau/justjava/di/Modules.kt | 6 +- .../justjava/ui/cart/CartActivity.kt | 24 +- .../ui/previousOrder/OrderItemsAdapter.kt | 47 ---- .../previousOrders/PreviousOrdersActivity.kt | 4 +- .../justjava/ui/profile/ProfileActivity.kt | 4 +- .../ViewOrderActivity.kt} | 77 ++++-- .../ViewOrderPresenter.kt} | 12 +- .../ViewOrderView.kt} | 4 +- .../res/layout/activity_previous_order.xml | 118 --------- .../main/res/layout/activity_view_order.xml | 242 ++++++++++++++++++ .../main/res/layout/include_order_details.xml | 120 --------- app/src/main/res/layout/item_cart.xml | 67 ----- app/src/main/res/layout/item_order_item.xml | 91 ++++--- app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 5 + 16 files changed, 370 insertions(+), 455 deletions(-) delete mode 100644 app/src/main/java/com/marknkamau/justjava/ui/previousOrder/OrderItemsAdapter.kt rename app/src/main/java/com/marknkamau/justjava/ui/{previousOrder/PreviousOrderActivity.kt => viewOrder/ViewOrderActivity.kt} (58%) rename app/src/main/java/com/marknkamau/justjava/ui/{previousOrder/PreviousOrderPresenter.kt => viewOrder/ViewOrderPresenter.kt} (81%) rename app/src/main/java/com/marknkamau/justjava/ui/{previousOrder/PreviousOrderView.kt => viewOrder/ViewOrderView.kt} (77%) delete mode 100644 app/src/main/res/layout/activity_previous_order.xml create mode 100644 app/src/main/res/layout/activity_view_order.xml delete mode 100644 app/src/main/res/layout/include_order_details.xml delete mode 100644 app/src/main/res/layout/item_cart.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6b626ce..ae26265 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -58,7 +58,8 @@ android:name=".ui.previousOrders.PreviousOrdersActivity" android:screenOrientation="portrait" android:parentActivityName=".ui.profile.ProfileActivity"/> - + diff --git a/app/src/main/java/com/marknkamau/justjava/di/Modules.kt b/app/src/main/java/com/marknkamau/justjava/di/Modules.kt index bd64acd..24161c5 100644 --- a/app/src/main/java/com/marknkamau/justjava/di/Modules.kt +++ b/app/src/main/java/com/marknkamau/justjava/di/Modules.kt @@ -13,8 +13,8 @@ import com.marknkamau.justjava.ui.login.LogInPresenter import com.marknkamau.justjava.ui.login.LogInView import com.marknkamau.justjava.ui.main.MainPresenter import com.marknkamau.justjava.ui.main.MainView -import com.marknkamau.justjava.ui.previousOrder.PreviousOrderPresenter -import com.marknkamau.justjava.ui.previousOrder.PreviousOrderView +import com.marknkamau.justjava.ui.viewOrder.ViewOrderPresenter +import com.marknkamau.justjava.ui.viewOrder.ViewOrderView import com.marknkamau.justjava.ui.previousOrders.PreviousOrdersPresenter import com.marknkamau.justjava.ui.previousOrders.PreviousOrdersView import com.marknkamau.justjava.ui.profile.ProfilePresenter @@ -36,7 +36,7 @@ val appModule = module { factory { (view: MainView) -> MainPresenter(view, Dispatchers.Main) } factory { (view: DrinkDetailsView) -> DrinkDetailsPresenter(view, get(), Dispatchers.Main) } factory { (view: CartView) -> CartPresenter(view, get(), get(), get(), get(), Dispatchers.Main) } - factory { (view: PreviousOrderView) -> PreviousOrderPresenter(view, get(), get(), get(), Dispatchers.Main) } + factory { (view: ViewOrderView) -> ViewOrderPresenter(view, get(), get(), get(), Dispatchers.Main) } factory { (view: ProfileView) -> ProfilePresenter(view, get(), get(), get(), get(), Dispatchers.Main) } factory { (view: PreviousOrdersView) -> PreviousOrdersPresenter(view, get(), get(), Dispatchers.Main) } } \ No newline at end of file diff --git a/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt index e2a4afe..716364a 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/cart/CartActivity.kt @@ -17,15 +17,15 @@ import com.marknkamau.justjava.data.models.CartItem import com.marknkamau.justjava.ui.BaseActivity import com.marknkamau.justjava.ui.login.LogInActivity import com.marknkamau.justjava.ui.main.MainActivity -import com.marknkamau.justjava.ui.previousOrder.PreviousOrderActivity import com.marknkamau.justjava.ui.signup.SignUpActivity +import com.marknkamau.justjava.ui.viewOrder.ViewOrderActivity import com.marknkamau.justjava.utils.BaseRecyclerViewAdapter import com.marknkamau.justjava.utils.DividerItemDecorator import com.marknkamau.justjava.utils.onTextChanged import com.marknkamau.justjava.utils.trimmedText import kotlinx.android.synthetic.main.activity_cart.* import kotlinx.android.synthetic.main.content_toolbar.* -import kotlinx.android.synthetic.main.item_cart.view.* +import kotlinx.android.synthetic.main.item_order_item.view.* import org.koin.android.ext.android.inject import org.koin.core.parameter.parametersOf @@ -55,10 +55,10 @@ class CartActivity : BaseActivity(), CartView { } } - adapter = BaseRecyclerViewAdapter(R.layout.item_cart) { cartItem -> - tvItemNameCart.text = cartItem.itemName - tvItemQtyCart.text = "${cartItem.itemQty}x" - tvItemPriceCart.text = context.getString(R.string.price_listing, cartItem.itemPrice) + adapter = BaseRecyclerViewAdapter(R.layout.item_order_item) { cartItem -> + tvItemNameItem.text = cartItem.itemName + tvItemQtyItem.text = "${cartItem.itemQty}x" + tvItemPriceItem.text = context.getString(R.string.price_listing, cartItem.itemPrice) val toppings = mutableListOf() @@ -67,12 +67,12 @@ class CartActivity : BaseActivity(), CartView { if (cartItem.itemMarshmallow) toppings.add("Marshmallows") if (toppings.isNotEmpty()) { - tvToppingsCart.visibility = View.VISIBLE - tvToppingsCart.text = toppings.joinToString(", ") + tvToppingsItem.visibility = View.VISIBLE + tvToppingsItem.text = toppings.joinToString(", ") } else { - tvToppingsCart.visibility = View.GONE + tvToppingsItem.visibility = View.GONE } - cartItemRootLayout.setOnClickListener { + orderItemRootLayout.setOnClickListener { editCartDialog.arguments = Bundle().apply { putParcelable(EditCartDialog.CART_ITEM, cartItem) } @@ -177,8 +177,8 @@ class CartActivity : BaseActivity(), CartView { } override fun finishActivity(order: Order) { - val i = Intent(this, PreviousOrderActivity::class.java) - i.putExtra(PreviousOrderActivity.ORDER_KEY, order) + val i = Intent(this, ViewOrderActivity::class.java) + i.putExtra(ViewOrderActivity.ORDER_KEY, order) TaskStackBuilder.create(this) .addNextIntentWithParentStack(Intent(this, MainActivity::class.java)) diff --git a/app/src/main/java/com/marknkamau/justjava/ui/previousOrder/OrderItemsAdapter.kt b/app/src/main/java/com/marknkamau/justjava/ui/previousOrder/OrderItemsAdapter.kt deleted file mode 100644 index ed80c0b..0000000 --- a/app/src/main/java/com/marknkamau/justjava/ui/previousOrder/OrderItemsAdapter.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.marknkamau.justjava.ui.previousOrder - -/** - * Created by Mark Njung'e. - * mark.kamau@outlook.com - * https://github.com/MarkNjunge - */ - -import androidx.recyclerview.widget.RecyclerView -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.marknkamau.justjava.R -import com.marknjunge.core.model.OrderItem -import kotlinx.android.synthetic.main.item_order_item.view.* - -class OrderItemsAdapter : androidx.recyclerview.widget.RecyclerView.Adapter() { - private val items by lazy { mutableListOf() } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(parent.inflate(R.layout.item_order_item)) - - override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(items[position]) - - override fun getItemCount() = items.size - - fun setItems(items: List) { - this.items.clear() - this.items.addAll(items) - notifyDataSetChanged() - } - - class ViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) { - fun bind(item: OrderItem) { - itemView.run { - tvItemName.text = item.itemName - tvItemQuantity.text = "x ${item.itemQty}" - tvChocolate.visibility = if (item.itemChoc) View.VISIBLE else View.GONE - tvCinnamon.visibility = if (item.itemCinnamon) View.VISIBLE else View.GONE - tvMarshmallows.visibility = if (item.itemMarshmallow) View.VISIBLE else View.GONE - } - } - } - - private fun ViewGroup.inflate(layoutRes: Int): View { - return LayoutInflater.from(context).inflate(layoutRes, this, false) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersActivity.kt index 69c5741..f202b1d 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/previousOrders/PreviousOrdersActivity.kt @@ -8,7 +8,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.marknjunge.core.model.Order import com.marknkamau.justjava.R -import com.marknkamau.justjava.ui.previousOrder.PreviousOrderActivity +import com.marknkamau.justjava.ui.viewOrder.ViewOrderActivity import com.marknkamau.justjava.utils.BaseRecyclerViewAdapter import com.marknkamau.justjava.utils.DividerItemDecorator import com.marknkamau.justjava.utils.formatForApp @@ -38,7 +38,7 @@ class PreviousOrdersActivity : AppCompatActivity(), PreviousOrdersView { tvOrderTotalItem.text = resources.getString(R.string.price_listing, order.totalPrice) previousOrderItemRootLayout.setOnClickListener { - PreviousOrderActivity.start(this@PreviousOrdersActivity, order) + ViewOrderActivity.start(this@PreviousOrdersActivity, order) } } diff --git a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt index fa4a2dc..9664701 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/profile/ProfileActivity.kt @@ -10,7 +10,7 @@ import com.marknjunge.core.model.Order import com.marknjunge.core.model.UserDetails import com.marknkamau.justjava.R import com.marknkamau.justjava.ui.BaseActivity -import com.marknkamau.justjava.ui.previousOrder.PreviousOrderActivity +import com.marknkamau.justjava.ui.viewOrder.ViewOrderActivity import com.marknkamau.justjava.ui.previousOrders.PreviousOrdersActivity import com.marknkamau.justjava.utils.* import kotlinx.android.synthetic.main.activity_profile.* @@ -37,7 +37,7 @@ class ProfileActivity : BaseActivity(), ProfileView { tvOrderTotalItem.text = resources.getString(R.string.price_listing, order.totalPrice) previousOrderItemRootLayout.setOnClickListener { - PreviousOrderActivity.start(this@ProfileActivity, order) + ViewOrderActivity.start(this@ProfileActivity, order) } } diff --git a/app/src/main/java/com/marknkamau/justjava/ui/previousOrder/PreviousOrderActivity.kt b/app/src/main/java/com/marknkamau/justjava/ui/viewOrder/ViewOrderActivity.kt similarity index 58% rename from app/src/main/java/com/marknkamau/justjava/ui/previousOrder/PreviousOrderActivity.kt rename to app/src/main/java/com/marknkamau/justjava/ui/viewOrder/ViewOrderActivity.kt index 8a459fb..9a27e3f 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/previousOrder/PreviousOrderActivity.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/viewOrder/ViewOrderActivity.kt @@ -1,4 +1,4 @@ -package com.marknkamau.justjava.ui.previousOrder +package com.marknkamau.justjava.ui.viewOrder import android.content.BroadcastReceiver import android.content.Context @@ -11,53 +11,75 @@ import androidx.appcompat.app.AlertDialog import android.view.View import android.widget.LinearLayout import android.widget.Toast +import androidx.recyclerview.widget.RecyclerView import com.marknkamau.justjava.R import com.marknkamau.justjava.data.local.PreferencesRepository import com.marknjunge.core.model.Order import com.marknjunge.core.model.OrderItem import com.marknkamau.justjava.data.network.MyFirebaseMessagingService +import com.marknkamau.justjava.utils.BaseRecyclerViewAdapter import com.marknkamau.justjava.utils.formatForApp -import kotlinx.android.synthetic.main.activity_previous_order.* -import kotlinx.android.synthetic.main.include_order_details.* +import kotlinx.android.synthetic.main.activity_view_order.* +import kotlinx.android.synthetic.main.content_toolbar.* +import kotlinx.android.synthetic.main.item_order_item.view.* import org.koin.android.ext.android.inject import org.koin.core.parameter.parametersOf import timber.log.Timber -class PreviousOrderActivity : AppCompatActivity(), PreviousOrderView { +class ViewOrderActivity : AppCompatActivity(), ViewOrderView { companion object { const val ORDER_KEY = "order_key" fun start(context: Context, order: Order) { - val i = Intent(context, PreviousOrderActivity::class.java) + val i = Intent(context, ViewOrderActivity::class.java) i.putExtra(ORDER_KEY, order) context.startActivity(i) } } - private lateinit var orderItemsAdapter: OrderItemsAdapter + private lateinit var orderItemsAdapter: BaseRecyclerViewAdapter private lateinit var broadcastReceiver: BroadcastReceiver private lateinit var order: Order private val preferencesRepository: PreferencesRepository by inject() private val broadcastManager by lazy { LocalBroadcastManager.getInstance(this) } - private val presenter: PreviousOrderPresenter by inject { parametersOf(this) } + private val presenter: ViewOrderPresenter by inject { parametersOf(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_previous_order) + setContentView(R.layout.activity_view_order) + setSupportActionBar(toolbar) + supportActionBar?.title = "Order" + supportActionBar?.setDisplayHomeAsUpEnabled(true) order = intent.getParcelableExtra(ORDER_KEY) updateViews(order) - orderItemsAdapter = OrderItemsAdapter() - rvOrderItems.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this, LinearLayout.VERTICAL, false) - rvOrderItems.adapter = orderItemsAdapter + orderItemsAdapter = BaseRecyclerViewAdapter(R.layout.item_order_item){orderItem -> + tvItemNameItem.text = orderItem.itemName + tvItemQtyItem.text = "${orderItem.itemQty}x" + tvItemPriceItem.text = context.getString(R.string.price_listing, orderItem.itemPrice) + val toppings = mutableListOf() - presenter.getOrderItems(order.orderId) + if (orderItem.itemCinnamon) toppings.add("Cinnamon") + if (orderItem.itemChoc) toppings.add("Chocolate") + if (orderItem.itemMarshmallow) toppings.add("Marshmallows") + + if (toppings.isNotEmpty()) { + tvToppingsItem.visibility = View.VISIBLE + tvToppingsItem.text = toppings.joinToString(", ") + } else { + tvToppingsItem.visibility = View.GONE + } + } + + rvOrderItemsOrder.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this, RecyclerView.VERTICAL, false) + rvOrderItemsOrder.adapter = orderItemsAdapter + presenter.getOrderItems(order.orderId) } override fun onStart() { @@ -70,8 +92,8 @@ class PreviousOrderActivity : AppCompatActivity(), PreviousOrderView { Timber.d("Payment received for order $orderId") if (order.orderId == orderId) { Timber.d("The current order has been paid for!") - btnPay.visibility = View.GONE - tvPaymentStatus.text = "Paid" + btnPayOrder.visibility = View.GONE + tvPaymentStatusOrder .text = "Paid" displayMessage("Payment received!") } } @@ -93,7 +115,8 @@ class PreviousOrderActivity : AppCompatActivity(), PreviousOrderView { } override fun displayOrderItems(orderItems: List) { - cardOrderItems.visibility = View.VISIBLE + pbLoadingOrderItemsOrder.visibility = View.GONE + rvOrderItemsOrder.visibility = View.VISIBLE orderItemsAdapter.setItems(orderItems) } @@ -107,26 +130,26 @@ class PreviousOrderActivity : AppCompatActivity(), PreviousOrderView { } private fun updateViews(order: Order) { - tvOrderId.text = order.orderId - tvOrderStatus.text = order.status.name.toLowerCase().capitalize() - tvOrderDate.text = order.date.formatForApp() - tvDeliveryAddress.text = order.deliveryAddress - tvTotalPrice.text = getString(R.string.ksh, order.totalPrice) + tvOrderIdOrder.text = order.orderId + tvOrderStatusOrder.text = order.status.name.toLowerCase().capitalize() + tvOrderDateOrder.text = order.date.formatForApp() + tvOrderAddressOrder.text = order.deliveryAddress + tvOrderTotalOrder .text = getString(R.string.ksh, order.totalPrice) if (order.additionalComments.isEmpty()) { - tvComments.visibility = View.GONE - tvCommentsLabel.visibility = View.GONE + tvOrderCommentsOrder.visibility = View.GONE + tvCommentsLabelOrder.visibility = View.GONE } else { - tvComments.text = order.additionalComments + tvOrderCommentsOrder.text = order.additionalComments } - tvPaymentMethod.text = order.paymentMethod.capitalize() - tvPaymentStatus.text = order.paymentStatus.capitalize() + tvPaymentMethodOrder.text = order.paymentMethod.capitalize() + tvPaymentStatusOrder.text = order.paymentStatus.capitalize() if (order.paymentMethod != "mpesa" || order.paymentStatus == "paid") { - btnPay.visibility = View.GONE + btnPayOrder.visibility = View.GONE } - btnPay.setOnClickListener { + btnPayOrder.setOnClickListener { val phoneNumber = preferencesRepository.getUserDetails().phone val dialog = AlertDialog.Builder(this) .setMessage("Are you sure you want to pay Ksh. 1 using $phoneNumber?\nThe money will be automatically refunded by Safaricom the following day.") diff --git a/app/src/main/java/com/marknkamau/justjava/ui/previousOrder/PreviousOrderPresenter.kt b/app/src/main/java/com/marknkamau/justjava/ui/viewOrder/ViewOrderPresenter.kt similarity index 81% rename from app/src/main/java/com/marknkamau/justjava/ui/previousOrder/PreviousOrderPresenter.kt rename to app/src/main/java/com/marknkamau/justjava/ui/viewOrder/ViewOrderPresenter.kt index 3f8c7b0..d2d7455 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/previousOrder/PreviousOrderPresenter.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/viewOrder/ViewOrderPresenter.kt @@ -1,4 +1,4 @@ -package com.marknkamau.justjava.ui.previousOrder +package com.marknkamau.justjava.ui.viewOrder import com.google.firebase.iid.FirebaseInstanceId import com.marknjunge.core.mpesa.MpesaInteractor @@ -15,11 +15,11 @@ import timber.log.Timber * https://github.com/MarkNjunge */ -class PreviousOrderPresenter(private val view: PreviousOrderView, - private val orderService: OrderService, - private val mpesaInteractor: MpesaInteractor, - private val authService: AuthService, - mainDispatcher: CoroutineDispatcher +class ViewOrderPresenter(private val view: ViewOrderView, + private val orderService: OrderService, + private val mpesaInteractor: MpesaInteractor, + private val authService: AuthService, + mainDispatcher: CoroutineDispatcher ) : BasePresenter(mainDispatcher) { fun getOrderDetails(orderId: String) { diff --git a/app/src/main/java/com/marknkamau/justjava/ui/previousOrder/PreviousOrderView.kt b/app/src/main/java/com/marknkamau/justjava/ui/viewOrder/ViewOrderView.kt similarity index 77% rename from app/src/main/java/com/marknkamau/justjava/ui/previousOrder/PreviousOrderView.kt rename to app/src/main/java/com/marknkamau/justjava/ui/viewOrder/ViewOrderView.kt index de98fca..6b3fbe5 100644 --- a/app/src/main/java/com/marknkamau/justjava/ui/previousOrder/PreviousOrderView.kt +++ b/app/src/main/java/com/marknkamau/justjava/ui/viewOrder/ViewOrderView.kt @@ -1,4 +1,4 @@ -package com.marknkamau.justjava.ui.previousOrder +package com.marknkamau.justjava.ui.viewOrder import com.marknjunge.core.model.Order import com.marknjunge.core.model.OrderItem @@ -10,7 +10,7 @@ import com.marknkamau.justjava.ui.BaseView * https://github.com/MarkNjunge */ -interface PreviousOrderView : BaseView { +interface ViewOrderView : BaseView { fun displayOrder(order: Order) fun displayOrderItems(orderItems: List) } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_previous_order.xml b/app/src/main/res/layout/activity_previous_order.xml deleted file mode 100644 index cdcd667..0000000 --- a/app/src/main/res/layout/activity_previous_order.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_view_order.xml b/app/src/main/res/layout/activity_view_order.xml new file mode 100644 index 0000000..298eafd --- /dev/null +++ b/app/src/main/res/layout/activity_view_order.xml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/include_order_details.xml b/app/src/main/res/layout/include_order_details.xml deleted file mode 100644 index d11f5e3..0000000 --- a/app/src/main/res/layout/include_order_details.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/item_cart.xml b/app/src/main/res/layout/item_cart.xml deleted file mode 100644 index 86c44d0..0000000 --- a/app/src/main/res/layout/item_cart.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_order_item.xml b/app/src/main/res/layout/item_order_item.xml index a202a95..bf71317 100644 --- a/app/src/main/res/layout/item_order_item.xml +++ b/app/src/main/res/layout/item_order_item.xml @@ -2,71 +2,66 @@ + tools:text="2x" /> - - - + app:layout_constraintEnd_toStartOf="@+id/tvItemPriceItem" + app:layout_constraintStart_toEndOf="@+id/tvItemQtyItem" + app:layout_constraintTop_toTopOf="parent"> - + + + + + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.0" + tools:text="Ksh. 900" /> + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 871bca0..aa1c393 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -107,6 +107,7 @@ Account details item for See more... + Payment Details item for diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 35f829f..2b73bfe 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -68,6 +68,11 @@ bold + + - - - - - - - - - - - - @@ -129,19 +96,4 @@ #60FFFFFF #FFFFFF - - - - diff --git a/app/src/test/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsPresenterTest.kt b/app/src/test/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsPresenterTest.kt index 4e8131d..d326b9c 100644 --- a/app/src/test/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsPresenterTest.kt +++ b/app/src/test/java/com/marknkamau/justjava/ui/drinkdetails/DrinkDetailsPresenterTest.kt @@ -4,7 +4,6 @@ import com.marknkamau.justjava.data.local.CartDao import com.marknkamau.justjava.data.models.CartItem import io.mockk.MockKAnnotations import io.mockk.coEvery -import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.verify import kotlinx.coroutines.Dispatchers diff --git a/justjavastaff/src/main/res/layout/include_order_details.xml b/justjavastaff/src/main/res/layout/include_order_details.xml index 1f8aaf8..e575a5b 100644 --- a/justjavastaff/src/main/res/layout/include_order_details.xml +++ b/justjavastaff/src/main/res/layout/include_order_details.xml @@ -1,6 +1,5 @@ Date: Sat, 6 Jul 2019 12:43:41 +0300 Subject: [PATCH 20/20] Separate app for debug build --- app/build.gradle | 1 + app/src/debug/ic_launcher-web.png | Bin 0 -> 33012 bytes .../res/drawable/ic_launcher_foreground.xml | 15 +++++++++++++++ .../debug/res/mipmap-anydpi-v26/ic_launcher.xml | 5 +++++ app/src/debug/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3428 bytes app/src/debug/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2166 bytes app/src/debug/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4902 bytes app/src/debug/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7531 bytes .../debug/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10689 bytes .../debug/res/values/ic_launcher_background.xml | 4 ++++ app/src/debug/res/values/strings.xml | 4 ++++ 11 files changed, 29 insertions(+) create mode 100644 app/src/debug/ic_launcher-web.png create mode 100644 app/src/debug/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/debug/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/debug/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/debug/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/debug/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/debug/res/values/ic_launcher_background.xml create mode 100644 app/src/debug/res/values/strings.xml diff --git a/app/build.gradle b/app/build.gradle index 0682af4..2500688 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,6 +27,7 @@ android { debug { ext.alwaysUpdateBuildId = false ext.enableCrashlytics = false + applicationIdSuffix ".debug" } release { minifyEnabled true diff --git a/app/src/debug/ic_launcher-web.png b/app/src/debug/ic_launcher-web.png new file mode 100644 index 0000000000000000000000000000000000000000..430f1f6ff5c3a69302ddccc2e4314ff6ba332181 GIT binary patch literal 33012 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 + + + + + + diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..7353dbd --- /dev/null +++ b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/debug/res/mipmap-hdpi/ic_launcher.png b/app/src/debug/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..52cdaef815fd0d6110598b75dbf1dbb44483e381 GIT binary patch literal 3428 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 z zl$qC)jIQZ#SVD(B{{H@W!w}v=*Nhlj4UeESzQTl~Tw!qW$btG|>^|;%y_K#6u>`Ra zn#RP$OzqL5M>c99ft4kEHRN&BpO%)EEnLl}V&;dqTln|EQN@ZCtN8l*LJ46J5fOuv zlao&fyHFxm1J8PlAt@>8qzJOYFh-2kU9eNA5{LqcK|C3%aZpgu6LE2IUtrma)sW|* zZ_u-KGljlt)6>&63Od(Uu3Q1x%gb)i`{gP`d!Y=pGYquF>0XL1ntMGDsO9JFL z6gdMwv6LxfuP+qQ6p5So#v5!b9)vymM-bXb;T72yyJQL7p?YIMU4C3u)d?(C}0ojd=F;9`HbZr%Qynwol^gnF3*zH1_ygeJC-;)5$h0zn9Qv;D-hp-|@ zaFIy*0WRpg_GCjkL#VZC)k*{5JC2bsV{wi+H&S4FxM-^Z+D0D&-vdP7WlI~>IHL$J zfw|=c3i_@%07*qoM6N<$g7WTWg8%>k literal 0 HcmV?d00001 diff --git a/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png b/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..5b329523a43eb751c1057ffdcb898572984f8241 GIT binary patch literal 7531 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 RjX0VKP?A%Vt&=tn{U6 + + #5C5C5C + \ No newline at end of file diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml new file mode 100644 index 0000000..ebe4007 --- /dev/null +++ b/app/src/debug/res/values/strings.xml @@ -0,0 +1,4 @@ + + + [D] JustJava + \ No newline at end of file