You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ra...@apache.org on 2020/07/11 14:08:09 UTC
[fineract-cn-mobile] branch development updated: :
This is an automated email from the ASF dual-hosted git repository.
rajanmaurya154 pushed a commit to branch development
in repository https://gitbox.apache.org/repos/asf/fineract-cn-mobile.git
The following commit(s) were added to refs/heads/development by this push:
new 592099e :
592099e is described below
commit 592099e802aee546a145f8c9e96a3aecd149312b
Author: miPlodder <ac...@gmail.com>
AuthorDate: Sun Jun 16 21:45:15 2019 +0530
:
Feat: Adds support for creating, viewing, editing group details, deleting, editing members and leaders name and tasks of group
---
app/build.gradle | 13 +
.../java/org/apache/fineract/FakeJsonName.java | 1 +
.../org/apache/fineract/FakeRemoteDataSource.java | 6 +
app/src/main/AndroidManifest.xml | 11 +-
.../main/java/org/apache/fineract/data/Status.kt | 10 +
.../data/datamanager/api/DataManagerGroups.kt | 45 +++
.../java/org/apache/fineract/data/models/Group.kt | 33 ++
.../fineract/data/remote/BaseApiManager.java | 7 +
.../apache/fineract/data/services/GroupsService.kt | 29 ++
.../injection/component/ActivityComponent.java | 24 ++
.../apache/fineract/ui/adapters/GroupsAdapter.kt | 79 +++++
.../apache/fineract/ui/adapters/NameListAdapter.kt | 72 ++++
.../fineract/ui/online/DashboardActivity.java | 3 +
.../FormCustomerDetailsFragment.java | 2 +-
.../fineract/ui/online/groups/GroupAction.kt | 6 +
.../creategroup/AddGroupLeaderStepFragment.kt | 181 ++++++++++
.../creategroup/AddGroupMemberStepFragment.kt | 178 ++++++++++
.../groups/creategroup/CreateGroupActivity.kt | 138 ++++++++
.../groups/creategroup/CreateGroupAdapter.kt | 41 +++
.../groups/creategroup/GroupAddressStepFragment.kt | 154 +++++++++
.../groups/creategroup/GroupDetailsStepFragment.kt | 124 +++++++
.../online/groups/creategroup/GroupModelHelper.kt | 25 ++
.../groups/creategroup/GroupReviewStepFragment.kt | 84 +++++
.../groups/groupdetails/GroupDetailsActivity.kt | 26 ++
.../groups/groupdetails/GroupDetailsFragment.kt | 133 ++++++++
.../online/groups/grouplist/GroupListFragment.kt | 133 ++++++++
.../ui/online/groups/grouplist/GroupViewModel.kt | 130 +++++++
.../groups/grouplist/GroupViewModelFactory.kt | 25 ++
.../grouptasks/GroupTasksBottomSheetFragment.kt | 144 ++++++++
.../java/org/apache/fineract/utils/Constants.kt | 11 +
.../java/org/apache/fineract/utils/DateUtils.java | 46 ++-
.../org/apache/fineract/utils/StatusUtils.java | 35 +-
.../main/java/org/apache/fineract/utils/Utils.java | 24 +-
.../fineract/utils/ValidateIdentifierUtil.java | 2 +-
app/src/main/res/drawable/border.xml | 9 +
app/src/main/res/drawable/circular_background.xml | 7 +
app/src/main/res/drawable/ic_teller_black_24dp.xml | 13 +
app/src/main/res/layout/activity_create_group.xml | 28 ++
app/src/main/res/layout/fragment_group_list.xml | 23 ++
.../layout/fragment_group_tasks_bottom_sheet.xml | 164 +++++++++
.../main/res/layout/fragment_groups_details.xml | 378 +++++++++++++++++++++
.../res/layout/fragment_step_add_group_leader.xml | 125 +++++++
.../res/layout/fragment_step_add_group_member.xml | 128 +++++++
.../res/layout/fragment_step_group_address.xml | 91 +++++
.../res/layout/fragment_step_group_details.xml | 95 ++++++
.../main/res/layout/fragment_step_group_review.xml | 277 +++++++++++++++
app/src/main/res/layout/item_group.xml | 63 ++++
app/src/main/res/layout/item_name_list.xml | 42 +++
app/src/main/res/menu/menu_group_detials.xml | 10 +
app/src/main/res/menu/menu_group_search.xml | 11 +
app/src/main/res/menu/menu_navigation_drawer.xml | 15 +-
app/src/main/res/values-ml-rIN/strings.xml | 2 +-
app/src/main/res/values/dimens.xml | 6 +
app/src/main/res/values/strings.xml | 48 ++-
app/src/main/res/values/styles_text.xml | 2 +-
app/src/main/res/xml/network_security_config.xml | 8 +
app/src/main/resources/groups.json | 122 +++++++
build.gradle | 3 +
58 files changed, 3618 insertions(+), 27 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 71788f4..0c7f303 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -17,6 +17,7 @@ android {
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
+ multiDexEnabled true
}
buildTypes {
@@ -85,6 +86,10 @@ dependencies {
implementation "androidx.cardview:cardview:$supportLibraryVersion"
implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion"
implementation "androidx.annotation:annotation:$supportLibraryVersion"
+ implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleExtension"
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ kapt "androidx.lifecycle:lifecycle-compiler:$lifecycleExtension"
+
// Kotlin Dependencies
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
@@ -145,6 +150,14 @@ dependencies {
implementation "com.mifos.mobile:mifos-passcode:$mifosPasscodeVersion"
+ //Easy Validation Library
+ implementation "com.wajahatkarim3.easyvalidation:easyvalidation-core:$easyValidationVersion"
+
+ //Coroutines
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version_kotlin_coroutines"
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version_kotlin_coroutines"
+
+
// Instrumentation test dependencies
androidTestImplementation jUnit
androidTestImplementation mockito
diff --git a/app/src/commonTest/java/org/apache/fineract/FakeJsonName.java b/app/src/commonTest/java/org/apache/fineract/FakeJsonName.java
index 9610ff0..cac6ae2 100644
--- a/app/src/commonTest/java/org/apache/fineract/FakeJsonName.java
+++ b/app/src/commonTest/java/org/apache/fineract/FakeJsonName.java
@@ -24,4 +24,5 @@ public class FakeJsonName {
public static final String PRODUCT_PAGE = "productPage.json";
public static final String PRODUCT_DEFINITION = "productDefinition.json";
public static final String PAYROLL_CONFIG = "payrollConfiguration.json";
+ public static final String GROUPS = "groups.json";
}
\ No newline at end of file
diff --git a/app/src/commonTest/java/org/apache/fineract/FakeRemoteDataSource.java b/app/src/commonTest/java/org/apache/fineract/FakeRemoteDataSource.java
index e6b5a4b..8ffc4c3 100644
--- a/app/src/commonTest/java/org/apache/fineract/FakeRemoteDataSource.java
+++ b/app/src/commonTest/java/org/apache/fineract/FakeRemoteDataSource.java
@@ -3,6 +3,7 @@ package org.apache.fineract;
import com.google.gson.reflect.TypeToken;
import org.apache.fineract.data.models.Authentication;
+import org.apache.fineract.data.models.Group;
import org.apache.fineract.data.models.accounts.LedgerPage;
import org.apache.fineract.data.models.accounts.AccountPage;
import org.apache.fineract.data.models.customer.Command;
@@ -113,4 +114,9 @@ public class FakeRemoteDataSource {
return testDataFactory.getObjectTypePojo(PayrollConfiguration.class,
FakeJsonName.PAYROLL_CONFIG);
}
+
+ public static List<Group> getGroups() {
+ return testDataFactory.getListTypePojo(new TypeToken<List<Group>>() {
+ }, FakeJsonName.GROUPS);
+ }
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d28cf45..08702c3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="org.apache.fineract">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -18,8 +19,10 @@
android:allowBackup="true"
android:icon="@drawable/launcher_image"
android:label="@string/app_name"
+ android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true"
- android:theme="@style/AppTheme">
+ android:theme="@style/AppTheme"
+ tools:targetApi="n">
<provider
android:name="androidx.core.content.FileProvider"
@@ -86,6 +89,12 @@
<activity android:name=".ui.online.customers.customeractivities.CustomerActivitiesActivity" />
+ <activity android:name=".ui.online.groups.groupdetails.GroupDetailsActivity" />
+
+ <activity
+ android:name=".ui.online.groups.creategroup.CreateGroupActivity"
+ android:windowSoftInputMode="adjustResize|stateHidden" />
+
<receiver
android:name=".jobs.JobsReceiver"
android:exported="false">
diff --git a/app/src/main/java/org/apache/fineract/data/Status.kt b/app/src/main/java/org/apache/fineract/data/Status.kt
new file mode 100644
index 0000000..a79e172
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/data/Status.kt
@@ -0,0 +1,10 @@
+package org.apache.fineract.data
+
+/**
+ * Created by Ahmad Jawid Muhammadi on 6/4/20
+ */
+enum class Status {
+ LOADING,
+ ERROR,
+ DONE
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/data/datamanager/api/DataManagerGroups.kt b/app/src/main/java/org/apache/fineract/data/datamanager/api/DataManagerGroups.kt
new file mode 100644
index 0000000..7de126f
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/data/datamanager/api/DataManagerGroups.kt
@@ -0,0 +1,45 @@
+package org.apache.fineract.data.datamanager.api
+
+import androidx.lifecycle.MutableLiveData
+import io.reactivex.Observable
+import io.reactivex.ObservableSource
+import io.reactivex.functions.Function
+import kotlinx.coroutines.Deferred
+import okhttp3.ResponseBody
+import org.apache.fineract.FakeRemoteDataSource
+import org.apache.fineract.data.local.PreferencesHelper
+import org.apache.fineract.data.models.Group
+import org.apache.fineract.data.models.customer.Command
+import org.apache.fineract.data.remote.BaseApiManager
+import javax.inject.Inject
+
+
+/*
+ * Created by saksham on 15/June/2019
+*/
+
+class DataManagerGroups @Inject constructor(private val baseManagerApi: BaseApiManager,
+ val dataManagerAuth: DataManagerAuth,
+ val preferencesHelper: PreferencesHelper)
+ : FineractBaseDataManager(dataManagerAuth, preferencesHelper) {
+
+ fun getGroups(): MutableLiveData<ArrayList<Group>> {
+ val groups = MutableLiveData<ArrayList<Group>>()
+
+ groups.value = ArrayList(baseManagerApi.groupsService.getGroups()
+ .onErrorResumeNext(Function<Throwable, ObservableSource<List<Group>>> {
+ Observable.just(FakeRemoteDataSource.getGroups())
+ }).blockingFirst())
+ return groups
+ }
+
+ fun createGroup(group: Group): Deferred<ResponseBody> = baseManagerApi.groupsService.createGroup(group)
+
+ fun updateGroup(identifier: String, group: Group): Deferred<ResponseBody> {
+ return baseManagerApi.groupsService.updateGroup(identifier, group)
+ }
+
+ fun changeGroupStatus(identifier: String, command: Command): Deferred<ResponseBody> {
+ return baseManagerApi.groupsService.changeGroupStatus(identifier, command)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/data/models/Group.kt b/app/src/main/java/org/apache/fineract/data/models/Group.kt
new file mode 100644
index 0000000..9f8a35f
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/data/models/Group.kt
@@ -0,0 +1,33 @@
+package org.apache.fineract.data.models
+
+import android.os.Parcelable
+import kotlinx.android.parcel.Parcelize
+import org.apache.fineract.data.models.customer.Address
+
+/*
+ * Created by saksham on 16/June/2019
+*/
+
+@Parcelize
+data class Group(
+ var identifier: String? = null,
+ var groupDefinitionIdentifier: String? = null,
+ var name: String? = null,
+ var leaders: List<String>? = null,
+ var members: List<String>? = null,
+ var office: String? = null,
+ var assignedEmployee: String? = null,
+ var weekday: Int? = null,
+ var status: Status? = null,
+ var address: Address? = null,
+ var createdOn: String? = null,
+ var createdBy: String? = null,
+ var lastModifiedBy: String? = null,
+ var lastModifiedOn: String? = null) : Parcelable {
+
+ enum class Status {
+ PENDING,
+ ACTIVE,
+ CLOSED
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/data/remote/BaseApiManager.java b/app/src/main/java/org/apache/fineract/data/remote/BaseApiManager.java
index adb2734..bfef0a3 100644
--- a/app/src/main/java/org/apache/fineract/data/remote/BaseApiManager.java
+++ b/app/src/main/java/org/apache/fineract/data/remote/BaseApiManager.java
@@ -7,6 +7,7 @@ import org.apache.fineract.data.services.AnonymousService;
import org.apache.fineract.data.services.AuthService;
import org.apache.fineract.data.services.CustomerService;
import org.apache.fineract.data.services.DepositService;
+import org.apache.fineract.data.services.GroupsService;
import org.apache.fineract.data.services.IndividualLendingService;
import org.apache.fineract.data.services.LoanService;
import org.apache.fineract.data.services.ProductService;
@@ -41,6 +42,7 @@ public class BaseApiManager {
private static TellersService tellerService;
private static ProductService productService;
private static PayrollService payrollService;
+ private static GroupsService groupsService;
public BaseApiManager(Context context) {
createService(context);
@@ -58,6 +60,7 @@ public class BaseApiManager {
tellerService = createApi(TellersService.class);
productService = createApi(ProductService.class);
payrollService = createApi(PayrollService.class);
+ groupsService = createApi(GroupsService.class);
}
private static void initAnonymous() {
@@ -142,4 +145,8 @@ public class BaseApiManager {
public PayrollService getPayrollService() {
return payrollService;
}
+
+ public GroupsService getGroupsService() {
+ return groupsService;
+ }
}
diff --git a/app/src/main/java/org/apache/fineract/data/services/GroupsService.kt b/app/src/main/java/org/apache/fineract/data/services/GroupsService.kt
new file mode 100644
index 0000000..3c0b702
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/data/services/GroupsService.kt
@@ -0,0 +1,29 @@
+package org.apache.fineract.data.services
+
+import io.reactivex.Observable
+import kotlinx.coroutines.Deferred
+import okhttp3.ResponseBody
+import org.apache.fineract.data.models.Group
+import org.apache.fineract.data.models.customer.Command
+import retrofit2.http.*
+
+/*
+ * Created by saksham on 15/June/2019
+*/
+
+interface GroupsService {
+
+ @GET("/groups")
+ fun getGroups(): Observable<List<Group>>
+
+ @POST("/groups")
+ fun createGroup(@Body group: Group): Deferred<ResponseBody>
+
+ @PUT("/groups/{identifier}")
+ fun updateGroup(@Path("identifier") identifier: String,
+ @Body group: Group): Deferred<ResponseBody>
+
+ @PUT("/groups/{identifier}/commands")
+ fun changeGroupStatus(@Path("identifier") identifier: String,
+ @Body command: Command): Deferred<ResponseBody>
+}
\ 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 6c250f8..7e8d2ec 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
@@ -30,6 +30,14 @@ import org.apache.fineract.ui.online.depositaccounts.createdepositaccount
import org.apache.fineract.ui.online.depositaccounts.depositaccountdetails
.DepositAccountDetailsFragment;
import org.apache.fineract.ui.online.depositaccounts.depositaccountslist.DepositAccountsFragment;
+import org.apache.fineract.ui.online.groups.creategroup.AddGroupLeaderStepFragment;
+import org.apache.fineract.ui.online.groups.creategroup.AddGroupMemberStepFragment;
+import org.apache.fineract.ui.online.groups.creategroup.CreateGroupActivity;
+import org.apache.fineract.ui.online.groups.creategroup.GroupAddressStepFragment;
+import org.apache.fineract.ui.online.groups.creategroup.GroupReviewStepFragment;
+import org.apache.fineract.ui.online.groups.groupdetails.GroupDetailsFragment;
+import org.apache.fineract.ui.online.groups.grouplist.GroupListFragment;
+import org.apache.fineract.ui.online.groups.grouptasks.GroupTasksBottomSheetFragment;
import org.apache.fineract.ui.online.identification.createidentification.identificationactivity
.CreateIdentificationActivity;
import org.apache.fineract.ui.online.identification.identificationdetails
@@ -135,5 +143,21 @@ public interface ActivityComponent {
void inject(EditPayrollAllocationFragment editPayrollAllocationFragment);
void inject(EditPayrollActivity editPayrollActivity);
+
+ void inject(GroupListFragment groupListFragment);
+
+ void inject(GroupAddressStepFragment groupAddressStepFragment);
+
+ void inject(CreateGroupActivity createGroupActivity);
+
+ void inject(AddGroupMemberStepFragment addGroupMemberStepFragment);
+
+ void inject(AddGroupLeaderStepFragment addGroupLeaderStepFragment);
+
+ void inject(GroupReviewStepFragment groupReviewStepFragment);
+
+ void inject(GroupDetailsFragment groupDetailsFragment);
+
+ void inject(GroupTasksBottomSheetFragment groupTasksBottomSheetFragment);
}
diff --git a/app/src/main/java/org/apache/fineract/ui/adapters/GroupsAdapter.kt b/app/src/main/java/org/apache/fineract/ui/adapters/GroupsAdapter.kt
new file mode 100644
index 0000000..75e6ece
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/adapters/GroupsAdapter.kt
@@ -0,0 +1,79 @@
+package org.apache.fineract.ui.adapters
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import kotlinx.android.synthetic.main.item_group.view.*
+import org.apache.fineract.R
+import org.apache.fineract.data.models.Group
+import org.apache.fineract.injection.ApplicationContext
+import org.apache.fineract.ui.base.OnItemClickListener
+import org.apache.fineract.utils.DateUtils
+import org.apache.fineract.utils.StatusUtils
+import javax.inject.Inject
+
+
+/*
+ * Created by saksham on 16/June/2019
+*/
+
+class GroupsAdapter @Inject constructor(@ApplicationContext var context: Context?)
+ : RecyclerView.Adapter<GroupsAdapter.ViewHolder>() {
+
+ var groups = ArrayList<Group>()
+ lateinit var onItemClickListener: OnItemClickListener
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ return ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_group, parent, false))
+ }
+
+ override fun getItemCount(): Int = groups.size
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ var group: Group = groups[position]
+
+ StatusUtils.setGroupsStatusIcon(group.status, holder.ivTypeIndicator, context)
+
+ holder.tvGroupIdentifier.text = group.identifier
+
+ val modifiedBy = context?.getString(R.string.last_modified_by) + context?.getString(R.string.colon) + group.lastModifiedBy
+ holder.tvLastModifiedBy.text = modifiedBy
+
+ val lastModifiedOn = context?.getString(R.string.last_modified_on) + context?.getString(R.string.colon) + DateUtils.getDate(group.lastModifiedOn,
+ DateUtils.INPUT_DATE_FORMAT, DateUtils.OUTPUT_DATE_FORMAT)
+ holder.tvLastModifiedOn.text = lastModifiedOn
+ }
+
+ fun setGroupList(groups: ArrayList<Group>) {
+ this.groups = groups
+ notifyDataSetChanged()
+ }
+
+ fun setItemClickListener(onItemClickListener: OnItemClickListener) {
+ this.onItemClickListener = onItemClickListener
+ }
+
+ inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
+ View.OnClickListener {
+ var llGroups: LinearLayout = itemView.ll_group
+ var ivTypeIndicator: ImageView = itemView.iv_type_indicator
+ var tvGroupIdentifier: TextView = itemView.tv_group_identifier
+ var tvLastModifiedBy: TextView = itemView.tv_last_modified_by
+ var tvLastModifiedOn: TextView = itemView.tv_last_modified_on
+
+ init {
+ llGroups.setOnClickListener(this)
+ }
+
+ override fun onClick(v: View?) {
+ if (onItemClickListener != null) {
+ onItemClickListener.onItemClick(v, adapterPosition)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/adapters/NameListAdapter.kt b/app/src/main/java/org/apache/fineract/ui/adapters/NameListAdapter.kt
new file mode 100644
index 0000000..b261a60
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/adapters/NameListAdapter.kt
@@ -0,0 +1,72 @@
+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.item_name_list.view.*
+import org.apache.fineract.R
+import javax.inject.Inject
+
+class NameListAdapter @Inject constructor()
+ : RecyclerView.Adapter<NameListAdapter.ViewHolder>() {
+
+ private var nameList = ArrayList<String>()
+ 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 = nameList.size
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ holder.bind(nameList[position], onItemClickListener, isReview)
+ }
+
+ fun setOnItemClickListener(onItemClickListener: OnItemClickListener?) {
+ this.onItemClickListener = onItemClickListener
+ }
+
+ fun submitList(list: ArrayList<String>) {
+ nameList = list
+ notifyDataSetChanged()
+ }
+
+ fun setReview(isReview: Boolean) {
+ this.isReview = isReview
+ }
+
+ class ViewHolder private constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
+
+ fun bind(name: String, onItemClickListener: OnItemClickListener?, isReview: Boolean) {
+ if (isReview) {
+ itemView.iv_edit.visibility = View.GONE
+ itemView.iv_delete.visibility = View.GONE
+ } else {
+ itemView.iv_edit.visibility = View.VISIBLE
+ itemView.iv_delete.visibility = View.VISIBLE
+ }
+ itemView.tv_name.text = name
+ itemView.iv_delete.setOnClickListener {
+ onItemClickListener?.onDeleteClicked(adapterPosition)
+ }
+ itemView.iv_edit.setOnClickListener {
+ onItemClickListener?.onEditClicked(adapterPosition)
+ }
+ }
+
+ companion object {
+ fun from(parent: ViewGroup): ViewHolder {
+ return ViewHolder(LayoutInflater.from(parent.context)
+ .inflate(R.layout.item_name_list, parent, false))
+ }
+ }
+ }
+
+ interface OnItemClickListener {
+ fun onEditClicked(position: Int)
+ fun onDeleteClicked(position: Int)
+ }
+}
\ No newline at end of file
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 15b4d61..7f0460d 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
@@ -28,6 +28,7 @@ import org.apache.fineract.ui.online.accounting.ledgers.LedgerFragment;
import org.apache.fineract.ui.online.accounting.accounts.AccountsFragment;
import org.apache.fineract.ui.online.customers.customerlist.CustomersFragment;
import org.apache.fineract.ui.online.dashboard.DashboardFragment;
+import org.apache.fineract.ui.online.groups.grouplist.GroupListFragment;
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;
@@ -139,6 +140,8 @@ public class DashboardActivity extends FineractBaseActivity implements
case R.id.item_teller:
replaceFragment(TellerFragment.Companion.newInstance(), true, R.id.container);
break;
+ case R.id.item_groups:
+ replaceFragment(GroupListFragment.Companion.newInstance(), true, R.id.container);
}
drawerLayout.closeDrawer(GravityCompat.START);
diff --git a/app/src/main/java/org/apache/fineract/ui/online/customers/createcustomer/FormCustomerDetailsFragment.java b/app/src/main/java/org/apache/fineract/ui/online/customers/createcustomer/FormCustomerDetailsFragment.java
index 4222be0..6e779fc 100644
--- a/app/src/main/java/org/apache/fineract/ui/online/customers/createcustomer/FormCustomerDetailsFragment.java
+++ b/app/src/main/java/org/apache/fineract/ui/online/customers/createcustomer/FormCustomerDetailsFragment.java
@@ -234,7 +234,7 @@ public class FormCustomerDetailsFragment extends FineractBaseFragment implements
return false;
} else if (account.length() < 3) {
showTextInputLayoutError(tilAccount,
- getString(R.string.must_be_at_least_three_characters, 3));
+ getString(R.string.must_be_at_least_n_characters, 3));
return false;
} else if (account.length() > 32) {
showTextInputLayoutError(tilAccount,
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/GroupAction.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/GroupAction.kt
new file mode 100644
index 0000000..13d14d4
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/GroupAction.kt
@@ -0,0 +1,6 @@
+package org.apache.fineract.ui.online.groups
+
+enum class GroupAction {
+ EDIT,
+ CREATE
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/AddGroupLeaderStepFragment.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/AddGroupLeaderStepFragment.kt
new file mode 100644
index 0000000..55c2e4d
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/AddGroupLeaderStepFragment.kt
@@ -0,0 +1,181 @@
+package org.apache.fineract.ui.online.groups.creategroup
+
+import android.content.DialogInterface
+import android.os.Bundle
+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_group_leader.*
+import kotlinx.android.synthetic.main.fragment_step_add_group_leader.view.*
+import kotlinx.android.synthetic.main.fragment_step_add_group_member.view.*
+import kotlinx.android.synthetic.main.fragment_step_add_group_member.view.rv_name
+import org.apache.fineract.R
+import org.apache.fineract.ui.adapters.NameListAdapter
+import org.apache.fineract.ui.base.FineractBaseActivity
+import org.apache.fineract.ui.base.FineractBaseFragment
+import org.apache.fineract.ui.online.groups.GroupAction
+import org.apache.fineract.utils.Constants
+import org.apache.fineract.utils.MaterialDialog
+import org.apache.fineract.utils.Utils
+import javax.inject.Inject
+
+
+/*
+ * Created by saksham on 02/July/2019
+*/
+
+class AddGroupLeaderStepFragment : FineractBaseFragment(), Step, NameListAdapter.OnItemClickListener {
+
+ lateinit var rootView: View
+ var leaders: ArrayList<String> = ArrayList()
+ private var currentAction = GroupAction.CREATE
+ private var editItemPosition = 0
+ private lateinit var groupAction: GroupAction
+
+ @Inject
+ lateinit var nameLisAdapter: NameListAdapter
+
+ companion object {
+ fun newInstance(groupAction: GroupAction) = AddGroupLeaderStepFragment().apply {
+ val bundle = Bundle().apply {
+ putSerializable(Constants.GROUP_ACTION, groupAction)
+ }
+ arguments = bundle
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ arguments?.getSerializable(Constants.GROUP_ACTION)?.let {
+ groupAction = it as GroupAction
+ }
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ rootView = inflater.inflate(R.layout.fragment_step_add_group_leader, container, false)
+ ButterKnife.bind(this, rootView)
+ (activity as FineractBaseActivity).activityComponent.inject(this)
+ rootView.rv_name.adapter = nameLisAdapter
+ nameLisAdapter.setOnItemClickListener(this)
+ if (groupAction == GroupAction.EDIT) {
+ showDataOnViews()
+ }
+ return rootView
+ }
+
+ private fun showDataOnViews() {
+ val group = (activity as CreateGroupActivity).getGroup()
+ leaders = group.leaders as ArrayList<String>
+ if (leaders.size == 0) {
+ showRecyclerView(false)
+ } else {
+ showRecyclerView(true)
+ }
+ nameLisAdapter.submitList(leaders)
+ }
+
+ @Optional
+ @OnClick(R.id.ibAddLeader)
+ fun showAddLeaderView() {
+ showAddLeaderView(GroupAction.CREATE, null)
+ }
+
+ private fun showAddLeaderView(action: GroupAction, name: String?) {
+ currentAction = action
+ llAddLeader.visibility = View.VISIBLE
+ when (action) {
+ GroupAction.CREATE -> {
+ btnAddLeader.text = getString(R.string.add)
+ }
+ GroupAction.EDIT -> {
+ etNewLeader.setText(name)
+ btnAddLeader.text = getString(R.string.update)
+ }
+ }
+ }
+
+ @Optional
+ @OnClick(R.id.btnAddLeader)
+ fun addLeader() {
+ if (etNewLeader.validator()
+ .nonEmpty()
+ .noNumbers()
+ .addErrorCallback { etNewLeader.error = it }.check()) {
+ if (currentAction == GroupAction.CREATE) {
+ leaders.add(etNewLeader.text.toString())
+ } else {
+ leaders[editItemPosition] = etNewLeader.text.toString()
+ }
+ etNewLeader.text.clear()
+ llAddLeader.visibility = View.GONE
+ Utils.hideKeyboard(context, etNewLeader)
+ showRecyclerView(true)
+ nameLisAdapter.submitList(leaders)
+ }
+ }
+
+ fun showRecyclerView(isShow: Boolean) {
+ if (isShow) {
+ rootView.rv_name.visibility = View.VISIBLE
+ rootView.tvAddLeader.visibility = View.GONE
+ } else {
+ rootView.rv_name.visibility = View.GONE
+ rootView.tvAddLeader.visibility = View.VISIBLE
+ }
+
+ }
+
+ @Optional
+ @OnClick(R.id.btnCancelAddLeader)
+ fun cancelLeaderAddition() {
+ etNewLeader.text.clear()
+ llAddLeader.visibility = View.GONE
+ }
+
+ override fun onSelected() {
+ }
+
+ override fun verifyStep(): VerificationError? {
+ if (leaders.size == 0) {
+ Toast.makeText(context, getString(R.string.error_group_atleast_1_member), Toast.LENGTH_SHORT).show()
+ return VerificationError("")
+ }
+ (activity as CreateGroupActivity).setLeaders(leaders)
+ return null
+ }
+
+ override fun onError(error: VerificationError) {
+
+ }
+
+ override fun onEditClicked(position: Int) {
+ editItemPosition = position
+ showAddLeaderView(GroupAction.EDIT, leaders[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, leaders[position]))
+ setPositiveButton(getString(R.string.delete)
+ ) { dialog: DialogInterface?, _ ->
+ leaders.removeAt(position)
+ nameLisAdapter.submitList(leaders)
+ if (leaders.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/online/groups/creategroup/AddGroupMemberStepFragment.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/AddGroupMemberStepFragment.kt
new file mode 100644
index 0000000..b7fe562
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/AddGroupMemberStepFragment.kt
@@ -0,0 +1,178 @@
+package org.apache.fineract.ui.online.groups.creategroup
+
+import android.content.DialogInterface
+import android.os.Bundle
+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_group_member.*
+import kotlinx.android.synthetic.main.fragment_step_add_group_member.view.*
+import org.apache.fineract.R
+import org.apache.fineract.ui.adapters.NameListAdapter
+import org.apache.fineract.ui.base.FineractBaseActivity
+import org.apache.fineract.ui.base.FineractBaseFragment
+import org.apache.fineract.ui.online.groups.GroupAction
+import org.apache.fineract.utils.Constants
+import org.apache.fineract.utils.MaterialDialog
+import org.apache.fineract.utils.Utils
+import javax.inject.Inject
+
+
+/*
+ * Created by saksham on 02/July/2019
+*/
+
+class AddGroupMemberStepFragment : FineractBaseFragment(), Step, NameListAdapter.OnItemClickListener {
+
+ lateinit var rootView: View
+ var members: ArrayList<String> = ArrayList()
+ private var currentAction = GroupAction.CREATE
+ private var editItemPosition = 0
+ private lateinit var groupAction: GroupAction
+
+ @Inject
+ lateinit var nameLisAdapter: NameListAdapter
+
+ companion object {
+ fun newInstance(groupAction: GroupAction) = AddGroupMemberStepFragment().apply {
+ val bundle = Bundle().apply {
+ putSerializable(Constants.GROUP_ACTION, groupAction)
+ }
+ arguments = bundle
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ arguments?.getSerializable(Constants.GROUP_ACTION)?.let {
+ groupAction = it as GroupAction
+ }
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ rootView = inflater.inflate(R.layout.fragment_step_add_group_member, container, false)
+ ButterKnife.bind(this, rootView)
+ (activity as FineractBaseActivity).activityComponent.inject(this)
+ rootView.rv_name.adapter = nameLisAdapter
+ nameLisAdapter.setOnItemClickListener(this)
+ if (groupAction == GroupAction.EDIT) {
+ showDataOnViews()
+ }
+ return rootView
+ }
+
+ private fun showDataOnViews() {
+ val group = (activity as CreateGroupActivity).getGroup()
+ members = group.members as ArrayList<String>
+ if (members.size == 0) {
+ showRecyclerView(false)
+ } else {
+ showRecyclerView(true)
+ }
+ nameLisAdapter.submitList(members)
+ }
+
+ @Optional
+ @OnClick(R.id.ibAddMember)
+ fun showAddMemberView() {
+ showAddMemberView(GroupAction.CREATE, null)
+ }
+
+ private fun showAddMemberView(action: GroupAction, name: String?) {
+ currentAction = action
+ llAddMember.visibility = View.VISIBLE
+ when (action) {
+ GroupAction.CREATE -> {
+ btnAddMember.text = getString(R.string.add)
+ }
+ GroupAction.EDIT -> {
+ etNewMember.setText(name)
+ btnAddMember.text = getString(R.string.update)
+ }
+ }
+ }
+
+ @Optional
+ @OnClick(R.id.btnAddMember)
+ fun addMember() {
+ if (etNewMember.validator()
+ .nonEmpty()
+ .noNumbers()
+ .addErrorCallback { etNewMember.error = it }.check()) {
+ if (currentAction == GroupAction.CREATE) {
+ members.add(etNewMember.text.toString())
+ } else {
+ members[editItemPosition] = etNewMember.text.toString()
+ }
+ etNewMember.text.clear()
+ llAddMember.visibility = View.GONE
+ Utils.hideKeyboard(context, etNewMember)
+ showRecyclerView(true)
+ nameLisAdapter.submitList(members)
+ }
+ }
+
+ fun showRecyclerView(isShow: Boolean) {
+ if (isShow) {
+ rootView.rv_name.visibility = View.VISIBLE
+ rootView.tvAddedMember.visibility = View.GONE
+ } else {
+ rootView.rv_name.visibility = View.GONE
+ rootView.tvAddedMember.visibility = View.VISIBLE
+ }
+
+ }
+
+ @Optional
+ @OnClick(R.id.btnCancelAddMember)
+ fun cancelMemberAddition() {
+ etNewMember.text.clear()
+ llAddMember.visibility = View.GONE
+ }
+
+ override fun onSelected() {
+ }
+
+ override fun verifyStep(): VerificationError? {
+ if (members.size == 0) {
+ Toast.makeText(context, getString(R.string.error_group_atleast_1_member), Toast.LENGTH_SHORT).show()
+ return VerificationError("")
+ }
+ (activity as CreateGroupActivity).setMembers(members)
+ return null
+ }
+
+ override fun onError(error: VerificationError) {
+
+ }
+
+ override fun onEditClicked(position: Int) {
+ editItemPosition = position
+ showAddMemberView(GroupAction.EDIT, members[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, members[position]))
+ setPositiveButton(getString(R.string.delete)
+ ) { dialog: DialogInterface?, _ ->
+ members.removeAt(position)
+ nameLisAdapter.submitList(members)
+ if (members.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/online/groups/creategroup/CreateGroupActivity.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/CreateGroupActivity.kt
new file mode 100644
index 0000000..00e5a8a
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/CreateGroupActivity.kt
@@ -0,0 +1,138 @@
+package org.apache.fineract.ui.online.groups.creategroup
+
+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_group.*
+import org.apache.fineract.R
+import org.apache.fineract.data.Status
+import org.apache.fineract.data.models.Group
+import org.apache.fineract.data.models.customer.Address
+import org.apache.fineract.ui.base.FineractBaseActivity
+import org.apache.fineract.ui.base.Toaster
+import org.apache.fineract.ui.online.groups.GroupAction
+import org.apache.fineract.ui.online.groups.grouplist.GroupViewModelFactory
+import org.apache.fineract.ui.online.groups.grouplist.GroupViewModel
+import org.apache.fineract.utils.Constants
+import org.apache.fineract.utils.DateUtils
+import javax.inject.Inject
+
+/*
+ * Created by saksham on 02/July/2019
+*/
+
+class CreateGroupActivity : FineractBaseActivity(), StepperLayout.StepperListener {
+
+ private var group = Group()
+ private var groupAction = GroupAction.CREATE
+
+ @Inject
+ lateinit var groupViewModelFactory: GroupViewModelFactory
+
+ lateinit var viewModel: GroupViewModel
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_create_group)
+ activityComponent.inject(this)
+ groupAction = intent.getSerializableExtra(Constants.GROUP_ACTION) as GroupAction
+ when (groupAction) {
+ GroupAction.CREATE -> {
+ setToolbarTitle(getString(R.string.create_group))
+ }
+ GroupAction.EDIT -> {
+ setToolbarTitle(getString(R.string.edit_group))
+ intent?.extras?.getParcelable<Group>(Constants.GROUP)?.let {
+ group = it
+ }
+ }
+ }
+ viewModel = ViewModelProviders.of(this, groupViewModelFactory).get(GroupViewModel::class.java)
+ subscribeUI()
+ showBackButton()
+ slCreateGroup.adapter = CreateGroupAdapter(supportFragmentManager, this, groupAction)
+ slCreateGroup.setOffscreenPageLimit(slCreateGroup.adapter.count)
+ slCreateGroup.setListener(this)
+ }
+
+ override fun onStepSelected(newStepPosition: Int) {}
+
+ override fun onError(verificationError: VerificationError?) {}
+
+ override fun onReturn() {}
+
+ private fun subscribeUI() {
+ viewModel.status.observe(this, Observer { status ->
+ when (status) {
+ Status.LOADING ->
+ if (groupAction == GroupAction.CREATE) {
+ showMifosProgressDialog(getString(R.string.create_group))
+ } else {
+ showMifosProgressDialog(getString(R.string.updating_group_please_wait))
+ }
+ Status.ERROR -> {
+ hideMifosProgressDialog()
+ if (groupAction == GroupAction.CREATE) {
+ Toaster.show(findViewById(android.R.id.content), R.string.error_while_creating_group, Toast.LENGTH_SHORT)
+ } else {
+ Toaster.show(findViewById(android.R.id.content), R.string.error_while_updating_group_status, Toast.LENGTH_SHORT)
+ }
+ }
+ Status.DONE -> {
+ hideMifosProgressDialog()
+ if (groupAction == GroupAction.CREATE) {
+ Toast.makeText(this, getString(R.string.group_identifier_updated_successfully, group.identifier), Toast.LENGTH_SHORT).show()
+ } else {
+ Toast.makeText(this, getString(R.string.group_identifier_updated_successfully, group.identifier), Toast.LENGTH_SHORT).show()
+ }
+ finish()
+ }
+ }
+ })
+ }
+
+ override fun onCompleted(completeButton: View?) {
+ when (groupAction) {
+ GroupAction.EDIT -> group.identifier?.let {
+ viewModel.updateGroup(it, group)
+ }
+ GroupAction.CREATE -> viewModel.createGroup(group)
+ }
+ }
+
+ fun setGroupDetails(identifier: String, groupDefinitionIdentifier: String, name: String, office: String, assignedEmployee: String) {
+ group.identifier = identifier
+ group.groupDefinitionIdentifier = groupDefinitionIdentifier
+ group.name = name
+ group.office = office
+ group.assignedEmployee = assignedEmployee
+ group.weekday = DateUtils.getWeekDayIndex(DateUtils.getPresentDay())
+ }
+
+ fun setMembers(members: List<String>) {
+ group.members = members
+ }
+
+ fun setLeaders(leaders: List<String>) {
+ group.leaders = leaders
+ }
+
+ fun setGroupAddress(street: String, city: String, region: String, postalCode: String, country: String, countryCode: String?) {
+ val address = Address()
+ address.street = street
+ address.city = city
+ address.region = region
+ address.postalCode = postalCode
+ address.country = country
+ address.countryCode = countryCode
+ group.address = address
+ }
+
+ fun getGroup(): Group {
+ return group
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/CreateGroupAdapter.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/CreateGroupAdapter.kt
new file mode 100644
index 0000000..c90627a
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/CreateGroupAdapter.kt
@@ -0,0 +1,41 @@
+package org.apache.fineract.ui.online.groups.creategroup
+
+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.online.groups.GroupAction
+
+
+/*
+ * Created by saksham on 02/July/2019
+*/
+
+class CreateGroupAdapter constructor(fm: FragmentManager,
+ context: Context,
+ val groupAction: GroupAction)
+ : AbstractFragmentStepAdapter(fm, context) {
+
+ private var createGroupSteps = context.resources.getStringArray(R.array.create_group_steps)
+
+ override fun getCount(): Int {
+ return createGroupSteps.size
+ }
+
+ override fun createStep(position: Int): Step? {
+ when (position) {
+ 0 -> return GroupDetailsStepFragment.newInstance(groupAction)
+ 1 -> return AddGroupMemberStepFragment.newInstance(groupAction)
+ 2 -> return AddGroupLeaderStepFragment.newInstance(groupAction)
+ 3 -> return GroupAddressStepFragment.newInstance(groupAction)
+ 4 -> return GroupReviewStepFragment.newInstance()
+ }
+ return null
+ }
+
+ override fun getViewModel(position: Int): StepViewModel {
+ return StepViewModel.Builder(context).setTitle(createGroupSteps[position]).create()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupAddressStepFragment.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupAddressStepFragment.kt
new file mode 100644
index 0000000..533ffb5
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupAddressStepFragment.kt
@@ -0,0 +1,154 @@
+package org.apache.fineract.ui.online.groups.creategroup
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import android.widget.Toast
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProviders
+import com.stepstone.stepper.Step
+import com.stepstone.stepper.VerificationError
+import com.wajahatkarim3.easyvalidation.core.rules.BaseRule
+import com.wajahatkarim3.easyvalidation.core.view_ktx.validator
+import kotlinx.android.synthetic.main.fragment_step_group_address.*
+import org.apache.fineract.R
+import org.apache.fineract.data.models.customer.Country
+import org.apache.fineract.ui.base.FineractBaseActivity
+import org.apache.fineract.ui.base.FineractBaseFragment
+import org.apache.fineract.ui.online.groups.GroupAction
+import org.apache.fineract.ui.online.groups.grouplist.GroupViewModelFactory
+import org.apache.fineract.ui.online.groups.grouplist.GroupViewModel
+import org.apache.fineract.utils.Constants
+import javax.inject.Inject
+
+
+/*
+ * Created by saksham on 03/July/2019
+*/
+
+class GroupAddressStepFragment : FineractBaseFragment(), Step {
+
+ lateinit var rootView: View
+ lateinit var countries: List<Country>
+ lateinit var viewModel: GroupViewModel
+ private lateinit var groupAction: GroupAction
+
+ @Inject
+ lateinit var groupViewModelFactory: GroupViewModelFactory
+
+ companion object {
+ fun newInstance(groupAction: GroupAction) = GroupAddressStepFragment().apply {
+ arguments = Bundle().apply {
+ putSerializable(Constants.GROUP_ACTION, groupAction)
+ }
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ arguments?.getSerializable(Constants.GROUP_ACTION)?.let {
+ groupAction = it as GroupAction
+ }
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ rootView = inflater.inflate(R.layout.fragment_step_group_address, container, false)
+ (activity as FineractBaseActivity).activityComponent.inject(this)
+ viewModel = ViewModelProviders.of(this,
+ groupViewModelFactory).get(GroupViewModel::class.java)
+ return rootView
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ viewModel.getCountries().observe(this, Observer {
+ countries = it
+ etCountry.setAdapter(ArrayAdapter(context, android.R.layout.simple_list_item_1, viewModel.getCountryNames(it)))
+ })
+ etCountry.threshold = 1
+
+ if (groupAction == GroupAction.EDIT) {
+ showDataOnViews()
+ }
+ }
+
+ private fun showDataOnViews() {
+ val group = (activity as CreateGroupActivity).getGroup()
+ etStreet.setText(group.address?.street)
+ etCity.setText(group.address?.city)
+ etRegion.setText(group.address?.region)
+ etPostalCode.setText(group.address?.postalCode)
+ etCountry.setText(group.address?.country)
+ }
+
+ override fun onSelected() {
+
+ }
+
+ override fun verifyStep(): VerificationError? {
+ if (!validateStreet() || !validateCity() || !validateRegion() || !validatePostalCode() || !validateCountry()) {
+ return VerificationError("")
+ }
+ (activity as CreateGroupActivity).setGroupAddress(etStreet.text.toString(), etCity.text.toString(), etRegion.text.toString(),
+ etPostalCode.text.toString(), etCountry.text.toString(), viewModel.getCountryCode(countries, etCountry.text.toString()))
+ return null
+ }
+
+ override fun onError(error: VerificationError) {
+
+ }
+
+ private fun validateStreet(): Boolean {
+ return etStreet.validator()
+ .nonEmpty()
+ .addErrorCallback {
+ etStreet.error = it
+ }
+ .check()
+ }
+
+ private fun validateCity(): Boolean {
+ return etCity.validator()
+ .nonEmpty()
+ .addErrorCallback {
+ etCity.error = it
+ }.check()
+ }
+
+ private fun validateRegion(): Boolean {
+ return etRegion.validator()
+ .nonEmpty()
+ .addErrorCallback {
+ etRegion.error = it
+ }.check()
+ }
+
+ private fun validatePostalCode(): Boolean {
+ return etPostalCode.validator()
+ .nonEmpty()
+ .onlyNumbers()
+ .addErrorCallback {
+ etPostalCode.error = it
+ }.check()
+ }
+
+ private fun validateCountry(): Boolean {
+ return etCountry.validator()
+ .nonEmpty()
+ .noNumbers()
+ .addRule(object : BaseRule {
+ override fun validate(text: String): Boolean {
+ return viewModel.isCountryValid(countries, etCountry.text.toString())
+ }
+
+ override fun getErrorMessage(): String {
+ return getString(R.string.invalid_country)
+ }
+ })
+ .addErrorCallback {
+ Toast.makeText(context, it, Toast.LENGTH_SHORT).show()
+ }.check()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupDetailsStepFragment.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupDetailsStepFragment.kt
new file mode 100644
index 0000000..ce57706
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupDetailsStepFragment.kt
@@ -0,0 +1,124 @@
+package org.apache.fineract.ui.online.groups.creategroup
+
+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_group_details.*
+import kotlinx.android.synthetic.main.fragment_step_group_details.view.*
+import org.apache.fineract.R
+import org.apache.fineract.ui.base.FineractBaseActivity
+import org.apache.fineract.ui.base.FineractBaseFragment
+import org.apache.fineract.ui.online.groups.GroupAction
+import org.apache.fineract.utils.Constants
+
+
+/*
+ * Created by saksham on 02/July/2019
+*/
+
+class GroupDetailsStepFragment : FineractBaseFragment(), Step {
+
+ lateinit var rootView: View
+ private lateinit var groupAction: GroupAction
+
+ companion object {
+ fun newInstance(groupAction: GroupAction) =
+ GroupDetailsStepFragment().apply {
+ val bundle = Bundle().apply {
+ putSerializable(Constants.GROUP_ACTION, groupAction)
+ }
+ arguments = bundle
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ arguments?.getSerializable(Constants.GROUP_ACTION)?.let {
+ groupAction = it as GroupAction
+ }
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ rootView = inflater.inflate(R.layout.fragment_step_group_details, container, false)
+ if (groupAction == GroupAction.EDIT) {
+ showDataOnViews()
+ }
+ return rootView
+ }
+
+ private fun showDataOnViews() {
+ val group = (activity as CreateGroupActivity).getGroup()
+ rootView.etIdentifier.setText(group.identifier)
+ rootView.etIdentifier.isEnabled = false
+ rootView.etGroupDefinitionIdentifier.setText(group.groupDefinitionIdentifier)
+ rootView.etName.setText(group.name)
+ rootView.etOffice.setText(group.office)
+ rootView.etAssignedEmployee.setText(group.assignedEmployee)
+ }
+
+ override fun onSelected() {}
+
+ override fun verifyStep(): VerificationError? {
+ if (!validateIdentifier() || !validateGroupDefinitionIdentifier() || !validateName()
+ || !validateOffice() || !validateAssignedEmployee()) {
+ return VerificationError(null)
+ }
+ (activity as CreateGroupActivity).setGroupDetails(etIdentifier.text.toString(),
+ etGroupDefinitionIdentifier.text.toString(),
+ etName.text.toString(),
+ etOffice.text.toString(),
+ etAssignedEmployee.text.toString())
+ return null
+ }
+
+ override fun onError(error: VerificationError) {
+ }
+
+ private fun validateIdentifier(): Boolean {
+ return etIdentifier.validator()
+ .minLength(5)
+ .addErrorCallback {
+ etIdentifier.error = it
+ }.check()
+ }
+
+ private fun validateGroupDefinitionIdentifier(): Boolean {
+ return etGroupDefinitionIdentifier.validator()
+ .minLength(5)
+ .addErrorCallback {
+ etGroupDefinitionIdentifier.error = it
+ }.check()
+ }
+
+ private fun validateName(): Boolean {
+ return etName.validator()
+ .minLength(5)
+ .noNumbers()
+ .addErrorCallback {
+ etName.error = it
+ }.check()
+ }
+
+ private fun validateOffice(): Boolean {
+ return etOffice.validator()
+ .minLength(5)
+ .noNumbers()
+ .addErrorCallback {
+ etOffice.error = it
+ }.check()
+ }
+
+ private fun validateAssignedEmployee(): Boolean {
+ return etAssignedEmployee.validator()
+ .minLength(5)
+ .noNumbers()
+ .addErrorCallback {
+ etAssignedEmployee.error = it
+ }
+ .check()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupModelHelper.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupModelHelper.kt
new file mode 100644
index 0000000..d3380f5
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupModelHelper.kt
@@ -0,0 +1,25 @@
+package org.apache.fineract.ui.online.groups.creategroup
+
+
+/*
+ * Created by saksham on 04/July/2019
+*/
+
+interface GroupModelHelper {
+
+ interface GroupDetails {
+
+ }
+
+ interface GroupMemberDetails {
+
+ }
+
+ interface GroupLeaderDetails {
+
+ }
+
+ interface GroupAddress {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupReviewStepFragment.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupReviewStepFragment.kt
new file mode 100644
index 0000000..559f132
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/creategroup/GroupReviewStepFragment.kt
@@ -0,0 +1,84 @@
+package org.apache.fineract.ui.online.groups.creategroup
+
+import android.os.Build
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.TextView
+import android.widget.Toast
+import androidx.recyclerview.widget.DividerItemDecoration
+import com.stepstone.stepper.Step
+import com.stepstone.stepper.VerificationError
+import kotlinx.android.synthetic.main.fragment_step_add_group_member.view.*
+import kotlinx.android.synthetic.main.fragment_step_group_review.*
+import kotlinx.android.synthetic.main.fragment_step_group_review.view.*
+import org.apache.fineract.R
+import org.apache.fineract.data.models.Group
+import org.apache.fineract.ui.adapters.NameListAdapter
+import org.apache.fineract.ui.base.FineractBaseActivity
+import org.apache.fineract.ui.base.FineractBaseFragment
+import javax.inject.Inject
+
+
+/*
+ * Created by saksham on 04/July/2019
+*/
+
+class GroupReviewStepFragment : FineractBaseFragment(), Step {
+
+ lateinit var rootView: View
+
+ @Inject
+ lateinit var memberNameAdapter: NameListAdapter
+
+ @Inject
+ lateinit var leaderNameAdapter: NameListAdapter
+
+ companion object {
+ fun newInstance(): GroupReviewStepFragment {
+ return GroupReviewStepFragment()
+ }
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ rootView = inflater.inflate(R.layout.fragment_step_group_review, container, false)
+ (activity as FineractBaseActivity).activityComponent.inject(this)
+ rootView.rv_leaders.adapter = leaderNameAdapter
+ leaderNameAdapter.setReview(true)
+ rootView.rv_members.adapter = memberNameAdapter
+ memberNameAdapter.setReview(true)
+
+ return rootView
+ }
+
+ private fun populateView(group: Group) {
+ tvIdentifier.text = group.identifier
+ tvGroupDefinitionIdentifier.text = group.groupDefinitionIdentifier
+ tvName.text = group.name
+ tvOffice.text = group.office
+ tvAssignedEmployee.text = group.assignedEmployee
+ group.members?.let {
+ memberNameAdapter.submitList(it as ArrayList<String>)
+ }
+ group.leaders?.let {
+ leaderNameAdapter.submitList(it as ArrayList<String>)
+ }
+ tvStreet.text = group.address?.street
+ tvCity.text = group.address?.city
+ tvRegion.text = group.address?.region
+ tvPostalCode.text = group.address?.postalCode
+ tvCountry.text = group.address?.country
+ }
+
+ override fun onSelected() {
+ populateView((activity as CreateGroupActivity).getGroup())
+ }
+
+ override fun verifyStep(): VerificationError? {
+ return null
+ }
+
+ override fun onError(error: VerificationError) {}
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/groupdetails/GroupDetailsActivity.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/groupdetails/GroupDetailsActivity.kt
new file mode 100644
index 0000000..0300dd2
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/groupdetails/GroupDetailsActivity.kt
@@ -0,0 +1,26 @@
+package org.apache.fineract.ui.online.groups.groupdetails
+
+import android.os.Bundle
+import android.os.PersistableBundle
+import android.util.Log
+import android.widget.Toast
+import org.apache.fineract.R
+import org.apache.fineract.data.models.Group
+import org.apache.fineract.ui.base.FineractBaseActivity
+import org.apache.fineract.utils.Constants
+
+
+/*
+ * Created by saksham on 21/June/2019
+*/
+
+class GroupDetailsActivity : FineractBaseActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_toolbar_container)
+
+ replaceFragment(GroupDetailsFragment.newInstance(intent.getParcelableExtra(Constants.GROUP)), false, R.id.container)
+ showBackButton()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/groupdetails/GroupDetailsFragment.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/groupdetails/GroupDetailsFragment.kt
new file mode 100644
index 0000000..7095ac0
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/groupdetails/GroupDetailsFragment.kt
@@ -0,0 +1,133 @@
+package org.apache.fineract.ui.online.groups.groupdetails
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.*
+import butterknife.ButterKnife
+import butterknife.OnClick
+import kotlinx.android.synthetic.main.fragment_groups_details.*
+import kotlinx.android.synthetic.main.fragment_groups_details.view.*
+import org.apache.fineract.R
+import org.apache.fineract.data.models.Group
+import org.apache.fineract.ui.adapters.NameListAdapter
+import org.apache.fineract.ui.base.FineractBaseActivity
+import org.apache.fineract.ui.base.FineractBaseFragment
+import org.apache.fineract.ui.online.groups.GroupAction
+import org.apache.fineract.ui.online.groups.creategroup.CreateGroupActivity
+import org.apache.fineract.ui.online.groups.grouptasks.GroupTasksBottomSheetFragment
+import org.apache.fineract.ui.views.CircularImageView
+import org.apache.fineract.utils.Constants
+import org.apache.fineract.utils.DateUtils
+import org.apache.fineract.utils.Utils
+import javax.inject.Inject
+
+
+/*
+ * Created by saksham on 22/June/2019
+*/
+
+class GroupDetailsFragment : FineractBaseFragment() {
+
+ lateinit var rootView: View
+ lateinit var group: Group
+
+ @Inject
+ lateinit var membersNameAdapter: NameListAdapter
+
+ @Inject
+ lateinit var leadersNameAdapter: NameListAdapter
+
+ companion object {
+ fun newInstance(group: Group): GroupDetailsFragment {
+ val fragment = GroupDetailsFragment()
+ val args = Bundle()
+ args.putParcelable(Constants.GROUP, group)
+ fragment.arguments = args
+ return fragment
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ group = arguments?.get(Constants.GROUP) as Group
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ rootView = inflater.inflate(R.layout.fragment_groups_details, container, false)
+ (activity as FineractBaseActivity).activityComponent.inject(this)
+ ButterKnife.bind(this, rootView)
+ rootView.rv_members.adapter = membersNameAdapter
+ membersNameAdapter.setReview(true)
+ rootView.rv_leaders.adapter = leadersNameAdapter
+ leadersNameAdapter.setReview(true)
+ setToolbarTitle(group.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_group_detials, menu)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.menu_edit_group -> {
+ val intent = Intent(activity, CreateGroupActivity::class.java).apply {
+ putExtra(Constants.GROUP, group)
+ putExtra(Constants.GROUP_ACTION, GroupAction.EDIT)
+ }
+ startActivity(intent)
+ }
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ tvIdentifier.text = group.identifier
+ tvGroupId.text = group.groupDefinitionIdentifier
+ tvName.text = group.name
+ tvStatus.text = group.status?.name
+ setGroupStatusCircularIcon(group.status, civStatus)
+ group.leaders?.let {
+ leadersNameAdapter.submitList(it as ArrayList<String>)
+ }
+ group.members?.let {
+ membersNameAdapter.submitList(it as ArrayList<String>)
+ }
+ tvOffice.text = group.office
+ tvAssignedEmployee.text = group.assignedEmployee
+ tvWeekday.text = DateUtils.getWeekDay(group.weekday!!)
+ tvStreet.text = group.address?.street
+ tvCity.text = group.address?.city
+ tvRegion.text = group.address?.region
+ tvPostalCode.text = group.address?.postalCode
+ tvCountry.text = group.address?.country
+ }
+
+ @OnClick(R.id.cv_tasks)
+ fun onTasksCardViewClicked() {
+ val bottomSheet = GroupTasksBottomSheetFragment(group)
+ bottomSheet.show(childFragmentManager, getString(R.string.tasks))
+ }
+
+ private fun setGroupStatusCircularIcon(status: Group.Status?, civStatus: CircularImageView) {
+ when (status) {
+ Group.Status.PENDING -> {
+ civStatus.setImageDrawable(Utils.setCircularBackground(R.color.blue, context))
+ }
+ Group.Status.ACTIVE -> {
+ civStatus.setImageDrawable(Utils.setCircularBackground(R.color.deposit_green, context))
+ }
+ Group.Status.CLOSED -> {
+ civStatus.setImageDrawable(Utils.setCircularBackground(R.color.red_dark, context))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/grouplist/GroupListFragment.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/grouplist/GroupListFragment.kt
new file mode 100644
index 0000000..448554b
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/grouplist/GroupListFragment.kt
@@ -0,0 +1,133 @@
+package org.apache.fineract.ui.online.groups.grouplist
+
+import android.app.SearchManager
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.*
+import androidx.appcompat.widget.SearchView
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProviders
+import androidx.recyclerview.widget.LinearLayoutManager
+import butterknife.ButterKnife
+import butterknife.OnClick
+import kotlinx.android.synthetic.main.fragment_group_list.*
+import org.apache.fineract.R
+import org.apache.fineract.data.models.Group
+import org.apache.fineract.ui.adapters.GroupsAdapter
+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.GroupAction
+import org.apache.fineract.ui.online.groups.creategroup.CreateGroupActivity
+import org.apache.fineract.ui.online.groups.groupdetails.GroupDetailsActivity
+import org.apache.fineract.utils.Constants
+import javax.inject.Inject
+
+
+/*
+ * Created by saksham on 15/June/2019
+*/
+
+class GroupListFragment : FineractBaseFragment(), OnItemClickListener {
+
+ lateinit var rootView: View
+
+ lateinit var viewModel: GroupViewModel
+
+ @Inject
+ lateinit var adapter: GroupsAdapter
+
+ @Inject
+ lateinit var groupViewModelFactory: GroupViewModelFactory
+
+ lateinit var groupList: ArrayList<Group>
+
+ val searchedGroup: (ArrayList<Group>) -> Unit = { groups ->
+ adapter.setGroupList(groups)
+ }
+
+ companion object {
+ fun newInstance(): GroupListFragment {
+ return GroupListFragment()
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setHasOptionsMenu(true)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ rootView = inflater.inflate(R.layout.fragment_group_list, container, false)
+ (activity as FineractBaseActivity).activityComponent.inject(this)
+ viewModel = ViewModelProviders.of(this,
+ groupViewModelFactory).get(GroupViewModel::class.java)
+ return rootView
+ }
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ ButterKnife.bind(this, rootView)
+ adapter.setItemClickListener(this)
+
+ rvGroups.adapter = adapter
+ rvGroups.layoutManager = LinearLayoutManager(context)
+ viewModel.getGroups().observe(this,
+
+ Observer {
+ groupList = it
+ adapter.setGroupList(it)
+ })
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ super.onCreateOptionsMenu(menu, inflater)
+ inflater.inflate(R.menu.menu_group_search, menu)
+
+ val searchManager = activity?.getSystemService(Context.SEARCH_SERVICE) as SearchManager
+ val searchView = menu.findItem(R.id.group_search).actionView as SearchView
+
+ searchView.setSearchableInfo(searchManager.getSearchableInfo(activity?.componentName))
+
+ searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
+ override fun onQueryTextSubmit(query: String): Boolean {
+ viewModel.searchGroup(groupList, query, searchedGroup)
+ return false
+ }
+
+ override fun onQueryTextChange(newText: String): Boolean {
+ if (TextUtils.isEmpty(newText)) {
+ adapter.setGroupList(groupList)
+ }
+ viewModel.searchGroup(groupList, newText, searchedGroup)
+ return true
+ }
+ })
+ }
+
+ override fun onItemClick(childView: View?, position: Int) {
+ val intent = Intent(context, GroupDetailsActivity::class.java).apply {
+ putExtra(Constants.GROUP, groupList[position])
+ }
+ startActivity(intent)
+ }
+
+ override fun onItemLongPress(childView: View?, position: Int) {
+ }
+
+ @OnClick(R.id.fabAddGroup)
+ fun addGroup() {
+ val intent = Intent(activity, CreateGroupActivity::class.java).apply {
+ putExtra(Constants.GROUP_ACTION, GroupAction.CREATE)
+ }
+ startActivity(intent)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/grouplist/GroupViewModel.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/grouplist/GroupViewModel.kt
new file mode 100644
index 0000000..6f9f159
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/grouplist/GroupViewModel.kt
@@ -0,0 +1,130 @@
+package org.apache.fineract.ui.online.groups.grouplist
+
+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.functions.Predicate
+import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
+import org.apache.fineract.data.Status
+import org.apache.fineract.data.datamanager.api.DataManagerAnonymous
+import org.apache.fineract.data.datamanager.api.DataManagerGroups
+import org.apache.fineract.data.models.Group
+import org.apache.fineract.data.models.customer.Command
+import org.apache.fineract.data.models.customer.Country
+
+/*
+ * Created by saksham on 15/June/2019
+*/
+
+class GroupViewModel constructor(val dataManagerGroups: DataManagerGroups, val dataManagerAnonymous: DataManagerAnonymous) : ViewModel() {
+
+ lateinit var groupsList: MutableLiveData<ArrayList<Group>>
+ 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<Status>()
+ val status: LiveData<Status>
+ get() = _status
+
+ fun getGroups(): MutableLiveData<ArrayList<Group>> {
+ groupsList = dataManagerGroups.getGroups()
+ return groupsList
+ }
+
+ fun searchGroup(groups: ArrayList<Group>, query: String, searchedGroup: (ArrayList<Group>) -> Unit) {
+ searchedGroup(ArrayList(Observable.fromIterable(groups).filter(object : Predicate<Group> {
+ override fun test(group: Group): Boolean {
+ return group.identifier?.toLowerCase()?.contains(query.toLowerCase()).toString().toBoolean()
+ }
+ }).toList().blockingGet()))
+ }
+
+ @SuppressLint("CheckResult")
+ fun getCountries(): MutableLiveData<List<Country>> {
+ val countries = MutableLiveData<List<Country>>()
+ dataManagerAnonymous.countries.subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe {
+ countries.value = it
+ }
+ return countries
+ }
+
+ fun createGroup(group: Group) {
+ uiScope.launch {
+ withContext(Dispatchers.Main) {
+ try {
+ _status.value = Status.LOADING
+ dataManagerGroups.createGroup(group).await()
+ _status.value = Status.DONE
+ } catch (e: Exception) {
+ _status.value = Status.ERROR
+ }
+ }
+ }
+ }
+
+ fun updateGroup(identifier: String, group: Group) {
+ uiScope.launch {
+ withContext(Dispatchers.Main) {
+ try {
+ _status.value = Status.LOADING
+ dataManagerGroups.updateGroup(identifier, group).await()
+ _status.value = Status.DONE
+ } catch (e: Exception) {
+ _status.value = Status.ERROR
+ }
+ }
+ }
+ }
+
+ fun changeGroupStatus(identifier: String, command: Command) {
+ uiScope.launch {
+ withContext(Dispatchers.Main) {
+ try {
+ _status.value = Status.LOADING
+ dataManagerGroups.changeGroupStatus(identifier, command).await()
+ _status.value = Status.DONE
+ } catch (e: Exception) {
+ _status.value = Status.ERROR
+ }
+ }
+ }
+ }
+
+ fun getCountryNames(countries: List<Country>): List<String> {
+ return Observable.fromIterable(countries).map { country: Country -> country.name }.toList().blockingGet()
+ }
+
+ fun getCountryCode(countries: List<Country>, countryName: String): String? {
+ for (country in countries) {
+ if (country.name.equals(countryName)) {
+ return country.alphaCode
+ }
+ }
+ return null
+ }
+
+ fun isCountryValid(countries: List<Country>, countryName: String): Boolean {
+ for (country in countries) {
+ if (country.name.equals(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()
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/grouplist/GroupViewModelFactory.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/grouplist/GroupViewModelFactory.kt
new file mode 100644
index 0000000..f541a37
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/grouplist/GroupViewModelFactory.kt
@@ -0,0 +1,25 @@
+package org.apache.fineract.ui.online.groups.grouplist
+
+import android.content.Context
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import org.apache.fineract.data.datamanager.api.DataManagerAnonymous
+import org.apache.fineract.data.datamanager.api.DataManagerGroups
+import org.apache.fineract.injection.ApplicationContext
+import javax.inject.Inject
+
+
+/*
+ * Created by saksham on 16/June/2019
+*/
+
+
+class GroupViewModelFactory @Inject constructor(@ApplicationContext var context: Context,
+ private val dataManagerGroups: DataManagerGroups,
+ private val dataManagerAnonymous: DataManagerAnonymous)
+ : ViewModelProvider.NewInstanceFactory() {
+
+ override fun <T : ViewModel?> create(modelClass: Class<T>): T {
+ return GroupViewModel(dataManagerGroups, dataManagerAnonymous) as T
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/ui/online/groups/grouptasks/GroupTasksBottomSheetFragment.kt b/app/src/main/java/org/apache/fineract/ui/online/groups/grouptasks/GroupTasksBottomSheetFragment.kt
new file mode 100644
index 0000000..76c601d
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/ui/online/groups/grouptasks/GroupTasksBottomSheetFragment.kt
@@ -0,0 +1,144 @@
+package org.apache.fineract.ui.online.groups.grouptasks
+
+import android.app.Dialog
+import android.os.Bundle
+import android.view.View
+import android.widget.Toast
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProviders
+import butterknife.ButterKnife
+import butterknife.OnClick
+import com.google.android.material.bottomsheet.BottomSheetBehavior
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import kotlinx.android.synthetic.main.fragment_group_tasks_bottom_sheet.view.*
+import org.apache.fineract.R
+import org.apache.fineract.data.Status
+import org.apache.fineract.data.models.Group
+import org.apache.fineract.data.models.customer.Command
+import org.apache.fineract.ui.base.FineractBaseActivity
+import org.apache.fineract.ui.base.FineractBaseBottomSheetDialogFragment
+import org.apache.fineract.ui.base.Toaster
+import org.apache.fineract.ui.online.groups.grouplist.GroupViewModel
+import org.apache.fineract.ui.online.groups.grouplist.GroupViewModelFactory
+import javax.inject.Inject
+
+/**
+ * Created by Ahmad Jawid Muhammadi on 04/April/2020
+ */
+class GroupTasksBottomSheetFragment(val group: Group) : FineractBaseBottomSheetDialogFragment() {
+
+ lateinit var rootView: View
+ private var command = Command()
+ lateinit var behavior: BottomSheetBehavior<*>
+ private lateinit var viewModel: GroupViewModel
+
+ @Inject
+ lateinit var viewModelFactory: GroupViewModelFactory
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
+ rootView = View.inflate(context, R.layout.fragment_group_tasks_bottom_sheet, null)
+ dialog.setContentView(rootView)
+ behavior = BottomSheetBehavior.from(rootView.parent as View)
+ (activity as FineractBaseActivity).activityComponent.inject(this)
+ ButterKnife.bind(this, rootView)
+ viewModel = ViewModelProviders.of(this, viewModelFactory).get(GroupViewModel::class.java)
+ setDataOnViews()
+
+ subscribeUI()
+ return dialog
+ }
+
+ private fun subscribeUI() {
+ viewModel.status.observe(this, Observer { status ->
+ when (status) {
+ Status.LOADING -> {
+ showMifosProgressDialog(getString(R.string.please_wait_updating_group_status))
+ }
+ Status.ERROR -> {
+ hideMifosProgressDialog()
+ Toaster.show(rootView, R.string.error_while_updating_group_status, Toast.LENGTH_SHORT)
+ }
+ Status.DONE -> {
+ Toaster.show(rootView, getString(R.string.group_identifier_updated_successfully, group.identifier), Toast.LENGTH_SHORT)
+ hideMifosProgressDialog()
+ dismiss()
+ }
+ }
+ })
+ }
+
+ private fun setDataOnViews() {
+ when (group.status) {
+ Group.Status.ACTIVE -> {
+ rootView.iv_task.setImageDrawable(
+ ContextCompat.getDrawable(activity!!, R.drawable.ic_close_black_24dp))
+ rootView.iv_task.setColorFilter(ContextCompat.getColor(activity!!, R.color.red_dark))
+ rootView.tv_task.text = getString(R.string.close)
+ }
+ Group.Status.PENDING -> {
+ rootView.iv_task.setImageDrawable(ContextCompat.getDrawable(activity!!,
+ R.drawable.ic_check_circle_black_24dp))
+ rootView.iv_task.setColorFilter(ContextCompat.getColor(activity!!, R.color.status))
+ rootView.tv_task.text = getString(R.string.activate)
+ }
+ Group.Status.CLOSED -> {
+ rootView.iv_task.setImageDrawable(ContextCompat.getDrawable(activity!!,
+ R.drawable.ic_check_circle_black_24dp))
+ rootView.iv_task.setColorFilter(ContextCompat.getColor(activity!!, R.color.status))
+ rootView.tv_task.text = getString(R.string.reopen)
+ }
+ }
+ }
+
+ @OnClick(R.id.iv_task)
+ fun onTaskImageViewClicked() {
+ when (group.status) {
+ Group.Status.ACTIVE -> {
+ command.action = Command.Action.CLOSE
+ rootView.tv_header.text = getString(R.string.close)
+ rootView.tv_sub_header.text = getString(R.string.please_verify_following_group_task, getString(R.string.lock))
+ rootView.btn_submit_task.text = getString(R.string.close)
+ }
+ Group.Status.PENDING -> {
+ command.action = Command.Action.ACTIVATE
+ rootView.tv_header.text = getString(R.string.activate)
+ rootView.tv_sub_header.text = getString(R.string.please_verify_following_group_task, getString(R.string.activate))
+ rootView.btn_submit_task.text = getString(R.string.activate)
+ }
+ Group.Status.CLOSED -> {
+ command.action = Command.Action.REOPEN
+ rootView.tv_header.text = getString(R.string.reopen)
+ rootView.tv_sub_header.text = getString(R.string.please_verify_following_group_task, getString(R.string.reopen))
+ rootView.btn_submit_task.text = getString(R.string.reopen)
+ }
+ }
+ rootView.ll_task_list.visibility = View.GONE
+ rootView.ll_task_form.visibility = View.VISIBLE
+ }
+
+ @OnClick(R.id.btn_submit_task)
+ fun submitTask() {
+ command.comment = rootView.et_comment.text.toString().trim { it <= ' ' }
+ rootView.et_comment.isEnabled = false
+ group.identifier?.let {
+ viewModel.changeGroupStatus(it, command)
+ }
+ }
+
+ @OnClick(R.id.btn_cancel)
+ fun onCancel() {
+ dismiss()
+ }
+
+ override fun onStart() {
+ super.onStart()
+ behavior?.state = BottomSheetBehavior.STATE_EXPANDED
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ hideMifosProgressBar()
+ }
+}
diff --git a/app/src/main/java/org/apache/fineract/utils/Constants.kt b/app/src/main/java/org/apache/fineract/utils/Constants.kt
new file mode 100644
index 0000000..6d9dca5
--- /dev/null
+++ b/app/src/main/java/org/apache/fineract/utils/Constants.kt
@@ -0,0 +1,11 @@
+package org.apache.fineract.utils
+
+
+/*
+ * Created by saksham on 23/June/2019
+*/
+
+object Constants {
+ const val GROUP = "group"
+ const val GROUP_ACTION = "group_action"
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/apache/fineract/utils/DateUtils.java b/app/src/main/java/org/apache/fineract/utils/DateUtils.java
index 172bfef..a582653 100644
--- a/app/src/main/java/org/apache/fineract/utils/DateUtils.java
+++ b/app/src/main/java/org/apache/fineract/utils/DateUtils.java
@@ -11,7 +11,7 @@ import java.util.TimeZone;
/**
* @author Rajan Maurya
- * On 06/07/17.
+ * On 06/07/17.
*/
public class DateUtils {
@@ -90,4 +90,48 @@ public class DateUtils {
Locale.ENGLISH);
return simpleDateFormat.format(calendar.getTime());
}
+
+ public static String getWeekDay(int index) {
+ switch (index) {
+ case 1:
+ return "Monday";
+ case 2:
+ return "Tuesday";
+ case 3:
+ return "Wednesday";
+ case 4:
+ return "Thursday";
+ case 5:
+ return "Friday";
+ case 6:
+ return "Saturday";
+ case 7:
+ return "Sunday";
+ }
+ return null;
+ }
+
+ public static int getWeekDayIndex(String weekday) {
+ switch (weekday) {
+ case "Monday":
+ return 1;
+ case "Tuesday":
+ return 2;
+ case "Wednesday":
+ return 3;
+ case "Thursday":
+ return 4;
+ case "Friday":
+ return 5;
+ case "Saturday":
+ return 6;
+ case "Sunday":
+ return 7;
+ }
+ return 0;
+ }
+
+ public static String getPresentDay() {
+ return new SimpleDateFormat("EEEE").format(new Date());
+ }
}
diff --git a/app/src/main/java/org/apache/fineract/utils/StatusUtils.java b/app/src/main/java/org/apache/fineract/utils/StatusUtils.java
index 3cd120f..bbfe894 100644
--- a/app/src/main/java/org/apache/fineract/utils/StatusUtils.java
+++ b/app/src/main/java/org/apache/fineract/utils/StatusUtils.java
@@ -1,13 +1,16 @@
package org.apache.fineract.utils;
import android.content.Context;
+
import androidx.core.content.ContextCompat;
import androidx.appcompat.widget.AppCompatImageView;
+
import android.widget.ImageView;
import com.google.gson.annotations.SerializedName;
import org.apache.fineract.R;
+import org.apache.fineract.data.models.Group;
import org.apache.fineract.data.models.accounts.AccountType;
import org.apache.fineract.data.models.customer.Command;
import org.apache.fineract.data.models.customer.Customer;
@@ -22,7 +25,7 @@ import org.apache.fineract.data.models.teller.Teller;
public class StatusUtils {
public static void setCustomerStatus(Customer.State state, AppCompatImageView imageView,
- Context context) {
+ Context context) {
switch (state) {
case ACTIVE:
imageView.setColorFilter(
@@ -44,7 +47,7 @@ public class StatusUtils {
}
public static void setTellerStatus(Teller.State state, AppCompatImageView imageView,
- Context context) {
+ Context context) {
switch (state) {
case ACTIVE:
imageView.setColorFilter(
@@ -66,7 +69,7 @@ public class StatusUtils {
}
public static void setCustomerStatusIcon(Customer.State state, ImageView imageView,
- Context context) {
+ Context context) {
switch (state) {
case ACTIVE:
imageView.setImageDrawable(ContextCompat.getDrawable(context,
@@ -96,7 +99,7 @@ public class StatusUtils {
}
public static void setLoanAccountStatus(LoanAccount.State state, AppCompatImageView imageView,
- Context context) {
+ Context context) {
switch (state) {
case CREATED:
imageView.setColorFilter(
@@ -125,8 +128,24 @@ public class StatusUtils {
}
}
+ public static void setGroupsStatusIcon(Group.Status state, ImageView imageView,
+ Context context) {
+ switch (state) {
+
+ case PENDING:
+ imageView.setColorFilter(ContextCompat.getColor(context, R.color.blue));
+ break;
+ case ACTIVE:
+ imageView.setColorFilter(ContextCompat.getColor(context, R.color.deposit_green));
+ break;
+ case CLOSED:
+ imageView.setColorFilter(ContextCompat.getColor(context, R.color.red_dark));
+ break;
+ }
+ }
+
public static void setLoanAccountStatusIcon(LoanAccount.State state, ImageView imageView,
- Context context) {
+ Context context) {
switch (state) {
case ACTIVE:
imageView.setImageDrawable(ContextCompat.getDrawable(context,
@@ -162,7 +181,7 @@ public class StatusUtils {
}
public static void setDepositAccountStatusIcon(DepositAccount.State state, ImageView imageView,
- Context context) {
+ Context context) {
switch (state) {
case ACTIVE:
imageView.setImageDrawable(ContextCompat.getDrawable(context,
@@ -222,7 +241,7 @@ public class StatusUtils {
}
public static void setCustomerActivitiesStatusIcon(Command.Action action, ImageView imageView,
- Context context) {
+ Context context) {
switch (action) {
case ACTIVATE:
imageView.setImageDrawable(ContextCompat.getDrawable(context,
@@ -259,7 +278,7 @@ public class StatusUtils {
}
public static void setAccountType(AccountType action, ImageView imageView,
- Context context) {
+ Context context) {
switch (action) {
case ASSET:
imageView.setColorFilter(
diff --git a/app/src/main/java/org/apache/fineract/utils/Utils.java b/app/src/main/java/org/apache/fineract/utils/Utils.java
index b0b8326..035959f 100644
--- a/app/src/main/java/org/apache/fineract/utils/Utils.java
+++ b/app/src/main/java/org/apache/fineract/utils/Utils.java
@@ -1,19 +1,28 @@
package org.apache.fineract.utils;
+import android.app.Activity;
import android.content.Context;
import android.graphics.PorterDuff;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+
import androidx.core.content.ContextCompat;
+
+import android.graphics.drawable.LayerDrawable;
import android.view.Menu;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
+import org.apache.fineract.R;
+
import java.util.Locale;
/**
* @author Rajan Maurya
- * On 30/07/17.
+ * On 30/07/17.
*/
public class Utils {
@@ -36,4 +45,17 @@ public class Utils {
}
}
}
+
+ public static LayerDrawable setCircularBackground(int colorId, Context context) {
+ Drawable color = new ColorDrawable(ContextCompat.getColor(context, colorId));
+ Drawable image = ContextCompat.getDrawable(context, R.drawable.circular_background);
+ LayerDrawable ld = new LayerDrawable(new Drawable[]{image, color});
+ return ld;
+ }
+
+ public static void hideKeyboard(Context context, View view) {
+ InputMethodManager imm = (InputMethodManager) context.getSystemService(
+ Activity.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
+ }
}
diff --git a/app/src/main/java/org/apache/fineract/utils/ValidateIdentifierUtil.java b/app/src/main/java/org/apache/fineract/utils/ValidateIdentifierUtil.java
index ae71bfe..be0e216 100644
--- a/app/src/main/java/org/apache/fineract/utils/ValidateIdentifierUtil.java
+++ b/app/src/main/java/org/apache/fineract/utils/ValidateIdentifierUtil.java
@@ -27,7 +27,7 @@ public class ValidateIdentifierUtil {
TextInputLayout textInputLayout) {
if (string.length() < 3) {
showTextInputLayoutError(textInputLayout,
- context.getString(R.string.must_be_at_least_three_characters, 3));
+ context.getString(R.string.must_be_at_least_n_characters, 3));
return false;
}
diff --git a/app/src/main/res/drawable/border.xml b/app/src/main/res/drawable/border.xml
new file mode 100644
index 0000000..3a17891
--- /dev/null
+++ b/app/src/main/res/drawable/border.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/white" />
+ <stroke
+ android:width="1dp"
+ android:color="@color/gray_dark" />
+ <corners android:radius="4dp" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/circular_background.xml b/app/src/main/res/drawable/circular_background.xml
new file mode 100644
index 0000000..c11f653
--- /dev/null
+++ b/app/src/main/res/drawable/circular_background.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <size
+ android:width="@dimen/status_width"
+ android:height="@dimen/status_width" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_teller_black_24dp.xml b/app/src/main/res/drawable/ic_teller_black_24dp.xml
new file mode 100644
index 0000000..bd452ec
--- /dev/null
+++ b/app/src/main/res/drawable/ic_teller_black_24dp.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_create_group.xml b/app/src/main/res/layout/activity_create_group.xml
new file mode 100644
index 0000000..92bbd87
--- /dev/null
+++ b/app/src/main/res/layout/activity_create_group.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout style="@style/LinearLayout.Base">
+
+ <include layout="@layout/toolbar" />
+
+ <com.stepstone.stepper.StepperLayout
+ android:id="@+id/slCreateGroup"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:ms_activeStepColor="?attr/colorPrimary"
+ app:ms_backButtonColor="#FFFFFF"
+ app:ms_bottomNavigationBackground="?attr/colorPrimary"
+ app:ms_completeButtonColor="#FFFFFF"
+ app:ms_inactiveStepColor="#cccccc"
+ app:ms_nextButtonColor="#FFFFFF"
+ app:ms_stepperFeedbackType="tabs|content|disabled_bottom_navigation"
+ app:ms_stepperType="tabs"
+ app:ms_tabNavigationEnabled="false"
+ app:ms_tabStepDividerWidth="138dp" />
+
+ </LinearLayout>
+
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_group_list.xml b/app/src/main/res/layout/fragment_group_list.xml
new file mode 100644
index 0000000..b431360
--- /dev/null
+++ b/app/src/main/res/layout/fragment_group_list.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rvGroups"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <com.google.android.material.floatingactionbutton.FloatingActionButton
+ android:id="@+id/fabAddGroup"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/layout_padding_16dp"
+ app:layout_anchor="@id/rvGroups"
+ app:layout_anchorGravity="bottom|right"
+ app:layout_behavior="org.apache.fineract.utils.ScrollFabBehavior"
+ app:srcCompat="@drawable/ic_add_black_24dp" />
+
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_group_tasks_bottom_sheet.xml b/app/src/main/res/layout/fragment_group_tasks_bottom_sheet.xml
new file mode 100644
index 0000000..e2f4442
--- /dev/null
+++ b/app/src/main/res/layout/fragment_group_tasks_bottom_sheet.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/ll_task_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/layout_padding_8dp"
+ android:visibility="visible">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:padding="@dimen/layout_padding_16dp"
+ android:text="@string/tasks"
+ android:textColor="@color/gray_dark"
+ android:textStyle="bold" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0.2dp"
+ android:background="@color/grey_500" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="@dimen/layout_padding_16dp">
+
+ <LinearLayout
+ android:id="@+id/ll_task"
+ style="@style/circleLayout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/iv_task"
+ android:layout_width="35dp"
+ android:layout_height="35dp"
+ app:srcCompat="@drawable/ic_lock_black_24dp" />
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/tv_task"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:paddingTop="@dimen/layout_padding_8dp"
+ android:textSize="@dimen/text_medium"
+ tools:text="Lock" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/ll_task_form"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="@dimen/layout_padding_16dp">
+
+ <TextView
+ android:id="@+id/tv_header"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:text="@string/tasks"
+ android:textColor="@color/colorPrimaryDark"
+ android:textSize="@dimen/text_large"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/tv_sub_header"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:text="@string/please_verify_following_task"
+ android:textSize="@dimen/text_size_14sp" />
+
+
+ </LinearLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingStart="@dimen/layout_padding_16dp"
+ android:paddingEnd="@dimen/layout_padding_16dp"
+ android:paddingRight="@dimen/layout_padding_16dp">
+
+ <EditText
+ android:id="@+id/et_comment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:hint="@string/enter_your_comment_here"
+ android:inputType="textMultiLine"
+ android:scrollbars="vertical"
+ android:scrollHorizontally="false" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:layout_marginBottom="@dimen/layout_padding_8dp"
+ android:gravity="end"
+ android:orientation="horizontal"
+ android:padding="@dimen/layout_padding_16dp">
+
+ <Button
+ android:id="@+id/btn_cancel"
+ style="@style/Widget.MaterialComponents.Button.TextButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginEnd="@dimen/layout_padding_8dp"
+ android:layout_marginRight="@dimen/layout_padding_8dp"
+ android:text="@string/cancel"
+ android:textAllCaps="false"
+ android:textSize="@dimen/text_size_14sp" />
+
+ <Button
+ android:id="@+id/btn_submit_task"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/tasks"
+ android:textAllCaps="false" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
+
+
+
diff --git a/app/src/main/res/layout/fragment_groups_details.xml b/app/src/main/res/layout/fragment_groups_details.xml
new file mode 100644
index 0000000..b5e91de
--- /dev/null
+++ b/app/src/main/res/layout/fragment_groups_details.xml
@@ -0,0 +1,378 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <androidx.core.widget.NestedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="@dimen/layout_padding_16dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/identifier"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tvIdentifier"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:text="@string/status"
+ android:textColor="@color/gray_dark" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:orientation="horizontal">
+
+ <org.apache.fineract.ui.views.CircularImageView
+ android:id="@+id/civStatus"
+ android:layout_width="25dp"
+ android:layout_height="match_parent" />
+
+ <TextView
+ android:id="@+id/tvStatus"
+ style="@style/Base.TextAppearance.AppCompat.Medium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+ </LinearLayout>
+
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:text="@string/group_id"
+ android:textColor="@color/gray_dark" />
+
+
+ <TextView
+ android:id="@+id/tvGroupId"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:text="@string/name"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tvName"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+ </LinearLayout>
+
+ </androidx.cardview.widget.CardView>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/layout_padding_16dp"
+ android:paddingTop="@dimen/layout_padding_16dp"
+ android:paddingEnd="@dimen/layout_padding_16dp"
+ android:paddingRight="@dimen/layout_padding_16dp"
+ android:paddingBottom="@dimen/layout_padding_8dp"
+ android:text="@string/leaders"
+ android:textColor="@color/gray_dark" />
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/layout_padding_16dp">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_leaders"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/layout_padding_16dp"
+ android:paddingTop="@dimen/layout_padding_16dp"
+ android:paddingEnd="@dimen/layout_padding_16dp"
+ android:paddingBottom="@dimen/layout_padding_8dp"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:itemCount="2"
+ tools:listitem="@layout/item_name_list" />
+ </androidx.cardview.widget.CardView>
+
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/layout_padding_16dp"
+ android:paddingTop="@dimen/layout_padding_16dp"
+ android:paddingEnd="@dimen/layout_padding_16dp"
+ android:paddingRight="@dimen/layout_padding_16dp"
+ android:paddingBottom="@dimen/layout_padding_8dp"
+ android:text="@string/members"
+ android:textColor="@color/gray_dark" />
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_members"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/layout_padding_16dp"
+ android:paddingTop="@dimen/layout_padding_16dp"
+ android:paddingEnd="@dimen/layout_padding_16dp"
+ android:paddingBottom="@dimen/layout_padding_8dp"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:itemCount="2"
+ tools:listitem="@layout/item_name_list" />
+
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="@dimen/default_padding">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/office"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tvOffice"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:text="@string/assigned_employee"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tvAssignedEmployee"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:text="@string/weekday"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tvWeekday"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+ </LinearLayout>
+
+ </androidx.cardview.widget.CardView>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/cv_tasks"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_12dp"
+ tools:targetApi="lollipop">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackgroundBorderless">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="@dimen/layout_padding_16dp">
+
+ <ImageView
+ style="@style/circleLayout"
+ android:layout_width="42dp"
+ android:layout_height="42dp"
+ app:srcCompat="@drawable/ic_task_black_24dp" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/layout_padding_8dp"
+ android:layout_marginLeft="@dimen/layout_padding_8dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/tasks" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:text="@string/change_group_status"
+ android:textColor="@color/gray_dark"
+ android:textSize="@dimen/text_size_12sp" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+ </LinearLayout>
+ </androidx.cardview.widget.CardView>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/layout_padding_16dp"
+ android:paddingTop="@dimen/layout_padding_16dp"
+ android:paddingEnd="@dimen/layout_padding_16dp"
+ android:paddingRight="@dimen/layout_padding_16dp"
+ android:paddingBottom="@dimen/layout_padding_8dp"
+ android:text="@string/address"
+ android:textColor="@color/gray_dark" />
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="@dimen/default_padding">
+
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/street"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tvStreet"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:text="@string/city"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tvCity"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:text="@string/region"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tvRegion"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:text="@string/postal_code"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tvPostalCode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:text="@string/country"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tvCountry"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_8dp"
+ android:textColor="@color/black"
+ tools:text="@string/medium_text" />
+ </LinearLayout>
+ </androidx.cardview.widget.CardView>
+
+ </LinearLayout>
+ </androidx.core.widget.NestedScrollView>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_step_add_group_leader.xml b/app/src/main/res/layout/fragment_step_add_group_leader.xml
new file mode 100644
index 0000000..b49c067
--- /dev/null
+++ b/app/src/main/res/layout/fragment_step_add_group_leader.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/default_margin">
+
+ <androidx.core.widget.NestedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior">
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/default_margin"
+ android:layout_marginBottom="@dimen/default_margin">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="@dimen/default_padding">
+
+ <LinearLayout
+ android:id="@+id/llMember"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:animateLayoutChanges="true"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="3"
+ android:text="@string/leaders"
+ android:textColor="@color/gray_dark" />
+
+ <ImageButton
+ android:id="@+id/ibAddLeader"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ app:srcCompat="@drawable/ic_add_black_24dp" />
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/tvAddLeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:padding="@dimen/layout_padding_16dp"
+ android:text="@string/no_group_leader_added"
+ android:visibility="visible" />
+
+ <LinearLayout
+ android:id="@+id/llAddLeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_12dp"
+ android:background="@drawable/border"
+ android:orientation="vertical"
+ android:padding="@dimen/layout_padding_16dp"
+ android:visibility="gone">
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/etNewLeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/name" />
+
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:gravity="right">
+
+ <Button
+ android:id="@+id/btnCancelAddLeader"
+ style="@style/Widget.MaterialComponents.Button.TextButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/cancel"
+ android:textSize="@dimen/text_size_14sp" />
+
+ <Button
+ android:id="@+id/btnAddLeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/add" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+
+ </LinearLayout>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:paddingTop="@dimen/layout_padding_16dp"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:itemCount="4"
+ tools:listitem="@layout/item_name_list" />
+ </LinearLayout>
+ </androidx.cardview.widget.CardView>
+ </androidx.core.widget.NestedScrollView>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_step_add_group_member.xml b/app/src/main/res/layout/fragment_step_add_group_member.xml
new file mode 100644
index 0000000..aac7ef5
--- /dev/null
+++ b/app/src/main/res/layout/fragment_step_add_group_member.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/default_margin">
+
+ <androidx.core.widget.NestedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior">
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/default_margin"
+ android:layout_marginBottom="@dimen/default_margin">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="@dimen/default_padding">
+
+ <LinearLayout
+ android:id="@+id/llMember"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:animateLayoutChanges="true"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="3"
+ android:text="@string/members"
+ android:textColor="@color/gray_dark" />
+
+ <ImageButton
+ android:id="@+id/ibAddMember"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ app:srcCompat="@drawable/ic_add_black_24dp" />
+
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/tvAddedMember"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:padding="@dimen/layout_padding_16dp"
+ android:text="@string/no_group_member_added"
+ android:visibility="visible" />
+
+ <LinearLayout
+ android:id="@+id/llAddMember"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_12dp"
+ android:background="@drawable/border"
+ android:orientation="vertical"
+ android:padding="@dimen/layout_padding_16dp"
+ android:visibility="gone">
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/etNewMember"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/name" />
+
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_16dp"
+ android:gravity="right">
+
+ <Button
+ android:id="@+id/btnCancelAddMember"
+ style="@style/Widget.MaterialComponents.Button.TextButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/cancel"
+ android:textSize="@dimen/text_size_14sp" />
+
+ <Button
+ android:id="@+id/btnAddMember"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/add" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+
+ </LinearLayout>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:paddingTop="@dimen/layout_padding_16dp"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:itemCount="4"
+ tools:listitem="@layout/item_name_list" />
+ </LinearLayout>
+
+ </androidx.cardview.widget.CardView>
+
+ </androidx.core.widget.NestedScrollView>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_step_group_address.xml b/app/src/main/res/layout/fragment_step_group_address.xml
new file mode 100644
index 0000000..cf35d49
--- /dev/null
+++ b/app/src/main/res/layout/fragment_step_group_address.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/default_margin">
+
+ <androidx.core.widget.NestedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior">
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/default_margin"
+ android:layout_marginBottom="@dimen/default_margin">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="@dimen/default_padding">
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/etStreet"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/street"
+ android:inputType="text" />
+
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/etCity"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/city"
+ android:inputType="text" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/etRegion"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/region"
+ android:inputType="text" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/etPostalCode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/postal_code"
+ android:inputType="number" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <AutoCompleteTextView
+ android:id="@+id/etCountry"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:digits="@string/restrict_a_zA_Z"
+ android:hint="@string/country"
+ android:inputType="text" />
+
+ </com.google.android.material.textfield.TextInputLayout>
+
+ </LinearLayout>
+ </androidx.cardview.widget.CardView>
+ </androidx.core.widget.NestedScrollView>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_step_group_details.xml b/app/src/main/res/layout/fragment_step_group_details.xml
new file mode 100644
index 0000000..9a73093
--- /dev/null
+++ b/app/src/main/res/layout/fragment_step_group_details.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/default_margin">
+
+ <androidx.core.widget.NestedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior">
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/default_margin"
+ android:layout_marginBottom="@dimen/default_margin">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="@dimen/default_padding">
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/tilIdentifier"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/etIdentifier"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/identifier"
+ android:inputType="text" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/tilGroupDefinitionIdentifier"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/etGroupDefinitionIdentifier"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/group_definition_identifier"
+ android:inputType="text" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/tilName"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+
+ <EditText
+ android:id="@+id/etName"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/name"
+ android:inputType="text" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/tilOffice"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/etOffice"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/office"
+ android:inputType="text" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/tilAssignedEmployee"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/etAssignedEmployee"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/assigned_employee"
+ android:inputType="text" />
+ </com.google.android.material.textfield.TextInputLayout>
+ </LinearLayout>
+ </androidx.cardview.widget.CardView>
+ </androidx.core.widget.NestedScrollView>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/app/src/main/res/layout/fragment_step_group_review.xml b/app/src/main/res/layout/fragment_step_group_review.xml
new file mode 100644
index 0000000..c70d391
--- /dev/null
+++ b/app/src/main/res/layout/fragment_step_group_review.xml
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/default_margin">
+
+ <androidx.core.widget.NestedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior">
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/default_margin"
+ android:layout_marginBottom="@dimen/default_margin">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="@dimen/default_padding">
+
+ <LinearLayout
+ android:id="@+id/llHeadOne"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/layout_padding_16dp"
+ android:baselineAligned="false"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/layout_padding_8dp"
+ android:layout_marginRight="@dimen/layout_padding_8dp"
+ android:background="@drawable/review_circle_bg"
+ android:gravity="center"
+ android:text="@string/one"
+ android:textColor="@color/white"
+ android:textSize="@dimen/text_size_12sp" />
+
+ <TextView
+ android:id="@+id/tvHeadOne"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold" />
+
+ </LinearLayout>
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:text="@string/identifier" />
+
+ <TextView
+ android:id="@+id/tvIdentifier"
+ style="@style/TextViewReview.Input"
+ android:textColor="@color/black" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:text="@string/group_definition_identifier" />
+
+ <TextView
+ android:id="@+id/tvGroupDefinitionIdentifier"
+ style="@style/TextViewReview.Input" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:text="@string/name" />
+
+ <TextView
+ android:id="@+id/tvName"
+ style="@style/TextViewReview.Input" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:text="@string/office" />
+
+ <TextView
+ android:id="@+id/tvOffice"
+ style="@style/TextViewReview.Input" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:text="@string/assigned_employee" />
+
+ <TextView
+ android:id="@+id/tvAssignedEmployee"
+ style="@style/TextViewReview.Input" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <LinearLayout
+ android:id="@+id/llHeadTwo"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/layout_padding_16dp"
+ android:baselineAligned="false"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/layout_padding_8dp"
+ android:layout_marginRight="@dimen/layout_padding_8dp"
+ android:background="@drawable/review_circle_bg"
+ android:gravity="center"
+ android:text="@string/two"
+ android:textColor="@color/white"
+ android:textSize="@dimen/text_size_12sp" />
+
+ <TextView
+ android:id="@+id/tvHeadTwo"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold" />
+
+ </LinearLayout>
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:paddingTop="@dimen/layout_padding_8dp"
+ android:text="@string/members" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_members"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_12dp"
+ android:layout_marginBottom="@dimen/layout_padding_12dp"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:itemCount="2"
+ tools:listitem="@layout/item_name_list" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <LinearLayout
+ android:id="@+id/llHeadThree"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/layout_padding_16dp"
+ android:baselineAligned="false"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/layout_padding_8dp"
+ android:layout_marginRight="@dimen/layout_padding_8dp"
+ android:background="@drawable/review_circle_bg"
+ android:gravity="center"
+ android:text="@string/three"
+ android:textColor="@color/white"
+ android:textSize="@dimen/text_size_12sp" />
+
+ <TextView
+ android:id="@+id/tvHeadThree"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold" />
+
+ </LinearLayout>
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:paddingTop="@dimen/layout_padding_8dp"
+ android:text="@string/leaders" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv_leaders"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_padding_12dp"
+ android:layout_marginBottom="@dimen/layout_padding_12dp"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:itemCount="2"
+ tools:listitem="@layout/item_name_list" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <LinearLayout
+ android:id="@+id/llHeadFour"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/layout_padding_16dp"
+ android:baselineAligned="false"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/layout_padding_8dp"
+ android:layout_marginRight="@dimen/layout_padding_8dp"
+ android:background="@drawable/review_circle_bg"
+ android:gravity="center"
+ android:text="@string/four"
+ android:textColor="@color/white"
+ android:textSize="@dimen/text_size_12sp" />
+
+ <TextView
+ android:id="@+id/tvHeadFour"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold" />
+
+ </LinearLayout>
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:text="@string/street" />
+
+ <TextView
+ android:id="@+id/tvStreet"
+ style="@style/TextViewReview.Input" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:text="@string/city" />
+
+ <TextView
+ android:id="@+id/tvCity"
+ style="@style/TextViewReview.Input" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:text="@string/region" />
+
+ <TextView
+ android:id="@+id/tvRegion"
+ style="@style/TextViewReview.Input" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:text="@string/postal_code" />
+
+ <TextView
+ android:id="@+id/tvPostalCode"
+ style="@style/TextViewReview.Input" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ <TextView
+ style="@style/TextViewReview.Head"
+ android:text="@string/country" />
+
+ <TextView
+ android:id="@+id/tvCountry"
+ style="@style/TextViewReview.Input" />
+
+ <View style="@style/TextViewUnderline.Grey" />
+
+ </LinearLayout>
+
+ </androidx.cardview.widget.CardView>
+ </androidx.core.widget.NestedScrollView>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_group.xml b/app/src/main/res/layout/item_group.xml
new file mode 100644
index 0000000..2166405
--- /dev/null
+++ b/app/src/main/res/layout/item_group.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/ll_group"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/iv_type_indicator"
+ android:layout_width="5dp"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/default_margin"
+ android:layout_marginBottom="@dimen/default_margin"
+ app:srcCompat="@drawable/round_corner" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="@dimen/default_padding">
+
+ <TextView
+ android:id="@+id/tv_group_identifier"
+ style="@style/Base.TextAppearance.AppCompat.Medium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@color/black"
+ tools:text="@string/identifier" />
+
+ <TextView
+ android:id="@+id/tv_last_modified_by"
+ style="@style/Base.TextAppearance.AppCompat.Small"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/last_modified_by"
+ android:textColor="@color/gray_dark" />
+
+ <TextView
+ android:id="@+id/tv_last_modified_on"
+ style="@style/Base.TextAppearance.AppCompat.Small"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/last_modified_on"
+ android:textColor="@color/gray_dark" />
+
+ </LinearLayout>
+
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0.2dp"
+ android:background="#E7DFDF" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_name_list.xml b/app/src/main/res/layout/item_name_list.xml
new file mode 100644
index 0000000..dd89e55
--- /dev/null
+++ b/app/src/main/res/layout/item_name_list.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/layout_padding_8dp"
+ android:background="@color/white"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/border"
+ android:orientation="horizontal"
+ android:padding="@dimen/layout_padding_12dp">
+
+ <TextView
+ android:id="@+id/tv_name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ tools:text="Ahmad Jawid" />
+
+ <ImageView
+ android:id="@+id/iv_edit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:tint="@color/colorAccent"
+ app:srcCompat="@drawable/ic_edit_black_24dp" />
+
+ <ImageView
+ android:id="@+id/iv_delete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/layout_padding_12dp"
+ android:layout_marginLeft="@dimen/layout_padding_12dp"
+ android:tint="@color/colorAccent"
+ app:srcCompat="@drawable/ic_delete_black_24dp" />
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_group_detials.xml b/app/src/main/res/menu/menu_group_detials.xml
new file mode 100644
index 0000000..5178c60
--- /dev/null
+++ b/app/src/main/res/menu/menu_group_detials.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/menu_edit_group"
+ android:icon="@drawable/ic_edit_black_24dp"
+ android:title="@string/edit"
+ app:showAsAction="always" />
+</menu>
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_group_search.xml b/app/src/main/res/menu/menu_group_search.xml
new file mode 100644
index 0000000..a1c59b8
--- /dev/null
+++ b/app/src/main/res/menu/menu_group_search.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/group_search"
+ android:icon="@drawable/ic_search_black_24dp"
+ android:title="@string/group_search"
+ app:actionViewClass="androidx.appcompat.widget.SearchView"
+ app:showAsAction="always" />
+</menu>
diff --git a/app/src/main/res/menu/menu_navigation_drawer.xml b/app/src/main/res/menu/menu_navigation_drawer.xml
index e42f38f..1886dc8 100644
--- a/app/src/main/res/menu/menu_navigation_drawer.xml
+++ b/app/src/main/res/menu/menu_navigation_drawer.xml
@@ -7,51 +7,48 @@
<item
android:id="@+id/item_dashboard"
- android:checked="true"
android:icon="@drawable/ic_dashboard_black_24dp"
android:title="@string/dashboard" />
<item
android:id="@+id/item_roles"
- android:checked="true"
android:icon="@drawable/ic_lock_black_24dp"
android:title="@string/roles_and_permissions" />
<item
android:id="@+id/item_customer"
- android:checked="true"
android:icon="@drawable/ic_customer_black_24dp"
android:title="@string/customer" />
<item
android:id="@+id/item_customer_payload"
- android:checked="true"
android:icon="@drawable/ic_business_center_black_24dp"
android:title="@string/customer_payloads" />
<item
android:id="@+id/item_ledger"
- android:checked="true"
android:icon="@drawable/ic_book_black_24dp"
android:title="@string/ledger" />
<item
android:id="@+id/item_accounts"
- android:checked="true"
android:icon="@drawable/ic_account_balance_black_24dp"
android:title="@string/accounts" />
<item
android:id="@+id/item_teller"
- android:checked="true"
- android:icon="@drawable/ic_supervisor_account_black_24dp"
+ android:icon="@drawable/ic_teller_black_24dp"
android:title="@string/teller" />
<item
android:id="@+id/item_product"
- android:checked="true"
android:icon="@drawable/ic_products_black_24dp"
android:title="@string/products" />
+ <item
+ android:id="@+id/item_groups"
+ android:icon="@drawable/ic_supervisor_account_black_24dp"
+ android:title="@string/groups" />
+
</group>
<group android:id="@+id/group2">
diff --git a/app/src/main/res/values-ml-rIN/strings.xml b/app/src/main/res/values-ml-rIN/strings.xml
index 3052c13..937afa5 100644
--- a/app/src/main/res/values-ml-rIN/strings.xml
+++ b/app/src/main/res/values-ml-rIN/strings.xml
@@ -220,7 +220,7 @@
<string name="amount_should_be_not_empty">തുക ശൂന്യമായി ഇടരുത്</string>
<string name="description_should_not_be_empty">വിവരണം ശൂന്യമായിരിക്കരുത്</string>
<string name="customer_name_should_not_be_empty">ഉപഭോക്താവിന്റെ പേര് ശൂന്യമായിരിക്കരുത്</string>
- <string name="must_be_at_least_three_characters">കുറഞ്ഞത്% 1 $ d പ്രതീകങ്ങൾ ഉണ്ടായിരിക്കണം</string>
+ <string name="must_be_at_least_n_characters">കുറഞ്ഞത്% 1 $ d പ്രതീകങ്ങൾ ഉണ്ടായിരിക്കണം</string>
<string name="only_thirty_two_character_allowed">32 പ്രതീകങ്ങൾ മാത്രം അനുവദനീയം</string>
<string name="only_alphabetic_decimal_digits_characters_allowed">അക്ഷരമാല, ദശാംശ സംഖ്യകൾ മാത്രം, \'-\' _ \'\'. \' \'!\' \'~\' \'*\' \'(\' \')\' പ്രതീകങ്ങൾ അനുവദിച്ചു</string>
<string name="invalid_country">അസാധുവായ രാജ്യം</string>
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 78fa8ad..5c6ca8a 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -9,6 +9,7 @@
<dimen name="layout_padding_5dp">5dp</dimen>
<dimen name="layout_padding_7dp">7dp</dimen>
<dimen name="layout_padding_10dp">10dp</dimen>
+ <dimen name="layout_padding_12dp">12dp</dimen>
<dimen name="layout_padding_15dp">15dp</dimen>
<dimen name="layout_padding_16dp">16dp</dimen>
<dimen name="layout_padding_24dp">24dp</dimen>
@@ -23,6 +24,7 @@
<dimen name="header_view_start_margin_bottom">14dp</dimen>
<dimen name="view_line_height">1dp</dimen>
+ <dimen name="view_line_width">1dp</dimen>
<dimen name="text_size_12sp">12sp</dimen>
<dimen name="text_size_14sp">14sp</dimen>
@@ -45,4 +47,8 @@
<dimen name="side_bar_width">5dp</dimen>
<dimen name="default_fab_button_size">56dp</dimen>
+
+ <!--Dimen values for Status-->
+ <dimen name="status_height">25dp</dimen>
+ <dimen name="status_width">25dp</dimen>
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8744d5d..af22aaa 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -38,7 +38,7 @@
<string name="activities">Activities</string>
<string name="recent_activities">Recent activities</string>
<string name="birthday">Birthday</string>
- <string name="assigned_employee">Assigned Employee: </string>
+ <string name="assigned_employee">Assigned Employee </string>
<string name="assigned_employee_list">Assigned Employee: %1$s</string>
<string name="not_assigned">Not assigned</string>
<string name="no_contact_details_available">No Contact details available</string>
@@ -179,12 +179,15 @@
<string name="customer_deposit_account">Customer deposit account</string>
<string name="customer_created_successfully">%1$s created successfully</string>
<string name="customer_updated_successfully">%1$s updated successfully</string>
+ <string name="group_identifier_created_successfully">Group %1$s created successfully</string>
+ <string name="group_identifier_updated_successfully">Group %1$s updated successfully</string>
<string name="created_by">Created by</string>
<string name="created_on">Created on</string>
<string name="no_deposit_account">No deposit account</string>
<string name="identification_search">Search identification card</string>
<string name="ledger_search">Ledger Search</string>
<string name="teller_search">Search teller</string>
+ <string name="group_search">Search Group</string>
<string name="loan_account_search">Loan Account Search</string>
<string name="loan_last_modified_by">%1$s %2$s</string>
<string name="loan_created_by">%1$s %2$s</string>
@@ -210,6 +213,27 @@
<string name="identification_card_scan">Identification card scan</string>
<string name="role">Role</string>
<string name="customer_name">%1$s %2$s</string>
+ <string name="groups">Groups</string>
+ <string name="group_id">Group Id</string>
+ <string name="leaders">Leaders</string>
+ <string name="members">Members</string>
+ <string name="office">Office</string>
+ <string name="weekday">Weekday</string>
+ <string name="street">Street</string>
+ <string name="city">City</string>
+ <string name="region">Region</string>
+ <string name="postal_code">Postal Code</string>
+ <string name="country">Country</string>
+ <string name="status">Status</string>
+ <string name="group_definition_identifier">Group Definition Identifier</string>
+ <string name="create_group">Create Group</string>
+ <string name="no_group_member_added">No Group Member Added</string>
+ <string name="no_group_leader_added">No Group Leader Added</string>
+
+ <!--Placeholder text-->
+ <string name="small_text" translatable="false">Small Text</string>
+ <string name="medium_text" translatable="false">Medium Text</string>
+ <string name="large_text" translatable="false">Large Text</string>
<!--Edit Text hint required-->
<string name="required_account">Account*</string>
@@ -250,7 +274,7 @@
<string name="amount_should_be_not_empty">Amount should not be empty</string>
<string name="description_should_not_be_empty">Description should not be empty</string>
<string name="customer_name_should_not_be_empty">Customer name should not be empty</string>
- <string name="must_be_at_least_three_characters">Must be at least %1$d characters</string>
+ <string name="must_be_at_least_n_characters">Must be at least %1$d characters</string>
<string name="only_thirty_two_character_allowed">Only 32 character allowed</string>
<string name="only_alphabetic_decimal_digits_characters_allowed">Only alphabetic, decimal digits,\'-\' \'_\' \'.\' \'!\' \'~\' \'*\' \'(\' \')\' characters allowed</string>
<string name="two_warning_message">%1$s \n %1$s</string>
@@ -297,7 +321,8 @@
<string name="error_fetching_customer_details">Failed to fetch customer details</string>
<string name="error_fetching_deposit_product">Failed to fetch deposit product</string>
<string name="error_failed_to_refresh_customers">Failed to refresh customers</string>
-
+ <string name="error_group_atleast_1_member">Group should have atleast 1 Member</string>
+ <string name="error_group_atleast_1_leader">Group should have atleast 1 Leader</string>
<!--Material Dialog-->
<string name="dialog_action_ok">OK</string>
@@ -414,6 +439,14 @@
<item>Review</item>
</string-array>
+ <string-array name="create_group_steps">
+ <item>Group Details</item>
+ <item>Add Members</item>
+ <item>Add Leaders</item>
+ <item>Group Address</item>
+ <item>Review</item>
+ </string-array>
+
<string-array name="edit_payroll_steps">
<item>Customer payroll</item>
<item>Payroll allocations</item>
@@ -500,4 +533,13 @@
<string name="email">Email</string>
<string name="logged_out_successfully">Logged out successfully.</string>
<string name="please_click_back_again_to_exit">Please click BACK again to exit</string>
+ <string name="update">Update</string>
+ <string name="dialog_message_confirm_name_deletion">Do you want to delete %s?</string>
+ <string name="edit_group">Edit Group</string>
+ <string name="updating_group_please_wait">Updating Group, please wait...</string>
+ <string name="please_verify_following_group_task">Please verify the following tasks before you can %1$s this group</string>
+ <string name="change_group_status">Change the status of group</string>
+ <string name="please_wait_updating_group_status">"Updating group status, please wait... "</string>
+ <string name="error_while_updating_group_status">Error while updating group status</string>
+ <string name="error_while_creating_group">Error while creating group</string>
</resources>
diff --git a/app/src/main/res/values/styles_text.xml b/app/src/main/res/values/styles_text.xml
index 40b7cdb..d4d5da5 100755
--- a/app/src/main/res/values/styles_text.xml
+++ b/app/src/main/res/values/styles_text.xml
@@ -11,7 +11,7 @@
</style>
<style name="TextViewReview.Head">
- <item name="android:paddingTop">@dimen/layout_padding_16dp</item>
+ <item name="android:paddingTop">@dimen/layout_padding_8dp</item>
</style>
<style name="TextViewReview.Input">
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..f18e1f0
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+ <base-config cleartextTrafficPermitted="true">
+ <trust-anchors>
+ <certificates src="system" />
+ </trust-anchors>
+ </base-config>
+</network-security-config>
\ No newline at end of file
diff --git a/app/src/main/resources/groups.json b/app/src/main/resources/groups.json
new file mode 100644
index 0000000..086d27f
--- /dev/null
+++ b/app/src/main/resources/groups.json
@@ -0,0 +1,122 @@
+[
+ {
+ "identifier": "group001",
+ "groupDefinitionIdentifier": "grpDef001",
+ "name": "SDLE Group",
+ "leaders": [
+ "Ndi",
+ "Mele"
+ ],
+ "members": [
+ "Awasom",
+ "Kamgue",
+ "Etta"
+ ],
+ "office": "Bambui",
+ "assignedEmployee": "Tabah Tih",
+ "weekday": 4,
+ "status": "PENDING",
+ "address": {
+ "street": "Ghana Street",
+ "city": "Bamenda",
+ "region": "NWR",
+ "postalCode": "8050",
+ "countryCode": "CM",
+ "country": "Cameroon"
+ },
+ "createdOn": "2018-06-26T15:09:36.672Z",
+ "createdBy": "ranefer",
+ "lastModifiedOn": "lastModifiedOn",
+ "lastModifiedBy": "lastModifiedBy"
+ },
+ {
+ "identifier": "group002",
+ "groupDefinitionIdentifier": "grpDef202",
+ "name": "SDLE Group",
+ "leaders": [
+ "Ndi",
+ "Mele"
+ ],
+ "members": [
+ "Awasom",
+ "Kamgue",
+ "Etta"
+ ],
+ "office": "Bambui",
+ "assignedEmployee": "Tabah Tih",
+ "weekday": 1,
+ "status": "ACTIVE",
+ "address": {
+ "street": "Ghana Street",
+ "city": "Bamenda",
+ "region": "NWR",
+ "postalCode": "8050",
+ "countryCode": "CM",
+ "country": "Cameroon"
+ },
+ "createdOn": "2018-06-26T15:09:36.672Z",
+ "createdBy": "ranefer",
+ "lastModifiedOn": "lastModifiedOn",
+ "lastModifiedBy": "lastModifiedBy"
+ },
+ {
+ "identifier": "group003",
+ "groupDefinitionIdentifier": "grpDef003",
+ "name": "SDLE Group",
+ "leaders": [
+ "Ndi",
+ "Mele"
+ ],
+ "members": [
+ "Awasom",
+ "Kamgue",
+ "Etta"
+ ],
+ "office": "Bambui",
+ "assignedEmployee": "Tabah Tih",
+ "weekday": 5,
+ "status": "CLOSED",
+ "address": {
+ "street": "Ghana Street",
+ "city": "Bamenda",
+ "region": "NWR",
+ "postalCode": "8050",
+ "countryCode": "CM",
+ "country": "Cameroon"
+ },
+ "createdOn": "2018-06-26T15:09:36.672Z",
+ "createdBy": "ranefer",
+ "lastModifiedOn": "lastModifiedOn",
+ "lastModifiedBy": "lastModifiedBy"
+ },
+ {
+ "identifier": "group004",
+ "groupDefinitionIdentifier": "grpDef004",
+ "name": "SDLE Group",
+ "leaders": [
+ "Ndi",
+ "Mele"
+ ],
+ "members": [
+ "Awasom",
+ "Kamgue",
+ "Etta"
+ ],
+ "office": "Bambui",
+ "assignedEmployee": "Tabah Tih",
+ "weekday": 5,
+ "status": "PENDING",
+ "address": {
+ "street": "Ghana Street",
+ "city": "Bamenda",
+ "region": "NWR",
+ "postalCode": "8050",
+ "countryCode": "CM",
+ "country": "Cameroon"
+ },
+ "createdOn": "2018-06-26T15:09:36.672Z",
+ "createdBy": "ranefer",
+ "lastModifiedOn": "lastModifiedOn",
+ "lastModifiedBy": "lastModifiedBy"
+ }
+]
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 439d2ac..e663451 100644
--- a/build.gradle
+++ b/build.gradle
@@ -42,6 +42,7 @@ ext {
retrofitVersion = '2.4.0'
okHttp3Version = '3.11.0'
butterKnifeVersion = '10.1.0'
+ lifecycleExtension = '2.0.0'
// rxjava dependencies
rxjavaVersion = '2.2.1'
@@ -69,4 +70,6 @@ ext {
circleImageviewVersion = '2.1.0'
compressorVersion = '2.1.0'
mifosPasscodeVersion = '1.0.0'
+ easyValidationVersion = '1.0.1'
+ version_kotlin_coroutines = '1.3.4'
}