From ff38a7154890fa040665142be9efc4b2c539f190 Mon Sep 17 00:00:00 2001 From: varun jain Date: Sun, 8 Aug 2021 01:37:41 +0530 Subject: [PATCH 1/5] Product details page implemented --- app/src/main/AndroidManifest.xml | 2 + .../fineract/data/models/loan/TermRange.kt | 6 +- .../data/models/product/BalanceRange.kt | 5 +- .../data/models/product/InterestBasis.kt | 2 + .../data/models/product/InterestRange.kt | 5 +- .../fineract/data/models/product/Product.kt | 6 +- .../component/ActivityComponent.java | 6 + .../ProductAccountAssignmentsAdapter.kt | 77 ++++ .../fineract/ui/adapters/ProductAdapter.kt | 20 +- .../fineract/ui/product/ProductFragment.kt | 20 +- .../productdetails/ProductDetailsActivity.kt | 21 + .../productdetails/productdetailsfragment.kt | 105 +++++ .../org/apache/fineract/utils/Constants.kt | 3 +- .../res/layout/account_assignments_item.xml | 74 ++++ .../res/layout/fragment_product_details.xml | 376 ++++++++++++++++++ .../main/res/menu/menu_product_details.xml | 10 + app/src/main/res/values/strings.xml | 14 + 17 files changed, 743 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/org/apache/fineract/ui/adapters/ProductAccountAssignmentsAdapter.kt create mode 100644 app/src/main/java/org/apache/fineract/ui/product/productdetails/ProductDetailsActivity.kt create mode 100644 app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt create mode 100644 app/src/main/res/layout/account_assignments_item.xml create mode 100644 app/src/main/res/layout/fragment_product_details.xml create mode 100644 app/src/main/res/menu/menu_product_details.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bad499ef..1155a43b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -94,6 +94,8 @@ android:name=".ui.online.groups.creategroup.CreateGroupActivity" android:windowSoftInputMode="adjustResize|stateHidden" /> + + diff --git a/app/src/main/java/org/apache/fineract/data/models/loan/TermRange.kt b/app/src/main/java/org/apache/fineract/data/models/loan/TermRange.kt index 5a472c27..ea24ca6e 100644 --- a/app/src/main/java/org/apache/fineract/data/models/loan/TermRange.kt +++ b/app/src/main/java/org/apache/fineract/data/models/loan/TermRange.kt @@ -1,12 +1,16 @@ package org.apache.fineract.data.models.loan +import android.os.Parcelable import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize /** * @author Rajan Maurya * On 12/07/17. */ + +@Parcelize data class TermRange( @SerializedName("temporalUnit") var temporalUnit: String?, @SerializedName("maximum") var maximum: Double? -) +) : Parcelable diff --git a/app/src/main/java/org/apache/fineract/data/models/product/BalanceRange.kt b/app/src/main/java/org/apache/fineract/data/models/product/BalanceRange.kt index 80c90149..c37953da 100644 --- a/app/src/main/java/org/apache/fineract/data/models/product/BalanceRange.kt +++ b/app/src/main/java/org/apache/fineract/data/models/product/BalanceRange.kt @@ -1,13 +1,16 @@ package org.apache.fineract.data.models.product +import android.os.Parcelable import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize /** * @author Rajan Maurya * On 20/07/17. */ +@Parcelize data class BalanceRange ( @SerializedName("minimum") var minimum: Double? = null, @SerializedName("maximum") var maximum: Double? = null -) +) : Parcelable diff --git a/app/src/main/java/org/apache/fineract/data/models/product/InterestBasis.kt b/app/src/main/java/org/apache/fineract/data/models/product/InterestBasis.kt index a3f39b4b..7781c526 100644 --- a/app/src/main/java/org/apache/fineract/data/models/product/InterestBasis.kt +++ b/app/src/main/java/org/apache/fineract/data/models/product/InterestBasis.kt @@ -1,5 +1,7 @@ package org.apache.fineract.data.models.product +import kotlinx.android.parcel.Parcelize + /** * @author Rajan Maurya * On 20/07/17. diff --git a/app/src/main/java/org/apache/fineract/data/models/product/InterestRange.kt b/app/src/main/java/org/apache/fineract/data/models/product/InterestRange.kt index f5882f18..7b5ad8e7 100644 --- a/app/src/main/java/org/apache/fineract/data/models/product/InterestRange.kt +++ b/app/src/main/java/org/apache/fineract/data/models/product/InterestRange.kt @@ -1,13 +1,16 @@ package org.apache.fineract.data.models.product +import android.os.Parcelable import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize /** * @author Rajan Maurya * On 20/07/17. */ +@Parcelize data class InterestRange ( @SerializedName("minimum") var minimum: Double? = null, @SerializedName("maximum") var maximum: Double? = null -) +) : Parcelable diff --git a/app/src/main/java/org/apache/fineract/data/models/product/Product.kt b/app/src/main/java/org/apache/fineract/data/models/product/Product.kt index c1e6431c..ba9c826f 100644 --- a/app/src/main/java/org/apache/fineract/data/models/product/Product.kt +++ b/app/src/main/java/org/apache/fineract/data/models/product/Product.kt @@ -1,6 +1,9 @@ package org.apache.fineract.data.models.product +import android.os.Parcelable import com.google.gson.annotations.SerializedName +import kotlinx.android.parcel.Parcelize +import kotlinx.android.parcel.RawValue import org.apache.fineract.data.models.loan.AccountAssignment import org.apache.fineract.data.models.loan.TermRange import java.util.ArrayList @@ -10,6 +13,7 @@ import java.util.ArrayList * On 20/07/17. */ +@Parcelize data class Product ( @SerializedName("identifier") val identifier: String? = null, @SerializedName("name") val name: String? = null, @@ -28,4 +32,4 @@ data class Product ( @SerializedName("createdBy") val createdBy: String? = null, @SerializedName("lastModifiedOn") val lastModifiedOn: String? = null, @SerializedName("lastModifiedBy") val lastModifiedBy: String? = null -) +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java b/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java index 7e8d2ec0..47eb88e2 100644 --- a/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java +++ b/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java @@ -60,6 +60,8 @@ import org.apache.fineract.ui.online.roles.roleslist.RolesFragment; import org.apache.fineract.ui.online.teller.TellerFragment; import org.apache.fineract.ui.product.ProductFragment; +import org.apache.fineract.ui.product.productdetails.ProductDetailsActivity; +import org.apache.fineract.ui.product.productdetails.ProductDetailsFragment; import dagger.Subcomponent; @@ -159,5 +161,9 @@ public interface ActivityComponent { void inject(GroupDetailsFragment groupDetailsFragment); void inject(GroupTasksBottomSheetFragment groupTasksBottomSheetFragment); + + void inject(ProductDetailsActivity productDetailsActivity); + + void inject(ProductDetailsFragment productDetailsFragment); } diff --git a/app/src/main/java/org/apache/fineract/ui/adapters/ProductAccountAssignmentsAdapter.kt b/app/src/main/java/org/apache/fineract/ui/adapters/ProductAccountAssignmentsAdapter.kt new file mode 100644 index 00000000..8819a88c --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/adapters/ProductAccountAssignmentsAdapter.kt @@ -0,0 +1,77 @@ +package org.apache.fineract.ui.adapters + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.account_assignments_item.view.* +import org.apache.fineract.R +import org.apache.fineract.data.models.loan.AccountAssignment +import javax.inject.Inject + +class ProductAccountAssignmentsAdapter @Inject constructor() : + RecyclerView.Adapter() { + + private var accountAssignmentsList = ArrayList() + private var onItemClickListener: OnItemClickListener? = null + private var isReview = false + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder.from(parent) + } + + override fun getItemCount(): Int = accountAssignmentsList.size + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(accountAssignmentsList[position], onItemClickListener, isReview) + } + + fun setOnItemClickListener(onItemClickListener: OnItemClickListener?) { + this.onItemClickListener = onItemClickListener + } + + fun submitList(list: ArrayList) { + accountAssignmentsList = list + notifyDataSetChanged() + } + + fun setReview(isReview: Boolean) { + this.isReview = isReview + } + + class ViewHolder private constructor(itemView: View) : RecyclerView.ViewHolder(itemView) { + + fun bind(accountAssignment: AccountAssignment, onItemClickListener: OnItemClickListener?, isReview: Boolean) { + if (isReview) { + itemView.ivEditProductAccountAss.visibility = View.GONE + itemView.ivDeleteProductAccountAss.visibility = View.GONE + } else { + itemView.ivEditProductAccountAss.visibility = View.VISIBLE + itemView.ivDeleteProductAccountAss.visibility = View.VISIBLE + } + itemView.tvDesignator.text = accountAssignment.designator + itemView.tvAccountIdentifier.text = accountAssignment.accountIdentifier + itemView.tvLedgerIdentifier.text = accountAssignment.ledgerIdentifier + itemView.ivDeleteProductAccountAss.setOnClickListener { + onItemClickListener?.onDeleteClicked(adapterPosition) + } + itemView.ivEditProductAccountAss.setOnClickListener { + onItemClickListener?.onEditClicked(adapterPosition) + } + } + + companion object { + fun from(parent: ViewGroup): ViewHolder { + return ViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.account_assignments_item, parent, false) + ) + } + } + } + + interface OnItemClickListener { + fun onEditClicked(position: Int) + fun onDeleteClicked(position: Int) + } +} diff --git a/app/src/main/java/org/apache/fineract/ui/adapters/ProductAdapter.kt b/app/src/main/java/org/apache/fineract/ui/adapters/ProductAdapter.kt index 7f06886f..701c2072 100644 --- a/app/src/main/java/org/apache/fineract/ui/adapters/ProductAdapter.kt +++ b/app/src/main/java/org/apache/fineract/ui/adapters/ProductAdapter.kt @@ -5,11 +5,13 @@ import androidx.recyclerview.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.LinearLayout import android.widget.TextView import kotlinx.android.synthetic.main.item_product.view.* import org.apache.fineract.R import org.apache.fineract.data.models.product.Product import org.apache.fineract.injection.ApplicationContext +import org.apache.fineract.ui.base.OnItemClickListener import org.apache.fineract.utils.DateUtils import javax.inject.Inject @@ -17,6 +19,7 @@ class ProductAdapter @Inject constructor(@ApplicationContext val context: Contex : RecyclerView.Adapter() { private var products: List = ArrayList() + lateinit var onItemClickListener: OnItemClickListener override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { @@ -50,11 +53,26 @@ class ProductAdapter @Inject constructor(@ApplicationContext val context: Contex notifyDataSetChanged() } - class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + fun setItemClickListener(onItemClickListener: OnItemClickListener) { + this.onItemClickListener = onItemClickListener + } + + inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener { val tvProductIdentifier: TextView = itemView.tv_product_identifier val tvModifiedBy: TextView = itemView.tv_modified_by val tvModifiedOn: TextView = itemView.tv_modified_on val tvName: TextView = itemView.tv_name + val llProduct: LinearLayout = itemView.ll_product + + init { + llProduct.setOnClickListener(this) + } + + override fun onClick(p0: View?) { + if (onItemClickListener != null) { + onItemClickListener.onItemClick(p0, adapterPosition) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/product/ProductFragment.kt b/app/src/main/java/org/apache/fineract/ui/product/ProductFragment.kt index aa46396c..0504933e 100644 --- a/app/src/main/java/org/apache/fineract/ui/product/ProductFragment.kt +++ b/app/src/main/java/org/apache/fineract/ui/product/ProductFragment.kt @@ -2,6 +2,7 @@ package org.apache.fineract.ui.product import android.app.SearchManager import android.content.Context +import android.content.Intent import android.os.Bundle import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.recyclerview.widget.LinearLayoutManager @@ -16,12 +17,17 @@ import org.apache.fineract.data.models.product.Product import org.apache.fineract.ui.adapters.ProductAdapter import org.apache.fineract.ui.base.FineractBaseActivity import org.apache.fineract.ui.base.FineractBaseFragment +import org.apache.fineract.ui.base.OnItemClickListener +import org.apache.fineract.ui.online.groups.groupdetails.GroupDetailsActivity +import org.apache.fineract.ui.product.productdetails.ProductDetailsActivity +import org.apache.fineract.ui.product.productdetails.ProductDetailsFragment +import org.apache.fineract.utils.Constants import java.util.* import javax.inject.Inject class ProductFragment : FineractBaseFragment(), ProductContract.View, - SwipeRefreshLayout.OnRefreshListener { + SwipeRefreshLayout.OnRefreshListener, OnItemClickListener { @Inject lateinit var productPresenter: ProductPresenter @@ -58,7 +64,7 @@ class ProductFragment : FineractBaseFragment(), ProductContract.View, super.onViewCreated(view, savedInstanceState) showUserInterface() - + productAdapter.setItemClickListener(this) btn_try_again.setOnClickListener { layoutError.visibility = View.GONE productPresenter.getProductsPage() @@ -124,7 +130,6 @@ class ProductFragment : FineractBaseFragment(), ProductContract.View, return false } }) - } override fun showEmptyProduct() { @@ -171,4 +176,13 @@ class ProductFragment : FineractBaseFragment(), ProductContract.View, productPresenter.detachView() } + override fun onItemClick(childView: View?, position: Int) { + val intent = Intent(context, ProductDetailsActivity::class.java).apply { + putExtra(Constants.PRODUCT, productList[position]) + } + startActivity(intent) + + } + + override fun onItemLongPress(childView: View?, position: Int) {} } diff --git a/app/src/main/java/org/apache/fineract/ui/product/productdetails/ProductDetailsActivity.kt b/app/src/main/java/org/apache/fineract/ui/product/productdetails/ProductDetailsActivity.kt new file mode 100644 index 00000000..c52988b8 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/product/productdetails/ProductDetailsActivity.kt @@ -0,0 +1,21 @@ +package org.apache.fineract.ui.product.productdetails + +import android.os.Bundle +import org.apache.fineract.R +import org.apache.fineract.ui.base.FineractBaseActivity +import org.apache.fineract.utils.Constants + +/* + * Created by Varun Jain on 07th August 2021 + */ + +class ProductDetailsActivity : FineractBaseActivity(){ + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_toolbar_container) + + replaceFragment(ProductDetailsFragment.newInstance(intent.getParcelableExtra(Constants.PRODUCT)), false, R.id.container) + showBackButton() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt b/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt new file mode 100644 index 00000000..756d0033 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt @@ -0,0 +1,105 @@ +package org.apache.fineract.ui.product.productdetails + +import android.content.Intent +import android.os.Bundle +import android.view.* +import android.widget.Toast +import butterknife.ButterKnife +import kotlinx.android.synthetic.main.fragment_product_details.* +import kotlinx.android.synthetic.main.fragment_product_details.view.* +import org.apache.fineract.R +import org.apache.fineract.data.models.loan.AccountAssignment +import org.apache.fineract.data.models.product.Product +import org.apache.fineract.ui.adapters.ProductAccountAssignmentsAdapter +import org.apache.fineract.ui.base.FineractBaseActivity +import org.apache.fineract.ui.base.FineractBaseFragment +import org.apache.fineract.ui.base.Toaster +import org.apache.fineract.ui.online.groups.GroupAction +import org.apache.fineract.ui.online.groups.creategroup.CreateGroupActivity +import org.apache.fineract.utils.Constants +import org.apache.fineract.utils.Utils +import javax.inject.Inject + +/* + * Created by Varun Jain on 07th August 2021 + */ + +class ProductDetailsFragment : FineractBaseFragment() { + + lateinit var rootView: View + lateinit var product: Product + + @Inject + lateinit var productAccountAssignmentsAdapter: ProductAccountAssignmentsAdapter + + companion object { + fun newInstance(product: Product): ProductDetailsFragment { + val fragment = ProductDetailsFragment() + val args = Bundle() + args.putParcelable(Constants.PRODUCT, product) + fragment.arguments = args + return fragment + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + product = arguments?.get(Constants.PRODUCT) as Product + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + rootView = inflater.inflate(R.layout.fragment_product_details, container, false) + (activity as FineractBaseActivity).activityComponent.inject(this) + ButterKnife.bind(this, rootView) + rootView.rvProductAccountAssignments.adapter = productAccountAssignmentsAdapter + productAccountAssignmentsAdapter.setReview(true) + setToolbarTitle(product.identifier) + setHasOptionsMenu(true) + return rootView + } + + override fun onPrepareOptionsMenu(menu: Menu) { + super.onPrepareOptionsMenu(menu) + Utils.setToolbarIconColor(context, menu, R.color.white) + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + super.onCreateOptionsMenu(menu, inflater) + inflater.inflate(R.menu.menu_product_details, menu) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_edit_group -> { + Toaster.show(rootView, "Under Construction", Toast.LENGTH_SHORT) + } + } + return super.onOptionsItemSelected(item) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + tvIdentifierProduct.text = product.identifier + tvNameProduct.text = product.name + tvPatternPackageProduct.text = product.patternPackage + tvProductTemporalUnit.text = product.termRange?.temporalUnit + tvMaximumTermRange.text = product.termRange?.maximum.toString() + tvMinProductBalanceRange.text = product.balanceRange?.minimum.toString() + tvMaxProductBalanceRange.text = product.balanceRange?.maximum.toString() + tvMaximumTermRange.text = product.balanceRange?.maximum.toString() + tvMaxInterestRange.text = product.interestRange?.maximum.toString() + tvMinInterestRange.text = product.interestRange?.minimum.toString() + tvProductDescription.text = product.description + tvInterestBasis.text = product.interestBasis.toString() + tvProductCurrencyCode.text = product.currencyCode.toString() + tvProductMinorCurrencyUnit.text = product.minorCurrencyUnitDigits.toString() + tvProductParams.text = product.parameters.toString() + product.accountAssignments?.let { + productAccountAssignmentsAdapter.submitList(it as ArrayList) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/utils/Constants.kt b/app/src/main/java/org/apache/fineract/utils/Constants.kt index 072c90f3..63db68aa 100644 --- a/app/src/main/java/org/apache/fineract/utils/Constants.kt +++ b/app/src/main/java/org/apache/fineract/utils/Constants.kt @@ -5,11 +5,12 @@ package org.apache.fineract.utils * Created by saksham on 23/June/2019 */ -object Constants { +object Constants { const val GROUP = "group" const val GROUP_ACTION = "group_action" const val DATABASE_NAME = "fineract-cn-mobile" const val BASIC_AUTH_KEY = "basic_auth_key" const val GATEWAY_USER_NAME = "fineract-cn" const val GATEWAY_PASSWORD = "password" + const val PRODUCT = "product" } \ No newline at end of file diff --git a/app/src/main/res/layout/account_assignments_item.xml b/app/src/main/res/layout/account_assignments_item.xml new file mode 100644 index 00000000..3ce03d07 --- /dev/null +++ b/app/src/main/res/layout/account_assignments_item.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_product_details.xml b/app/src/main/res/layout/fragment_product_details.xml new file mode 100644 index 00000000..e41aee16 --- /dev/null +++ b/app/src/main/res/layout/fragment_product_details.xml @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_product_details.xml b/app/src/main/res/menu/menu_product_details.xml new file mode 100644 index 00000000..79d33109 --- /dev/null +++ b/app/src/main/res/menu/menu_product_details.xml @@ -0,0 +1,10 @@ + + + + + \ 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 b25c3ac7..9046a576 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -544,4 +544,18 @@ "Updating group status, please wait... " Error while updating group status Error while creating group + Designator + Ledger Identifier + Pattern package + Term Range + Temporal Unit + Maximum + Balance Range + Minimum + Interest Range + Account Assignments + Currency Code + Minor Currency Unit Digits + Parameters + Interest Basis From ebbf194d651cdb9b929f3dfdc01c42658146aa8d Mon Sep 17 00:00:00 2001 From: varun jain Date: Fri, 13 Aug 2021 11:31:15 +0530 Subject: [PATCH 2/5] Migration to MVVM --- .../component/ActivityComponent.java | 2 +- .../fineract/ui/online/DashboardActivity.java | 2 +- .../productdetails/productdetailsfragment.kt | 6 +- .../{ => productlist}/ProductFragment.kt | 133 ++++++------------ .../ui/product/viewmodel/ProductViewModel.kt | 101 +++++++++++++ .../viewmodel/ProductViewModelFactory.kt | 29 ++++ 6 files changed, 177 insertions(+), 96 deletions(-) rename app/src/main/java/org/apache/fineract/ui/product/{ => productlist}/ProductFragment.kt (51%) create mode 100644 app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModel.kt create mode 100644 app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModelFactory.kt diff --git a/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java b/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java index 47eb88e2..30edc627 100644 --- a/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java +++ b/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java @@ -59,7 +59,7 @@ import org.apache.fineract.ui.online.review.AddLoanReviewFragment; import org.apache.fineract.ui.online.roles.roleslist.RolesFragment; import org.apache.fineract.ui.online.teller.TellerFragment; -import org.apache.fineract.ui.product.ProductFragment; +import org.apache.fineract.ui.product.productlist.ProductFragment; import org.apache.fineract.ui.product.productdetails.ProductDetailsActivity; import org.apache.fineract.ui.product.productdetails.ProductDetailsFragment; diff --git a/app/src/main/java/org/apache/fineract/ui/online/DashboardActivity.java b/app/src/main/java/org/apache/fineract/ui/online/DashboardActivity.java index 7f0460d9..a4090646 100644 --- a/app/src/main/java/org/apache/fineract/ui/online/DashboardActivity.java +++ b/app/src/main/java/org/apache/fineract/ui/online/DashboardActivity.java @@ -32,7 +32,7 @@ import org.apache.fineract.ui.online.launcher.LauncherActivity; import org.apache.fineract.ui.online.roles.roleslist.RolesFragment; import org.apache.fineract.ui.online.teller.TellerFragment; -import org.apache.fineract.ui.product.ProductFragment; +import org.apache.fineract.ui.product.productlist.ProductFragment; import org.apache.fineract.utils.MaterialDialog; import javax.inject.Inject; diff --git a/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt b/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt index 756d0033..7bde5637 100644 --- a/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt +++ b/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt @@ -14,8 +14,6 @@ import org.apache.fineract.ui.adapters.ProductAccountAssignmentsAdapter import org.apache.fineract.ui.base.FineractBaseActivity import org.apache.fineract.ui.base.FineractBaseFragment import org.apache.fineract.ui.base.Toaster -import org.apache.fineract.ui.online.groups.GroupAction -import org.apache.fineract.ui.online.groups.creategroup.CreateGroupActivity import org.apache.fineract.utils.Constants import org.apache.fineract.utils.Utils import javax.inject.Inject @@ -74,8 +72,8 @@ class ProductDetailsFragment : FineractBaseFragment() { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.menu_edit_group -> { - Toaster.show(rootView, "Under Construction", Toast.LENGTH_SHORT) + R.id.menu_product_details -> { + Toaster.show(rootView, getString(R.string.Under_construction), Toast.LENGTH_SHORT) } } return super.onOptionsItemSelected(item) diff --git a/app/src/main/java/org/apache/fineract/ui/product/ProductFragment.kt b/app/src/main/java/org/apache/fineract/ui/product/productlist/ProductFragment.kt similarity index 51% rename from app/src/main/java/org/apache/fineract/ui/product/ProductFragment.kt rename to app/src/main/java/org/apache/fineract/ui/product/productlist/ProductFragment.kt index 0504933e..a3a990fb 100644 --- a/app/src/main/java/org/apache/fineract/ui/product/ProductFragment.kt +++ b/app/src/main/java/org/apache/fineract/ui/product/productlist/ProductFragment.kt @@ -1,4 +1,4 @@ -package org.apache.fineract.ui.product +package org.apache.fineract.ui.product.productlist import android.app.SearchManager import android.content.Context @@ -9,7 +9,8 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.appcompat.widget.SearchView import android.text.TextUtils import android.view.* -import androidx.recyclerview.widget.RecyclerView +import androidx.lifecycle.ViewModelProviders +import butterknife.ButterKnife import kotlinx.android.synthetic.main.fragment_product.* import kotlinx.android.synthetic.main.layout_exception_handler.* import org.apache.fineract.R @@ -18,24 +19,28 @@ import org.apache.fineract.ui.adapters.ProductAdapter import org.apache.fineract.ui.base.FineractBaseActivity import org.apache.fineract.ui.base.FineractBaseFragment import org.apache.fineract.ui.base.OnItemClickListener -import org.apache.fineract.ui.online.groups.groupdetails.GroupDetailsActivity import org.apache.fineract.ui.product.productdetails.ProductDetailsActivity -import org.apache.fineract.ui.product.productdetails.ProductDetailsFragment +import org.apache.fineract.ui.product.viewmodel.ProductViewModel +import org.apache.fineract.ui.product.viewmodel.ProductViewModelFactory import org.apache.fineract.utils.Constants -import java.util.* import javax.inject.Inject +import kotlin.collections.ArrayList +import androidx.lifecycle.Observer +class ProductFragment : FineractBaseFragment(), + SwipeRefreshLayout.OnRefreshListener, OnItemClickListener { -class ProductFragment : FineractBaseFragment(), ProductContract.View, - SwipeRefreshLayout.OnRefreshListener, OnItemClickListener { + lateinit var rootView: View - @Inject - lateinit var productPresenter: ProductPresenter + lateinit var viewModel: ProductViewModel @Inject lateinit var productAdapter: ProductAdapter - lateinit var productList: List + @Inject + lateinit var productViewModelFactory: ProductViewModelFactory + + lateinit var productList: ArrayList companion object { fun newInstance() = ProductFragment().apply { @@ -44,58 +49,54 @@ class ProductFragment : FineractBaseFragment(), ProductContract.View, } } + val searchedProduct: (ArrayList) -> Unit = { products -> + productAdapter.setProductsList(products) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) - productList = ArrayList() } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View? { - // Inflate the layout for this fragment - val rootView = inflater.inflate(R.layout.fragment_product, container, false) + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + rootView = inflater.inflate(R.layout.fragment_product, container, false) (activity as FineractBaseActivity).activityComponent.inject(this) - productPresenter.attachView(this) initializeFineractUIErrorHandler(activity, rootView) + viewModel = + ViewModelProviders.of(this, productViewModelFactory).get(ProductViewModel::class.java) return rootView } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - showUserInterface() + ButterKnife.bind(this, rootView) productAdapter.setItemClickListener(this) + btn_try_again.setOnClickListener { layoutError.visibility = View.GONE - productPresenter.getProductsPage() + viewModel.getProducts() } - productPresenter.getProductsPage() - } - - override fun showUserInterface() { - - setToolbarTitle(getString(R.string.products)) - val layoutManager = LinearLayoutManager(activity) - layoutManager.orientation = RecyclerView.VERTICAL - rvProduct.layoutManager = layoutManager - rvProduct.setHasFixedSize(true) rvProduct.adapter = productAdapter - - swipeContainer.setColorSchemeColors(*activity!! - .resources.getIntArray(R.array.swipeRefreshColors)) - swipeContainer.setOnRefreshListener(this) - + rvProduct.layoutManager = LinearLayoutManager(context) } - override fun onRefresh() { - productPresenter.getProductsPage() + override fun onStart() { + super.onStart() + viewModel.getProducts()?.observe(this, Observer { + it?.let { + productList = it + productAdapter.setProductsList(it) + } + }) } - override fun showProduct(products: List) { - showRecyclerView(true) - this.productList = products - productAdapter.setProductsList(products) + override fun onRefresh() { + viewModel.getProducts() } @@ -114,68 +115,20 @@ class ProductFragment : FineractBaseFragment(), ProductContract.View, searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { - productPresenter.searchProduct(productList, query) + viewModel.searchProducts(productList, query, searchedProduct) return false } override fun onQueryTextChange(newText: String): Boolean { if (TextUtils.isEmpty(newText)) { - showRecyclerView(true) productAdapter.setProductsList(productList) - - } else { - productPresenter.searchProduct(productList, newText) } - - return false + viewModel.searchProducts(productList, newText, searchedProduct) + return true } }) } - override fun showEmptyProduct() { - showRecyclerView(false) - showFineractEmptyUI(getString(R.string.products), getString(R.string.products), - R.drawable.ic_person_outline_black_24dp) - } - - override fun showRecyclerView(status: Boolean) { - if (status) { - rvProduct.visibility = View.VISIBLE - layoutError.visibility = View.GONE - } else { - rvProduct.visibility = View.GONE - layoutError.visibility = View.VISIBLE - } - } - - override fun showProgressbar() { - swipeContainer.isRefreshing = true - } - - override fun hideProgressbar() { - swipeContainer.isRefreshing = false - } - - override fun searchedProduct(products: List) { - //showRecyclerView(true) - productAdapter.setProductsList(products) - } - - override fun showNoInternetConnection() { - showRecyclerView(false) - showNoInternetConnection() - } - - override fun showError(message: String) { - showRecyclerView(false) - showFineractErrorUI(getString(R.string.products)) - } - - override fun onDestroyView() { - super.onDestroyView() - productPresenter.detachView() - } - override fun onItemClick(childView: View?, position: Int) { val intent = Intent(context, ProductDetailsActivity::class.java).apply { putExtra(Constants.PRODUCT, productList[position]) diff --git a/app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModel.kt b/app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModel.kt new file mode 100644 index 00000000..eaf654e1 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModel.kt @@ -0,0 +1,101 @@ +package org.apache.fineract.ui.product.viewmodel + +import android.annotation.SuppressLint +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.* +import org.apache.fineract.couchbase.SynchronizationManager +import org.apache.fineract.data.Status +import org.apache.fineract.data.datamanager.api.DataManagerAnonymous +import org.apache.fineract.data.datamanager.api.DataManagerProduct +import org.apache.fineract.data.local.PreferencesHelper +import org.apache.fineract.data.models.customer.Country +import org.apache.fineract.data.models.product.Product +import org.apache.fineract.data.models.product.ProductPage +import org.apache.fineract.utils.DateUtils +import org.apache.fineract.utils.serializeToMap +import org.apache.fineract.utils.toDataClass + +/* + * Created by Varun Jain on 11/August/2021 +*/ + + +class ProductViewModel constructor(private val synchronizationManager: SynchronizationManager, + private val dataManagerAnonymous: DataManagerAnonymous, + private val preferencesHelper: PreferencesHelper, + private val dataManagerProduct: DataManagerProduct +) : ViewModel() { + + var productList = MutableLiveData>() + private var viewModelJob = Job() + + // Create a Coroutine scope using a job to be able to cancel when needed + private val uiScope = CoroutineScope(viewModelJob + Dispatchers.IO) + private var _status = MutableLiveData() + val status: LiveData + get() = _status + + @SuppressLint("CheckResult") + fun getProducts(): MutableLiveData>? { + dataManagerProduct.fetchProductPage().subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe{ + productList.value = it.elements as ArrayList + } + + return productList + } + + fun searchProducts(products: ArrayList, query: String, searchedProduct: (ArrayList) -> Unit) { + searchedProduct(ArrayList(Observable.fromIterable(products).filter { product -> product.identifier?.toLowerCase()?.contains(query.toLowerCase()).toString().toBoolean() }.toList().blockingGet())) + } + + @SuppressLint("CheckResult") + fun getCountries(): MutableLiveData> { + val countries = MutableLiveData>() + dataManagerAnonymous.countries.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + countries.value = it + } + return countries + } + + fun getCountryNames(countries: List): List { + return Observable.fromIterable(countries).map { country: Country -> country.name }.toList().blockingGet() + } + + fun getCountryCode(countries: List, countryName: String): String? { + for (country in countries) { + if (country.name == countryName) { + return country.alphaCode + } + } + return null + } + + fun isCountryValid(countries: List, countryName: String): Boolean { + for (country in countries) { + if (country.name == countryName) { + return true + } + } + return false + } + + /** + * When the [ViewModel] is finished, we cancel our coroutine [viewModelJob], which tells the + * Retrofit service to stop. + */ + override fun onCleared() { + super.onCleared() + viewModelJob.cancel() + synchronizationManager.closeDatabase() + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModelFactory.kt b/app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModelFactory.kt new file mode 100644 index 00000000..dbbe15c7 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModelFactory.kt @@ -0,0 +1,29 @@ +package org.apache.fineract.ui.product.viewmodel + +import android.content.Context +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import org.apache.fineract.couchbase.SynchronizationManager +import org.apache.fineract.data.datamanager.api.DataManagerAnonymous +import org.apache.fineract.data.datamanager.api.DataManagerProduct +import org.apache.fineract.data.local.PreferencesHelper +import org.apache.fineract.injection.ApplicationContext +import javax.inject.Inject + +/* + * Created by Varun Jain on 11/August/2021 +*/ + +class ProductViewModelFactory @Inject constructor(@ApplicationContext var context: Context, + private val synchronizationManager: SynchronizationManager, + private val dataManagerAnonymous: DataManagerAnonymous, + private val preferencesHelper: PreferencesHelper, + private val dataManagerProduct: DataManagerProduct +) + : ViewModelProvider.NewInstanceFactory() { + + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T { + return ProductViewModel(synchronizationManager, dataManagerAnonymous, preferencesHelper, dataManagerProduct) as T + } +} \ No newline at end of file From b4909c2a1b2ef3cada8147f6e4bf06b0e7bb03e4 Mon Sep 17 00:00:00 2001 From: varun jain Date: Tue, 17 Aug 2021 01:40:31 +0530 Subject: [PATCH 3/5] Added support to define a product or update the Product definition --- app/src/main/AndroidManifest.xml | 4 + .../fineract/data/models/product/Product.kt | 32 +- .../component/ActivityComponent.java | 12 + .../fineract/ui/product/ProductAction.kt | 6 + .../AddAccountAssignmentsFragment.kt | 231 ++++++++++++ .../createproduct/CreateProductActivity.kt | 177 ++++++++++ .../createproduct/CreateProductAdapter.kt | 40 +++ .../ProductDetailsStepFragment.kt | 239 +++++++++++++ .../ProductReviewStepFragment.kt | 80 +++++ .../productdetails/productdetailsfragment.kt | 9 +- .../ui/product/productlist/ProductFragment.kt | 21 +- .../ui/product/viewmodel/ProductViewModel.kt | 56 +++ .../org/apache/fineract/utils/Constants.kt | 1 + .../res/layout/activity_create_product.xml | 28 ++ app/src/main/res/layout/fragment_product.xml | 24 +- .../fragment_step_add_account_assignments.xml | 151 ++++++++ .../layout/fragment_step_product_details.xml | 290 ++++++++++++++++ .../layout/fragment_step_product_review.xml | 328 ++++++++++++++++++ app/src/main/res/values/strings.xml | 20 ++ 19 files changed, 1714 insertions(+), 35 deletions(-) create mode 100644 app/src/main/java/org/apache/fineract/ui/product/ProductAction.kt create mode 100644 app/src/main/java/org/apache/fineract/ui/product/createproduct/AddAccountAssignmentsFragment.kt create mode 100644 app/src/main/java/org/apache/fineract/ui/product/createproduct/CreateProductActivity.kt create mode 100644 app/src/main/java/org/apache/fineract/ui/product/createproduct/CreateProductAdapter.kt create mode 100644 app/src/main/java/org/apache/fineract/ui/product/createproduct/ProductDetailsStepFragment.kt create mode 100644 app/src/main/java/org/apache/fineract/ui/product/createproduct/ProductReviewStepFragment.kt create mode 100644 app/src/main/res/layout/activity_create_product.xml create mode 100644 app/src/main/res/layout/fragment_step_add_account_assignments.xml create mode 100644 app/src/main/res/layout/fragment_step_product_details.xml create mode 100644 app/src/main/res/layout/fragment_step_product_review.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1155a43b..320ffb4a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -66,6 +66,10 @@ + + diff --git a/app/src/main/java/org/apache/fineract/data/models/product/Product.kt b/app/src/main/java/org/apache/fineract/data/models/product/Product.kt index ba9c826f..234072d1 100644 --- a/app/src/main/java/org/apache/fineract/data/models/product/Product.kt +++ b/app/src/main/java/org/apache/fineract/data/models/product/Product.kt @@ -15,21 +15,21 @@ import java.util.ArrayList @Parcelize data class Product ( - @SerializedName("identifier") val identifier: String? = null, - @SerializedName("name") val name: String? = null, - @SerializedName("termRange") val termRange: TermRange? = null, - @SerializedName("balanceRange") val balanceRange: BalanceRange? = null, - @SerializedName("interestRange") val interestRange: InterestRange? = null, - @SerializedName("interestBasis") val interestBasis: InterestBasis? = null, - @SerializedName("patternPackage") val patternPackage: String? = null, - @SerializedName("description") val description: String? = null, - @SerializedName("currencyCode") val currencyCode: String? = null, - @SerializedName("minorCurrencyUnitDigits") val minorCurrencyUnitDigits: Int = 0, - @SerializedName("accountAssignments") val accountAssignments: List = + @SerializedName("identifier") var identifier: String? = null, + @SerializedName("name") var name: String? = null, + @SerializedName("termRange") var termRange: TermRange? = null, + @SerializedName("balanceRange") var balanceRange: BalanceRange? = null, + @SerializedName("interestRange") var interestRange: InterestRange? = null, + @SerializedName("interestBasis") var interestBasis: InterestBasis? = null, + @SerializedName("patternPackage") var patternPackage: String? = null, + @SerializedName("description") var description: String? = null, + @SerializedName("currencyCode") var currencyCode: String? = null, + @SerializedName("minorCurrencyUnitDigits") var minorCurrencyUnitDigits: Int = 0, + @SerializedName("accountAssignments") var accountAssignments: List = ArrayList(), - @SerializedName("parameters") val parameters: String? = null, - @SerializedName("createdOn") val createdOn: String? = null, - @SerializedName("createdBy") val createdBy: String? = null, - @SerializedName("lastModifiedOn") val lastModifiedOn: String? = null, - @SerializedName("lastModifiedBy") val lastModifiedBy: String? = null + @SerializedName("parameters") var parameters: String? = null, + @SerializedName("createdOn") var createdOn: String? = null, + @SerializedName("createdBy") var createdBy: String? = null, + @SerializedName("lastModifiedOn") var lastModifiedOn: String? = null, + @SerializedName("lastModifiedBy") var lastModifiedBy: String? = null ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java b/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java index 30edc627..1dd37350 100644 --- a/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java +++ b/app/src/main/java/org/apache/fineract/injection/component/ActivityComponent.java @@ -59,6 +59,10 @@ import org.apache.fineract.ui.online.review.AddLoanReviewFragment; import org.apache.fineract.ui.online.roles.roleslist.RolesFragment; import org.apache.fineract.ui.online.teller.TellerFragment; +import org.apache.fineract.ui.product.createproduct.AddAccountAssignmentsFragment; +import org.apache.fineract.ui.product.createproduct.CreateProductActivity; +import org.apache.fineract.ui.product.createproduct.ProductDetailsStepFragment; +import org.apache.fineract.ui.product.createproduct.ProductReviewStepFragment; import org.apache.fineract.ui.product.productlist.ProductFragment; import org.apache.fineract.ui.product.productdetails.ProductDetailsActivity; import org.apache.fineract.ui.product.productdetails.ProductDetailsFragment; @@ -165,5 +169,13 @@ public interface ActivityComponent { void inject(ProductDetailsActivity productDetailsActivity); void inject(ProductDetailsFragment productDetailsFragment); + + void inject(CreateProductActivity createProductActivity); + + void inject(ProductDetailsStepFragment productDetailsStepFragment); + + void inject(AddAccountAssignmentsFragment addAccountAssignmentsFragment); + + void inject(ProductReviewStepFragment productReviewStepFragment); } diff --git a/app/src/main/java/org/apache/fineract/ui/product/ProductAction.kt b/app/src/main/java/org/apache/fineract/ui/product/ProductAction.kt new file mode 100644 index 00000000..bef5616b --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/product/ProductAction.kt @@ -0,0 +1,6 @@ +package org.apache.fineract.ui.product + +enum class ProductAction { + EDIT, + CREATE +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/product/createproduct/AddAccountAssignmentsFragment.kt b/app/src/main/java/org/apache/fineract/ui/product/createproduct/AddAccountAssignmentsFragment.kt new file mode 100644 index 00000000..92862394 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/product/createproduct/AddAccountAssignmentsFragment.kt @@ -0,0 +1,231 @@ +package org.apache.fineract.ui.product.createproduct + +import android.content.DialogInterface +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import butterknife.ButterKnife +import butterknife.OnClick +import butterknife.Optional +import com.stepstone.stepper.Step +import com.stepstone.stepper.VerificationError +import com.wajahatkarim3.easyvalidation.core.view_ktx.validator +import kotlinx.android.synthetic.main.fragment_step_add_account_assignments.* +import kotlinx.android.synthetic.main.fragment_step_add_account_assignments.view.* +import org.apache.fineract.R +import org.apache.fineract.data.models.loan.AccountAssignment +import org.apache.fineract.ui.adapters.ProductAccountAssignmentsAdapter +import org.apache.fineract.ui.base.FineractBaseFragment +import org.apache.fineract.ui.online.groups.GroupAction +import org.apache.fineract.ui.product.ProductAction +import org.apache.fineract.utils.Constants +import org.apache.fineract.utils.MaterialDialog +import org.apache.fineract.utils.Utils +import javax.inject.Inject + +/* + * Created by Varun Jain on 15th August 2021 + */ + +class AddAccountAssignmentsFragment : FineractBaseFragment(), Step, + ProductAccountAssignmentsAdapter.OnItemClickListener { + + lateinit var rootView: View + var accountAssignments: ArrayList = ArrayList() + private var currentAction = ProductAction.CREATE + private var editItemPosition = 0 + private lateinit var productAction: ProductAction + + @Inject + lateinit var productAccountAssignmentsAdapter: ProductAccountAssignmentsAdapter + + companion object { + fun newInstance(productAction: ProductAction) = AddAccountAssignmentsFragment().apply { + val bundle = Bundle().apply { + putSerializable(Constants.PRODUCT_ACTION, productAction) + } + arguments = bundle + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + arguments?.getSerializable(Constants.PRODUCT_ACTION)?.let { + productAction = it as ProductAction + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + rootView = + inflater.inflate(R.layout.fragment_step_add_account_assignments, container, false) + ButterKnife.bind(this, rootView) + (activity as CreateProductActivity).activityComponent.inject(this) + rootView.rvProductAccountAssignments.adapter = productAccountAssignmentsAdapter + productAccountAssignmentsAdapter.setOnItemClickListener(this) + if (productAction == ProductAction.EDIT) { + showDataOnViews() + } + return rootView + } + + private fun showDataOnViews() { + val product = (activity as CreateProductActivity).getProduct() + accountAssignments = product.accountAssignments as ArrayList + if (accountAssignments.size == 0) { + showRecyclerView(false) + } else { + showRecyclerView(true) + } + productAccountAssignmentsAdapter.submitList(accountAssignments) + } + + private fun showRecyclerView(showRecyclerView: Boolean) { + if (showRecyclerView) { + rootView.rvProductAccountAssignments.visibility = View.VISIBLE + rootView.tvAddProductAccountAssignments.visibility = View.GONE + } else { + rootView.rvProductAccountAssignments.visibility = View.GONE + rootView.tvAddProductAccountAssignments.visibility = View.VISIBLE + } + } + + + override fun verifyStep(): VerificationError? { + if (accountAssignments.size == 0) { + Toast.makeText( + context, + getString(R.string.error_product_atleast_1_account_assignment), + Toast.LENGTH_SHORT + ).show() + return VerificationError("") + } + (activity as CreateProductActivity).setAccountAssignments(accountAssignments) + return null + } + + override fun onSelected() { + } + + override fun onError(p0: VerificationError) { + } + + @Optional + @OnClick(R.id.ibAddAccountAssignment) + fun showAddLeaderView() { + showAddAccountAssignmentsView(ProductAction.CREATE, null) + } + + private fun showAddAccountAssignmentsView( + action: ProductAction, + accountAssignment: AccountAssignment? + ) { + Log.d("varun", ">>>>>>>>>>>>>>> ${currentAction.toString()}") + currentAction = action + llAddProductAccountAssignments.visibility = View.VISIBLE + when (action) { + ProductAction.EDIT -> { + btnAddProductAccountAssignment.text = getString(R.string.update) + etDesignator.setText(accountAssignment?.designator) + etAccountIdentifier.setText(accountAssignment?.accountIdentifier) + etLedgerIdentifier.setText(accountAssignment?.ledgerIdentifier) + } + ProductAction.CREATE -> { + btnAddProductAccountAssignment.text = getString(R.string.add) + } + } + } + + @Optional + @OnClick(R.id.btnAddProductAccountAssignment) + fun addAccountAssignment() { + if ( validateAccountIdentifier() || validateDesignator() || validateLedgerIdentifier()) { + if (currentAction == ProductAction.CREATE) { + accountAssignments.add( + AccountAssignment( + etDesignator.text.toString(), + etAccountIdentifier.text.toString(), + etLedgerIdentifier.text.toString() + ) + ) + } else { + accountAssignments[editItemPosition].designator = etDesignator.text.toString() + accountAssignments[editItemPosition].accountIdentifier = + etAccountIdentifier.text.toString() + accountAssignments[editItemPosition].ledgerIdentifier = + etLedgerIdentifier.text.toString() + } + etDesignator.text.clear() + etAccountIdentifier.text.clear() + etLedgerIdentifier.text.clear() + llAddProductAccountAssignments.visibility = View.GONE + Utils.hideKeyboard(context, etDesignator) + Utils.hideKeyboard(context, etAccountIdentifier) + Utils.hideKeyboard(context, etLedgerIdentifier) + showRecyclerView(true) + productAccountAssignmentsAdapter.submitList(accountAssignments) + + } + } + + private fun validateDesignator() : Boolean { + return etDesignator.validator() + .nonEmpty().addErrorCallback { etDesignator.error = it }.check() + } + + + private fun validateAccountIdentifier() : Boolean { + return etAccountIdentifier.validator() + .nonEmpty().addErrorCallback { etAccountIdentifier.error = it }.check() + } + + + private fun validateLedgerIdentifier() : Boolean { + return etLedgerIdentifier.validator() + .nonEmpty().addErrorCallback { etLedgerIdentifier.error = it }.check() + } + + @Optional + @OnClick(R.id.btnCancelProductAccountAssignments) + fun cancelProductAccountAssignmentAddition() { + etLedgerIdentifier.text.clear() + etDesignator.text.clear() + etAccountIdentifier.text.clear() + llAddProductAccountAssignments.visibility = View.GONE + } + + override fun onEditClicked(position: Int) { + editItemPosition = position + showAddAccountAssignmentsView(ProductAction.EDIT, accountAssignments[position]) + } + + override fun onDeleteClicked(position: Int) { + MaterialDialog.Builder().init(context).apply { + setTitle(getString(R.string.dialog_title_confirm_deletion)) + setMessage( + getString( + R.string.dialog_message_confirm_name_deletion, + accountAssignments[position].designator + ) + ) + setPositiveButton( + getString(R.string.delete) + ) { dialog: DialogInterface?, _ -> + accountAssignments.removeAt(position) + productAccountAssignmentsAdapter.submitList(accountAssignments) + if (accountAssignments.size == 0) { + showRecyclerView(false) + } + dialog?.dismiss() + } + setNegativeButton(getString(R.string.dialog_action_cancel)) + createMaterialDialog() + }.run { show() } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/product/createproduct/CreateProductActivity.kt b/app/src/main/java/org/apache/fineract/ui/product/createproduct/CreateProductActivity.kt new file mode 100644 index 00000000..f76dd06e --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/product/createproduct/CreateProductActivity.kt @@ -0,0 +1,177 @@ +package org.apache.fineract.ui.product.createproduct + +import android.os.Bundle +import android.view.View +import android.widget.Toast +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import com.stepstone.stepper.StepperLayout +import com.stepstone.stepper.VerificationError +import kotlinx.android.synthetic.main.activity_create_product.* +import org.apache.fineract.R +import org.apache.fineract.data.Status +import org.apache.fineract.data.models.loan.AccountAssignment +import org.apache.fineract.data.models.loan.TermRange +import org.apache.fineract.data.models.product.BalanceRange +import org.apache.fineract.data.models.product.InterestBasis +import org.apache.fineract.data.models.product.InterestRange +import org.apache.fineract.data.models.product.Product +import org.apache.fineract.ui.base.FineractBaseActivity +import org.apache.fineract.ui.base.Toaster +import org.apache.fineract.ui.product.ProductAction +import org.apache.fineract.ui.product.viewmodel.ProductViewModel +import org.apache.fineract.ui.product.viewmodel.ProductViewModelFactory +import org.apache.fineract.utils.Constants +import javax.inject.Inject + +/* + * Created by Varun Jain on 14th August 2021 + */ + +class CreateProductActivity : FineractBaseActivity(), StepperLayout.StepperListener { + + private var product = Product() + private var productAction = ProductAction.CREATE + + @Inject + lateinit var productViewModelFactory: ProductViewModelFactory + + lateinit var productViewModel: ProductViewModel + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_create_product) + activityComponent.inject(this) + productAction = intent.getSerializableExtra(Constants.PRODUCT_ACTION) as ProductAction + when (productAction) { + ProductAction.EDIT -> { + setToolbarTitle(getString(R.string.edit_product)) + intent?.extras?.getParcelable(Constants.PRODUCT)?.let { + product = it + } + } + ProductAction.CREATE -> { + setToolbarTitle(getString(R.string.create_product)) + } + } + productViewModel = + ViewModelProviders.of(this, productViewModelFactory).get(ProductViewModel::class.java) + subscribeUI() + showBackButton() + slCreateProduct.adapter = CreateProductAdapter(supportFragmentManager, this, productAction) + slCreateProduct.setOffscreenPageLimit(slCreateProduct.adapter.count) + slCreateProduct.setListener(this) + } + + private fun subscribeUI() { + productViewModel.status.observe(this, Observer { status -> + when (status) { + Status.LOADING -> { + if (productAction == ProductAction.CREATE) { + showMifosProgressDialog(getString(R.string.create_product)) + } else { + showMifosProgressDialog(getString(R.string.updating_product_please_wait)) + } + } + Status.ERROR -> { + hideMifosProgressDialog() + if (productAction == ProductAction.CREATE) { + Toaster.show( + findViewById(android.R.id.content), + R.string.error_while_creating_product, + Toast.LENGTH_SHORT + ) + } else { + Toaster.show( + findViewById(android.R.id.content), + R.string.error_while_updating_group, + Toast.LENGTH_SHORT + ) + } + } + Status.DONE -> { + hideMifosProgressDialog() + if (productAction == ProductAction.CREATE) { + Toast.makeText( + this, + getString( + R.string.product_identifier_created_successfully, + product.identifier + ), + Toast.LENGTH_SHORT + ).show() + } else { + Toast.makeText( + this, + getString( + R.string.product_identifier_updated_successfully, + product.identifier + ), + Toast.LENGTH_SHORT + ).show() + } + finish() + } + } + }) + } + + fun setProductDetails( + identifier: String, + name: String, + desc: String, + currentCode: String, + minorCurrencyUnitDigits: Int, + parameters: String, + patternPackage: String + ) { + product.identifier = identifier + product.name = name + product.description = desc + product.currencyCode = currentCode + product.minorCurrencyUnitDigits = minorCurrencyUnitDigits + product.parameters = parameters + product.patternPackage = patternPackage + } + + fun setTermRange(temporalUnit: String, maxTermRange: Double) { + product.termRange = TermRange(temporalUnit, maxTermRange) + } + + fun setBalanceRange(minBalanceRange: Double, maxBalanceRange: Double) { + product.balanceRange = BalanceRange(minBalanceRange, maxBalanceRange) + } + + fun setInterestRange(minInterestRange: Double, maxInterestRange: Double) { + product.interestRange = InterestRange(minInterestRange, maxInterestRange) + } + + fun setInterestBasis(interestBasis: InterestBasis) { + product.interestBasis = interestBasis + } + + fun setAccountAssignments(accountAssignments: List) { + product.accountAssignments = accountAssignments + } + + fun getProduct(): Product { + return product + } + + override fun onCompleted(p0: View?) { + when (productAction) { + ProductAction.CREATE -> { + productViewModel.createProduct(product) + } + ProductAction.EDIT -> product.identifier?.let { + productViewModel.updateProduct(product) + } + } + } + + override fun onError(p0: VerificationError?) {} + + override fun onStepSelected(p0: Int) {} + + override fun onReturn() {} +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/product/createproduct/CreateProductAdapter.kt b/app/src/main/java/org/apache/fineract/ui/product/createproduct/CreateProductAdapter.kt new file mode 100644 index 00000000..c416c57a --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/product/createproduct/CreateProductAdapter.kt @@ -0,0 +1,40 @@ +package org.apache.fineract.ui.product.createproduct + +import android.content.Context +import androidx.fragment.app.FragmentManager +import com.stepstone.stepper.Step +import com.stepstone.stepper.adapter.AbstractFragmentStepAdapter +import com.stepstone.stepper.viewmodel.StepViewModel +import org.apache.fineract.R +import org.apache.fineract.ui.product.ProductAction + + +/* + * Created by Varun Jain on 15th August 2021 + */ + + +class CreateProductAdapter constructor(fm: FragmentManager, + context: Context, + val productAction: ProductAction) + : AbstractFragmentStepAdapter(fm, context) { + + private var createProductSteps = context.resources.getStringArray(R.array.create_product_steps) + + override fun getCount(): Int { + return 3 + } + + override fun createStep(p0: Int): Step? { + when (p0) { + 0 -> return ProductDetailsStepFragment.newInstance(productAction) + 1 -> return AddAccountAssignmentsFragment.newInstance(productAction) + 2 -> return ProductReviewStepFragment.newInstance() + } + return null + } + + override fun getViewModel(position: Int): StepViewModel { + return StepViewModel.Builder(context).setTitle(createProductSteps[position]).create() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/product/createproduct/ProductDetailsStepFragment.kt b/app/src/main/java/org/apache/fineract/ui/product/createproduct/ProductDetailsStepFragment.kt new file mode 100644 index 00000000..7113d1ba --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/product/createproduct/ProductDetailsStepFragment.kt @@ -0,0 +1,239 @@ +package org.apache.fineract.ui.product.createproduct + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.stepstone.stepper.Step +import com.stepstone.stepper.VerificationError +import com.wajahatkarim3.easyvalidation.core.view_ktx.validator +import kotlinx.android.synthetic.main.fragment_step_product_details.* +import kotlinx.android.synthetic.main.fragment_step_product_details.view.* +import org.apache.fineract.R +import org.apache.fineract.data.models.product.InterestBasis +import org.apache.fineract.ui.base.FineractBaseFragment +import org.apache.fineract.ui.product.ProductAction +import org.apache.fineract.utils.Constants + + +/* + * Created by Varun Jain on 14th August 2021 + */ + +class ProductDetailsStepFragment : FineractBaseFragment(), Step { + + lateinit var rootView: View + private lateinit var productAction: ProductAction + + companion object { + fun newInstance(productAction: ProductAction) = ProductDetailsStepFragment().apply { + val bundle = Bundle().apply { + putSerializable(Constants.PRODUCT_ACTION, productAction) + } + arguments = bundle + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + arguments?.getSerializable(Constants.PRODUCT_ACTION)?.let { + productAction = it as ProductAction + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + rootView = inflater.inflate(R.layout.fragment_step_product_details, container, false) + if (productAction == ProductAction.EDIT) { + populateViews() + } + return rootView + } + + private fun populateViews() { + val product = (activity as CreateProductActivity).getProduct() + rootView.etIdentifier.setText(product.identifier) + rootView.etIdentifier.isEnabled = false + rootView.etName.setText(product.name) + rootView.etPatternPackage.setText(product.patternPackage) + rootView.etDescription.setText(product.description) + rootView.etCurrencyCode.setText(product.currencyCode) + rootView.etParameters.setText(product.parameters) + rootView.etMinorCurrencyUnitDigits.setText(product.minorCurrencyUnitDigits.toString()) + rootView.spinnerInterestBasis.setSelection(getIndexFromInterestBasisType(product.interestBasis)) + rootView.etTermRangeMax.setText(product.termRange?.maximum.toString()) + rootView.etTemporalUnit.setText(product.termRange?.temporalUnit) + rootView.etBalanceRangeMinimum.setText(product.balanceRange?.minimum.toString()) + rootView.etMaximumBalanceRange.setText(product.balanceRange?.maximum.toString()) + rootView.etMinInterestRange.setText(product.interestRange?.minimum.toString()) + rootView.etMaximumInterestRange.setText(product.interestRange?.maximum.toString()) + } + + + private fun getIndexFromInterestBasisType(interestBasis: InterestBasis?): Int { + return when (interestBasis) { + InterestBasis.BEGINNING_BALANCE -> 0 + InterestBasis.CURRENT_BALANCE -> 1 + else -> return 0 + } + } + + private fun getInterestBasisTypeFromIndex(index: Int): InterestBasis { + return when (index) { + 0 -> InterestBasis.BEGINNING_BALANCE + 1 -> InterestBasis.CURRENT_BALANCE + else -> InterestBasis.BEGINNING_BALANCE + } + } + + override fun verifyStep(): VerificationError? { + if (!validateBalanceRangeMax() || !validateName() || !validateIdentifier() || !validatePatternPackage() || !validateTermRangeMax() || !validateInterestRangeMax() || !validateInterestRangeMin() || !validateBalanceRangeMax() || !validateBalanceRangeMin() || !validateDescription() || !validateCurrencyCode() || !validateMinorCurrencyUnitDigits() || !validateParameters()) { + return VerificationError(null) + } + (activity as CreateProductActivity) + .setProductDetails( + etIdentifier.text.toString(), + etName.text.toString(), + etDescription.text.toString(), + etCurrencyCode.text.toString(), + etMinorCurrencyUnitDigits.text.toString().toInt(), + etParameters.text.toString(), + etPatternPackage.text.toString() + ) + (activity as CreateProductActivity) + .setTermRange(etTemporalUnit.text.toString(), etTermRangeMax.text.toString().toDouble()) + (activity as CreateProductActivity) + .setBalanceRange( + etBalanceRangeMinimum.text.toString().toDouble(), + etMaximumBalanceRange.text.toString().toDouble() + ) + (activity as CreateProductActivity) + .setInterestRange( + etMinInterestRange.text.toString().toDouble(), + etMaximumInterestRange.text.toString().toDouble() + ) + (activity as CreateProductActivity) + .setInterestBasis(getInterestBasisTypeFromIndex(spinnerInterestBasis.selectedItemPosition)) + return null + } + + private fun validateIdentifier(): Boolean { + return etIdentifier.validator() + .nonEmpty() + .minLength(5) + .addErrorCallback { + etIdentifier.error = it + } + .check() + } + + private fun validateName(): Boolean { + return etName.validator() + .nonEmpty() + .minLength(5) + .addErrorCallback { + etName.error = it + } + .check() + } + + private fun validatePatternPackage(): Boolean { + return etPatternPackage.validator() + .minLength(5) + .nonEmpty() + .addErrorCallback { + etPatternPackage.error = it + } + .check() + } + + private fun validateDescription(): Boolean { + return etDescription.validator() + .minLength(5) + .nonEmpty() + .addErrorCallback { + etDescription.error = it + } + .check() + } + + private fun validateCurrencyCode(): Boolean { + return etCurrencyCode.validator() + .minLength(5) + .nonEmpty() + .addErrorCallback { + etCurrencyCode.error = it + } + .check() + } + + private fun validateMinorCurrencyUnitDigits(): Boolean { + return etMinorCurrencyUnitDigits.validator() + .nonEmpty() + .addErrorCallback { + etMinorCurrencyUnitDigits.error = it + } + .check() + } + + private fun validateParameters(): Boolean { + return etParameters.validator() + .minLength(5) + .addErrorCallback { + etParameters.error = it + } + .check() + } + + private fun validateInterestRangeMax(): Boolean { + return etMaximumInterestRange.validator() + .nonEmpty() + .addErrorCallback { + etMaximumInterestRange.error = it + } + .check() + } + + private fun validateInterestRangeMin(): Boolean { + return etMinInterestRange.validator() + .nonEmpty() + .addErrorCallback { + etMinInterestRange.error = it + } + .check() + } + + private fun validateBalanceRangeMin(): Boolean { + return etBalanceRangeMinimum.validator() + .nonEmpty() + .addErrorCallback { + etBalanceRangeMinimum.error = it + } + .check() + } + + private fun validateBalanceRangeMax(): Boolean { + return etMaximumBalanceRange.validator() + .nonEmpty() + .addErrorCallback { + etMaximumBalanceRange.error = it + } + .check() + } + + private fun validateTermRangeMax(): Boolean { + return etTermRangeMax.validator() + .nonEmpty() + .addErrorCallback { + etTermRangeMax.error = it + } + .check() + } + + override fun onSelected() {} + + override fun onError(p0: VerificationError) {} +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/product/createproduct/ProductReviewStepFragment.kt b/app/src/main/java/org/apache/fineract/ui/product/createproduct/ProductReviewStepFragment.kt new file mode 100644 index 00000000..a9462685 --- /dev/null +++ b/app/src/main/java/org/apache/fineract/ui/product/createproduct/ProductReviewStepFragment.kt @@ -0,0 +1,80 @@ +package org.apache.fineract.ui.product.createproduct + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.stepstone.stepper.Step +import com.stepstone.stepper.VerificationError +import kotlinx.android.synthetic.main.fragment_step_group_review.* +import kotlinx.android.synthetic.main.fragment_step_product_review.* +import kotlinx.android.synthetic.main.fragment_step_product_review.view.* +import org.apache.fineract.R +import org.apache.fineract.data.models.loan.AccountAssignment +import org.apache.fineract.data.models.product.Product +import org.apache.fineract.ui.adapters.ProductAccountAssignmentsAdapter +import org.apache.fineract.ui.base.FineractBaseFragment +import javax.inject.Inject + + +/* + * Created by Varun Jain on 15th August 2021 + */ + +class ProductReviewStepFragment : FineractBaseFragment(), Step{ + + lateinit var rootView: View + + @Inject + lateinit var productAccountAssignmentsAdapter: ProductAccountAssignmentsAdapter + + companion object { + fun newInstance(): ProductReviewStepFragment { + return ProductReviewStepFragment() + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + rootView = inflater.inflate(R.layout.fragment_step_product_review, container, false) + (activity as CreateProductActivity).activityComponent.inject(this) + rootView.rvProductAccountAssignmentsStepReview.adapter = productAccountAssignmentsAdapter + productAccountAssignmentsAdapter.setReview(true) + + return rootView + } + + override fun verifyStep(): VerificationError? { + return null + } + + override fun onSelected() { + populateView((activity as CreateProductActivity).getProduct()) + } + + private fun populateView(product: Product) { + tvProductIdentifier.text = product.identifier + tvProductName.text = product.name + tvPatternPackageProduct.text = product.patternPackage + tvProductDescription.text = product.description + tvProductCurrencyCode.text = product.currencyCode + tvProductMinorCurrencyUnit.text = product.minorCurrencyUnitDigits.toString() + tvParameters.text = product.parameters + tvInterestBasis.text = product.interestBasis.toString() + product.accountAssignments?.let { + productAccountAssignmentsAdapter.submitList(it as ArrayList) + } + tvMinProductBalanceRange.text = product.balanceRange?.minimum.toString() + tvMaxProductBalanceRange.text = product.balanceRange?.maximum.toString() + tvMinInterestRange.text = product.interestRange?.minimum.toString() + tvMaxInterestRange.text = product.interestRange?.maximum.toString() + tvProductTemporalUnit.text = product.termRange?.temporalUnit.toString() + tvMaximumTermRange.text = product.termRange?.maximum.toString() + } + + override fun onError(p0: VerificationError) { + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt b/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt index 7bde5637..1e944b90 100644 --- a/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt +++ b/app/src/main/java/org/apache/fineract/ui/product/productdetails/productdetailsfragment.kt @@ -14,6 +14,8 @@ import org.apache.fineract.ui.adapters.ProductAccountAssignmentsAdapter import org.apache.fineract.ui.base.FineractBaseActivity import org.apache.fineract.ui.base.FineractBaseFragment import org.apache.fineract.ui.base.Toaster +import org.apache.fineract.ui.product.ProductAction +import org.apache.fineract.ui.product.createproduct.CreateProductActivity import org.apache.fineract.utils.Constants import org.apache.fineract.utils.Utils import javax.inject.Inject @@ -73,7 +75,12 @@ class ProductDetailsFragment : FineractBaseFragment() { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_product_details -> { - Toaster.show(rootView, getString(R.string.Under_construction), Toast.LENGTH_SHORT) + val intent = Intent(activity, CreateProductActivity::class.java).apply { + putExtra(Constants.PRODUCT, product) + putExtra(Constants.PRODUCT_ACTION, ProductAction.EDIT) + } + startActivity(intent) + activity!!.finish() } } return super.onOptionsItemSelected(item) diff --git a/app/src/main/java/org/apache/fineract/ui/product/productlist/ProductFragment.kt b/app/src/main/java/org/apache/fineract/ui/product/productlist/ProductFragment.kt index a3a990fb..3680d51c 100644 --- a/app/src/main/java/org/apache/fineract/ui/product/productlist/ProductFragment.kt +++ b/app/src/main/java/org/apache/fineract/ui/product/productlist/ProductFragment.kt @@ -26,9 +26,13 @@ import org.apache.fineract.utils.Constants import javax.inject.Inject import kotlin.collections.ArrayList import androidx.lifecycle.Observer +import butterknife.OnClick +import org.apache.fineract.ui.online.groups.GroupAction +import org.apache.fineract.ui.online.groups.creategroup.CreateGroupActivity +import org.apache.fineract.ui.product.ProductAction +import org.apache.fineract.ui.product.createproduct.CreateProductActivity -class ProductFragment : FineractBaseFragment(), - SwipeRefreshLayout.OnRefreshListener, OnItemClickListener { +class ProductFragment : FineractBaseFragment(), OnItemClickListener { lateinit var rootView: View @@ -95,11 +99,6 @@ class ProductFragment : FineractBaseFragment(), }) } - override fun onRefresh() { - viewModel.getProducts() - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) inflater.inflate(R.menu.menu_product_search, menu) @@ -138,4 +137,12 @@ class ProductFragment : FineractBaseFragment(), } override fun onItemLongPress(childView: View?, position: Int) {} + + @OnClick(R.id.fabAddProduct) + fun addGroup() { + val intent = Intent(activity, CreateProductActivity::class.java).apply { + putExtra(Constants.PRODUCT_ACTION, ProductAction.CREATE) + } + startActivity(intent) + } } diff --git a/app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModel.kt b/app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModel.kt index eaf654e1..f6269c25 100644 --- a/app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModel.kt +++ b/app/src/main/java/org/apache/fineract/ui/product/viewmodel/ProductViewModel.kt @@ -55,6 +55,62 @@ class ProductViewModel constructor(private val synchronizationManager: Synchroni searchedProduct(ArrayList(Observable.fromIterable(products).filter { product -> product.identifier?.toLowerCase()?.contains(query.toLowerCase()).toString().toBoolean() }.toList().blockingGet())) } + @SuppressLint("CheckResult") + fun createProduct(product: Product) { +// uiScope.launch { +// withContext(Dispatchers.Main) { +// try { +// _status.value = Status.LOADING +// product.createdBy = preferencesHelper.userName +// product.createdOn = DateUtils.getCurrentDate() +// product.lastModifiedBy = preferencesHelper.userName +// product.lastModifiedOn = DateUtils.getCurrentDate() +// dataManagerProduct.createTeller(teller).subscribeOn(Schedulers.io()) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribeWith(object : DisposableCompletableObserver() { +// override fun onComplete() { +// _status.value = Status.DONE +// } +// +// override fun onError(e: Throwable) { +// _status.value = Status.ERROR +// } +// }) +// } catch (exception: Exception) { +// _status.value = Status.ERROR +// } +// } +// } + } + + @SuppressLint("CheckResult") + fun updateProduct(product: Product) { +// uiScope.launch { +// withContext(Dispatchers.Main) { +// try { +// _status.value = Status.LOADING +// product.createdBy = preferencesHelper.userName +// product.createdOn = DateUtils.getCurrentDate() +// product.lastModifiedBy = preferencesHelper.userName +// product.lastModifiedOn = DateUtils.getCurrentDate() +// dataManagerProduct.updateTeller(teller).subscribeOn(Schedulers.io()) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribeWith(object : DisposableCompletableObserver() { +// override fun onComplete() { +// _status.value = Status.DONE +// } +// +// override fun onError(e: Throwable) { +// _status.value = Status.ERROR +// } +// }) +// } catch (exception: Exception) { +// _status.value = Status.ERROR +// } +// } +// } + } + @SuppressLint("CheckResult") fun getCountries(): MutableLiveData> { val countries = MutableLiveData>() diff --git a/app/src/main/java/org/apache/fineract/utils/Constants.kt b/app/src/main/java/org/apache/fineract/utils/Constants.kt index 63db68aa..f141ef71 100644 --- a/app/src/main/java/org/apache/fineract/utils/Constants.kt +++ b/app/src/main/java/org/apache/fineract/utils/Constants.kt @@ -13,4 +13,5 @@ object Constants { const val GATEWAY_USER_NAME = "fineract-cn" const val GATEWAY_PASSWORD = "password" const val PRODUCT = "product" + const val PRODUCT_ACTION = "product_action" } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_create_product.xml b/app/src/main/res/layout/activity_create_product.xml new file mode 100644 index 00000000..d4469fa4 --- /dev/null +++ b/app/src/main/res/layout/activity_create_product.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_product.xml b/app/src/main/res/layout/fragment_product.xml index 2b279d34..cabb6ba3 100644 --- a/app/src/main/res/layout/fragment_product.xml +++ b/app/src/main/res/layout/fragment_product.xml @@ -1,23 +1,25 @@ - - - + android:layout_width="match_parent" + android:layout_height="match_parent"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +