diff --git a/app/build.gradle b/app/build.gradle index 9b0025d6..068a6760 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,7 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" + multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } @@ -81,6 +82,9 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.kotlinVersion" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$rootProject.kotlinVersion" + // Circle Image View + implementation 'de.hdodenhof:circleimageview:3.0.1' + // Support Dependencies implementation "androidx.appcompat:appcompat:$rootProject.supportLibraryVersion" implementation "com.google.android.material:material:$rootProject.supportLibraryVersion" @@ -127,6 +131,10 @@ dependencies { implementation 'com.github.bumptech.glide:glide:4.8.0' kapt 'com.github.bumptech.glide:compiler:4.8.0' + implementation 'me.dm7.barcodescanner:zxing:1.9.13' + implementation 'com.karumi:dexter:5.0.0' + implementation 'com.hover:android-sdk:1.5.1' + //dbFlow for database kapt "com.github.Raizlabs.DBFlow:dbflow-processor:$rootProject.dbFlowVersion" implementation "com.github.Raizlabs.DBFlow:dbflow-core:$rootProject.dbFlowVersion" @@ -134,7 +142,7 @@ dependencies { implementation "com.github.Raizlabs.DBFlow:dbflow-kotlinextensions:$rootProject.dbFlowVersion" implementation "com.github.Raizlabs.DBFlow:dbflow-rx2:$rootProject.dbFlowVersion" implementation "com.github.Raizlabs.DBFlow:dbflow-rx2-kotlinextensions:$rootProject.dbFlowVersion" - + implementation 'com.android.support:multidex:1.0.3' //OpenSource Licences implementation "com.google.android.gms:play-services-oss-licenses:17.0.0" @@ -161,35 +169,41 @@ dependencies { testImplementation "org.hamcrest:hamcrest-core:$rootProject.hamcrestVersion" testImplementation "org.hamcrest:hamcrest-library:$rootProject.hamcrestVersion" testImplementation "org.hamcrest:hamcrest-integration:$rootProject.hamcrestVersion" - testImplementation 'org.robolectric:robolectric:3.3.1' + testImplementation 'org.robolectric:robolectric:4.2.1' + + //Navigation + def nav_version = "2.3.2" + + implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" + implementation "androidx.navigation:navigation-ui-ktx:$nav_version" } - // Log out test results to console - tasks.matching { it instanceof Test }.all { - testLogging.events = ["failed", "passed", "skipped"] - } +// Log out test results to console +tasks.matching { it instanceof Test }.all { + testLogging.events = ["failed", "passed", "skipped"] +} - /* +/* Resolves dependency versions across test and production APKs, specifically, transitive dependencies. This is required since Espresso internally has a dependency on support-annotations. */ - configurations.all { - resolutionStrategy { - force 'com.android.support:support-annotations:27.1.1' - force 'com.google.code.findbugs:jsr305:1.3.9' - } +configurations.all { + resolutionStrategy { + force 'com.android.support:support-annotations:27.1.1' + force 'com.google.code.findbugs:jsr305:1.3.9' } +} - /* +/* All direct/transitive dependencies shared between your test and production APKs need to be excluded from the test APK! This is necessary because both APKs will contain the same classes. Not excluding these dependencies from your test configuration will result in an dex pre-verifier error at runtime. More info in this tools bug: (https://code.google.com/p/android/issues/detail?id=192497) */ - configurations.compile.dependencies.each { compileDependency -> +configurations.compile.dependencies.each { compileDependency -> println "Excluding compile dependency: ${compileDependency.getName()}" configurations.androidTestCompile.dependencies.each { androidTestCompileDependency -> configurations.androidTestCompile.exclude module: "${compileDependency.getName()}" } - } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 42c9f1bd..c9a877f2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,28 +1,34 @@ + package="org.mifos.mobile.cn"> - - + + + + + + + - + - + - + - @@ -38,9 +44,23 @@ - + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/data/datamanager/DataManagerAuth.kt b/app/src/main/kotlin/org/mifos/mobile/cn/data/datamanager/DataManagerAuth.kt index e75955b3..ed77ff34 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/data/datamanager/DataManagerAuth.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/data/datamanager/DataManagerAuth.kt @@ -1,9 +1,14 @@ package org.mifos.mobile.cn.data.datamanager +import android.util.Base64 import io.reactivex.Observable +import io.reactivex.ObservableSource +import io.reactivex.functions.Function import org.mifos.mobile.cn.data.local.PreferencesHelper import org.mifos.mobile.cn.data.models.Authentication import org.mifos.mobile.cn.data.remote.BaseApiManager +import org.mifos.mobile.cn.fakesource.FakeRemoteDataSource +import java.nio.charset.Charset import javax.inject.Inject import javax.inject.Singleton @@ -43,6 +48,10 @@ class DataManagerAuth @Inject constructor(private val baseApiManager: BaseApiMan return@concatMap Observable.just(loginResponse) }) }*/ + fun login(username: String, password: String): Observable { + return baseApiManager.getAuthApi().login(username, + Base64.encodeToString(password.toByteArray(Charset.forName("UTF-8")), Base64.NO_WRAP)) + } fun refreshToken(): Observable { return baseApiManager.getAuthApi().refreshToken() } diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/data/local/PreferenceKey.kt b/app/src/main/kotlin/org/mifos/mobile/cn/data/local/PreferenceKey.kt index 05358c3c..7e1e067b 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/data/local/PreferenceKey.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/data/local/PreferenceKey.kt @@ -2,12 +2,12 @@ package org.mifos.mobile.cn.data.local object PreferenceKey { - const val PREF_ICOMMIT = "preferences_icommit" + const val PREF_MIFOS = "preferences_mifos" const val PREF_KEY_ACCESS_TOKEN = "PREF_KEY_ACCESS_TOKEN" - + const val PREF_KEY_COOKIES = "PREF_KEY_COOKIES" const val PREF_KEY_LOGIN_STATUS = "PREF_KEY_LOGIN_STATUS" - + const val PREF_KEY_TENANT_IDENTIFIER = "PREF_KEY_TENANT_IDENTIFIER" const val PREF_KEY_USER_NAME = "PREF_KEY_USER_NAME" //TODO:remove this while implementing API diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/data/local/PreferencesHelper.kt b/app/src/main/kotlin/org/mifos/mobile/cn/data/local/PreferencesHelper.kt index 316a3a7e..f739c12a 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/data/local/PreferencesHelper.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/data/local/PreferencesHelper.kt @@ -15,7 +15,7 @@ class PreferencesHelper constructor(@ApplicationContext context: Context) { private val preferences: SharedPreferences = context.getSharedPreferences( - PreferenceKey.PREF_ICOMMIT, Context.MODE_PRIVATE) + PreferenceKey.PREF_MIFOS, Context.MODE_PRIVATE) private val gson: Gson = GsonBuilder() .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz") .create() @@ -74,11 +74,12 @@ constructor(@ApplicationContext context: Context) { fun putAccessToken(accessToken: String) { preferences.edit().putString( - PreferenceKey.PREF_KEY_ACCESS_TOKEN, "Basic $accessToken").apply() + PreferenceKey.PREF_KEY_ACCESS_TOKEN, accessToken).apply() } - val accessToken: String - get() = preferences.getString(PreferenceKey.PREF_KEY_ACCESS_TOKEN, null) + fun getAccessToken(): String? { + return preferences.getString(PreferenceKey.PREF_KEY_ACCESS_TOKEN, null) + } fun putLoginStatus(loginStatus: Boolean) { preferences.edit().putBoolean(PreferenceKey.PREF_KEY_LOGIN_STATUS, loginStatus).apply() @@ -91,26 +92,34 @@ constructor(@ApplicationContext context: Context) { preferences.edit().putString(PreferenceKey.PREF_KEY_USER_NAME, username).apply() } + fun getUserName(): String? { + return preferences.getString(PreferenceKey.PREF_KEY_USER_NAME, null) + } fun getSignedInUser(): Authentication? { val userJson = preferences.getString(PreferenceKey.PREF_KEY_SIGNED_IN_USER, null) ?: return null - return gson.fromJson(userJson, Authentication::class.java!!) + return gson.fromJson(userJson, Authentication::class.java) } fun putSignInUser(user: Authentication) { preferences.edit().putString(PreferenceKey.PREF_KEY_SIGNED_IN_USER, gson.toJson(user)).apply() } + fun putTenantIdentifier(tenantIdentifier: String) { + preferences.edit().putString(PreferenceKey.PREF_KEY_TENANT_IDENTIFIER, + tenantIdentifier).apply() + } - val username: String - get() = preferences.getString(PreferenceKey.PREF_KEY_USER_NAME, null) + fun getTenantIdentifier(): String? { + return preferences.getString(PreferenceKey.PREF_KEY_TENANT_IDENTIFIER, null) + } //TODO: remove the password prefernce helper - fun putPassword(password: String) { + /* fun putPassword(password: String) { preferences.edit().putString(PreferenceKey.PREF_KEY_PASSWORD, password).apply() } val password: String get() = preferences.getString(PreferenceKey.PREF_KEY_PASSWORD, null) - +*/ } diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/data/models/beneficiaries/listBeneficiaries.kt b/app/src/main/kotlin/org/mifos/mobile/cn/data/models/beneficiaries/listBeneficiaries.kt new file mode 100644 index 00000000..49e9aade --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/data/models/beneficiaries/listBeneficiaries.kt @@ -0,0 +1,3 @@ +package org.mifos.mobile.cn.data.models.beneficiaries + +data class Beneficiary(val name: String, val description: String, val price: String) \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/BaseUrl.kt b/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/BaseUrl.kt index c4e3ba89..e56962e5 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/BaseUrl.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/BaseUrl.kt @@ -9,9 +9,9 @@ import org.mifos.mobile.cn.BuildConfig object BaseUrl { private const val PROTOCOL_HTTPS = "http://" - private const val API_TEST_ENDPOINT = "example.com" + private const val API_TEST_ENDPOINT = "buffalo.mifos.io" private const val API_PRODUCTION_ENDPOINT = "example.com" - private const val PORT = "8000" + private const val PORT = "4200" // "/" in the last of the base url always val defaultBaseUrl: String diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/ConnectivityInterceptor.kt b/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/ConnectivityInterceptor.kt new file mode 100644 index 00000000..e15e599e --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/ConnectivityInterceptor.kt @@ -0,0 +1,24 @@ +package org.mifos.mobile.cn.data.remote + +import android.content.Context +import okhttp3.Interceptor +import okhttp3.Response +import org.mifos.mobile.cn.exceptions.NoConnectivityException +import org.mifos.mobile.cn.ui.utils.Network +import java.io.IOException + +/** + * @author Rajan Maurya + * On 23/09/17. + */ +class ConnectivityInterceptor(private val context: Context) : Interceptor { + @Throws(IOException::class) + override fun intercept(chain: Interceptor.Chain): Response { + if (!Network.isConnected(context)) { + throw NoConnectivityException() + } + val builder = chain.request().newBuilder() + return chain.proceed(builder.build()) + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/MifosInterceptor.kt b/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/MifosInterceptor.kt index f72e71e4..5bd66d13 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/MifosInterceptor.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/MifosInterceptor.kt @@ -1,14 +1,16 @@ package org.mifos.mobile.cn.data.remote import android.content.Context -import androidx.annotation.NonNull import android.text.TextUtils +import androidx.annotation.NonNull import okhttp3.Interceptor import okhttp3.Response import org.mifos.mobile.cn.MifosApplication +import org.mifos.mobile.cn.data.local.PreferenceKey import org.mifos.mobile.cn.data.local.PreferencesHelper import org.mifos.mobile.cn.injection.ApplicationContext import java.io.IOException +import java.util.* import javax.inject.Inject class MifosInterceptor @Inject constructor(@ApplicationContext context: Context) : Interceptor { @@ -22,6 +24,11 @@ class MifosInterceptor @Inject constructor(@ApplicationContext context: Context) companion object { val HEADER_ACCESS_TOKEN = "access_token" + val HEADER_TENANT = "X-Tenant-Identifier" + val HEADER_AUTH = "Authorization" + val HEADER_ACCEPT_JSON = "Accept" + val HEADER_CONTENT_TYPE = "Content-type" + val HEADER_USER = "User" } @Throws(IOException::class) @@ -29,11 +36,42 @@ class MifosInterceptor @Inject constructor(@ApplicationContext context: Context) val chainRequest = chain.request() val builder = chainRequest.newBuilder() - val accessToken = preferencesHelper.accessToken + //TODO fix call single time instead of calling every request + val authToken: String? = preferencesHelper.getAccessToken() + val tenantIdentifier = preferencesHelper.getTenantIdentifier() + val user: String? = preferencesHelper.getUserName() + val refreshTokenStatus = preferencesHelper.getBoolean( + PreferenceKey.PREF_KEY_REFRESH_ACCESS_TOKEN, false) + + builder.header(HEADER_ACCEPT_JSON, "application/json") + builder.header(HEADER_CONTENT_TYPE, "application/json") + + if (refreshTokenStatus) { + //Add Cookies + val cookies = preferencesHelper.getStringSet( + PreferenceKey.PREF_KEY_COOKIES) as HashSet? + if (cookies != null) { + for (cookie in cookies) { + builder.addHeader("Cookie", cookie) + } + } + } else { + if (!TextUtils.isEmpty(authToken)) { + builder.header(HEADER_AUTH, authToken) + } + if (!TextUtils.isEmpty(user)) { + builder.header(HEADER_USER, user) + } + } + + if (!TextUtils.isEmpty(tenantIdentifier)) { + builder.header(HEADER_TENANT, "tn01") + } + /*val accessToken = preferencesHelper.accessToken if (!TextUtils.isEmpty(accessToken)) { builder.header(HEADER_ACCESS_TOKEN, preferencesHelper.accessToken) - } + }*/ val request = builder.build() return chain.proceed(request) diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/MifosOkHttpClient.kt b/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/MifosOkHttpClient.kt index 794f2418..199c56f9 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/MifosOkHttpClient.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/data/remote/MifosOkHttpClient.kt @@ -73,13 +73,13 @@ class MifosOkHttpClient constructor(private val context: Context) { logger.level = HttpLoggingInterceptor.Level.BODY //Setting Timeout 120 Seconds - okHttpBuilder.connectTimeout(120, TimeUnit.SECONDS) - okHttpBuilder.readTimeout(120, TimeUnit.SECONDS) + okHttpBuilder.connectTimeout(60, TimeUnit.SECONDS) + okHttpBuilder.readTimeout(60, TimeUnit.SECONDS) //Interceptor :> Full Body Logger and ApiRequest Header okHttpBuilder.addInterceptor(logger) + okHttpBuilder.addInterceptor(ConnectivityInterceptor(context)) okHttpBuilder.addInterceptor(MifosInterceptor(context)) - return okHttpBuilder.build() } } \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/data/services/AuthService.kt b/app/src/main/kotlin/org/mifos/mobile/cn/data/services/AuthService.kt index 01e7f719..ba794e92 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/data/services/AuthService.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/data/services/AuthService.kt @@ -3,7 +3,10 @@ package org.mifos.mobile.cn.data.services import io.reactivex.Observable import org.mifos.mobile.cn.data.models.Authentication import org.mifos.mobile.cn.data.remote.EndPoints +import retrofit2.http.Header +import retrofit2.http.Headers import retrofit2.http.POST +import retrofit2.http.Query /** * @author Rajan Maurya @@ -13,6 +16,12 @@ interface AuthService { /*@GET("/authentication") fun login(loginRequest: LoginRequest): Observable*/ + //@Headers("X-Tenant-Identifier: tn01") + @POST(EndPoints.API_IDENTITY_PATH + "/token?grant_type=password") + abstract fun login( + @Query("username") username: String, + @Query("password") password: String): Observable + @POST(EndPoints.API_IDENTITY_PATH + "/token?grant_type=refresh_token") abstract fun refreshToken(): Observable } \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/injection/component/ActivityComponent.kt b/app/src/main/kotlin/org/mifos/mobile/cn/injection/component/ActivityComponent.kt index 13cbf11c..b67631ae 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/injection/component/ActivityComponent.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/injection/component/ActivityComponent.kt @@ -4,6 +4,7 @@ package org.mifos.mobile.cn.injection.component import dagger.Subcomponent import org.mifos.mobile.cn.injection.PerActivity import org.mifos.mobile.cn.injection.module.ActivityModule +import org.mifos.mobile.cn.ui.mifos.Account import org.mifos.mobile.cn.ui.mifos.DashboardActivity import org.mifos.mobile.cn.ui.mifos.aboutus.AboutUsFragment import org.mifos.mobile.cn.ui.mifos.accounts.AccountsFragment @@ -39,6 +40,8 @@ interface ActivityComponent { fun inject(passcodeActivity: PasscodeActivity) + fun inject(account :Account) + fun inject(launcherActivity: LauncherActivity) fun inject(dashboardActivity: DashboardActivity) diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/injection/component/ApplicationComponent.kt b/app/src/main/kotlin/org/mifos/mobile/cn/injection/component/ApplicationComponent.kt index dbb4f285..fbc3f01b 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/injection/component/ApplicationComponent.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/injection/component/ApplicationComponent.kt @@ -11,6 +11,7 @@ import org.mifos.mobile.cn.data.local.PreferencesHelper import org.mifos.mobile.cn.data.remote.MifosInterceptor import org.mifos.mobile.cn.injection.ApplicationContext import org.mifos.mobile.cn.injection.module.ApplicationModule +import javax.inject.Inject import javax.inject.Singleton @Singleton diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/adapter/BeneficiariesAdapter.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/adapter/BeneficiariesAdapter.kt new file mode 100644 index 00000000..61c64a50 --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/adapter/BeneficiariesAdapter.kt @@ -0,0 +1,35 @@ +package org.mifos.mobile.cn.ui.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.data.models.beneficiaries.Beneficiary + + +class BeneficiariesAdapter(val beneficiariesList: ArrayList) : RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val v = LayoutInflater.from(parent.context).inflate(R.layout.item_beneficiaries, parent, false) + return ViewHolder(v) + } + + override fun getItemCount(): Int { + return beneficiariesList.size + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val list: Beneficiary = beneficiariesList[position] + holder.textViewName?.text = list.name + holder.textViewDescription?.text = list.description + holder.textViewPrice?.text = list.price + } + + class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val textViewName = itemView.findViewById(R.id.tv_name) + val textViewDescription = itemView.findViewById(R.id.tv_beneficiaries_decription) + val textViewPrice = itemView.findViewById(R.id.tv_price) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/base/MifosBaseFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/base/MifosBaseFragment.kt index ff78b31b..078c39c7 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/base/MifosBaseFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/base/MifosBaseFragment.kt @@ -63,7 +63,7 @@ open class MifosBaseFragment : Fragment() { callback.showTabLayout(false) } - override fun onAttach(context: Context?) { + override fun onAttach(context: Context) { super.onAttach(context) val activity = context as? Activity try { diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Account.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Account.kt new file mode 100644 index 00000000..4a7abcd4 --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Account.kt @@ -0,0 +1,292 @@ +package org.mifos.mobile.cn.ui.mifos + +import android.app.SearchManager +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.viewpager.widget.ViewPager +import androidx.appcompat.widget.SearchView +import android.view.* +import android.widget.Toast +import kotlinx.android.synthetic.main.fragment_client_accounts.* +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.data.models.accounts.deposit.DepositAccount +import org.mifos.mobile.cn.data.models.accounts.loan.LoanAccount +import org.mifos.mobile.cn.enums.AccountType +import org.mifos.mobile.cn.ui.adapter.ViewPagerAdapter +import org.mifos.mobile.cn.ui.base.MifosBaseActivity +import org.mifos.mobile.cn.ui.base.MifosBaseFragment +import org.mifos.mobile.cn.ui.mifos.accounts.AccountsContract +import org.mifos.mobile.cn.ui.mifos.accounts.AccountsFragment +import org.mifos.mobile.cn.ui.mifos.accounts.AccountsPresenter +import org.mifos.mobile.cn.ui.mifos.accountsFilter.AccountsFilterBottomSheet +import org.mifos.mobile.cn.ui.mifos.customerAccounts.CustomerAccountFragment +import org.mifos.mobile.cn.ui.mifos.loanApplication.loanActivity.LoanApplicationActivity +import org.mifos.mobile.cn.ui.utils.ConstantKeys +import org.mifos.mobile.cn.ui.utils.StatusUtils +import javax.inject.Inject + +class Account : MifosBaseFragment() , AccountsContract.View { + private lateinit var accountType: AccountType + + + @Inject + internal lateinit var accountsPresenter: AccountsPresenter + + companion object { + fun newInstance(accountType: AccountType): CustomerAccountFragment { + val fragment = CustomerAccountFragment() + val args = Bundle() + args.putSerializable(ConstantKeys.ACCOUNT_TYPE, accountType) + fragment.arguments = args + return fragment + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setHasOptionsMenu(true) + if (arguments != null) { + accountType = arguments!!.getSerializable(ConstantKeys.ACCOUNT_TYPE) as AccountType + } + + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val rootview: View = inflater.inflate(R.layout.fragment_client_accounts, + container, false) + (activity as MifosBaseActivity).activityComponent.inject(this) + accountsPresenter.attachView(this) + return rootview + + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setUpViewPagerAndTabLayout() + setToolbarTitle(getString(R.string.accounts)) + accountsPresenter.loadLoanAccounts() + accountsPresenter.loadDepositAccounts() + } + + /** + * Returns tag of Fragment present at `position` + * @param position position of Fragment + * @return Tag of Fragment + */ + private fun getFragmentTag(position: Int): String { + return "android:switcher:" + R.id.viewpager + ":" + position + } + + + private fun setUpViewPagerAndTabLayout() { + val viewPagerAdapter = ViewPagerAdapter(childFragmentManager) + viewPagerAdapter.addFragment(AccountsFragment.newInstance(ConstantKeys.DEPOSIT_ACCOUNTS), + getString(R.string.deposit)) + viewPagerAdapter.addFragment(AccountsFragment.newInstance(ConstantKeys.LOAN_ACCOUNTS), + getString(R.string.loan)) + viewpager.adapter = viewPagerAdapter + viewpager.offscreenPageLimit = 2 + when (accountType) { + AccountType.DEPOSIT -> viewpager.currentItem = 0 + AccountType.LOAN -> viewpager.currentItem = 1 + } + + deposit_toggle_btn.setOnClickListener { + viewpager.currentItem = 0 + } + loan_toggle_btn.setOnClickListener { + viewpager.currentItem = 1 + } + + tabs.setupWithViewPager(viewpager) + viewpager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled(position: Int, positionOffset: Float, + positionOffsetPixels: Int) { + activity?.invalidateOptionsMenu() + (activity as MifosBaseActivity).hideKeyBoard(view!!) + } + + override fun onPageSelected(position: Int) {} + + override fun onPageScrollStateChanged(state: Int) {} + }) + + + } + + /** + * It provides with `loanAccounts` fetched from server which is then passed to fragment + * implementing [AccountsContract.View] i.e. [AccountsFragment] which further displays them + * in a recyclerView + * @param loanAccounts [List] of [LoanAccount] + */ + override fun showLoanAccounts(loanAccounts: List) { + + (childFragmentManager.findFragmentByTag(getFragmentTag(1)) as AccountsContract.View) + .showLoanAccounts(loanAccounts) + (childFragmentManager.findFragmentByTag(getFragmentTag(1)) as AccountsContract.View) + .hideProgress() + } + + /** + * It provides with `depositAccounts` fetched from server which is then passed to fragment + * implementing [AccountsContract.View] i.e. [AccountsFragment] which further displays them + * in a recyclerView + * @param depositAccounts [List] of [DepositAccount] + */ + + override fun showDepositAccounts(depositAccounts: List) { + (childFragmentManager.findFragmentByTag(getFragmentTag(0)) as AccountsContract.View) + .showDepositAccounts(depositAccounts) + (childFragmentManager.findFragmentByTag(getFragmentTag(0)) as AccountsContract.View) + .hideProgress() + } + + + override fun showError(message: String) { + (childFragmentManager.findFragmentByTag(getFragmentTag(1)) as AccountsContract.View) + .showError(getString(R.string.loan)) + (childFragmentManager.findFragmentByTag(getFragmentTag(0)) as AccountsContract.View) + .showError(getString(R.string.deposit)) + Toast.makeText(activity, message, Toast.LENGTH_SHORT).show() + } + + override fun showEmptyAccounts(feature: String) { + (childFragmentManager.findFragmentByTag(getFragmentTag(1)) as AccountsContract.View) + .showEmptyAccounts(getString(R.string.loan)) + (childFragmentManager.findFragmentByTag(getFragmentTag(0)) as AccountsContract.View) + .showEmptyAccounts(getString(R.string.deposit)) + } + + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + inflater?.inflate(R.menu.menu_account, menu) + if (viewpager.currentItem == 1) { + loan_toggle_focus_btn.visibility = View.VISIBLE + deposit_toggle_focus_btn.visibility = View.GONE + iv_apply_for_loan.visibility = View.VISIBLE + applyForLoan() + menu?.findItem(R.id.menu_filter_loan)?.isVisible = true + menu?.findItem(R.id.menu_filter_deposit)?.isVisible = false + menu?.findItem(R.id.menu_search_loan)?.isVisible = true + menu?.findItem(R.id.menu_search_deposit)?.isVisible = false + initSearch(menu!!, AccountType.LOAN) + } else if (viewpager.currentItem == 0) { + deposit_toggle_focus_btn.visibility = View.VISIBLE + loan_toggle_focus_btn.visibility = View.GONE + iv_apply_for_loan.visibility = View.GONE + menu?.findItem(R.id.menu_filter_loan)?.isVisible = false + menu?.findItem(R.id.menu_filter_deposit)?.isVisible = true + menu?.findItem(R.id.menu_search_deposit)?.isVisible = true + menu?.findItem(R.id.menu_search_loan)?.isVisible = false + initSearch(menu!!, AccountType.DEPOSIT) + } + super.onCreateOptionsMenu(menu, inflater) + + } + + private fun applyForLoan() { + iv_apply_for_loan.setOnClickListener(View.OnClickListener { + val intent = Intent(activity, LoanApplicationActivity::class.java) + intent.putExtra(ConstantKeys.CUSTOMER_IDENTIFIER, "customer_identifier") + startActivity(intent) + }) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item?.itemId) { + R.id.menu_filter_loan -> showFilterDialog(AccountType.LOAN) + R.id.menu_filter_deposit -> showFilterDialog(AccountType.DEPOSIT) + } + return true + } + + private fun showFilterDialog(accountType: AccountType) { + val accountFilterBottomSheet = AccountsFilterBottomSheet() + when (accountType) { + AccountType.LOAN -> { + if ((childFragmentManager.findFragmentByTag(getFragmentTag(1)) + as AccountsFragment).currentFilterList == null) { + accountFilterBottomSheet.filterList = StatusUtils.getLoanAccountsStatusList(context!!) + } else { + accountFilterBottomSheet.filterList = (childFragmentManager + .findFragmentByTag(getFragmentTag(1)) + as AccountsFragment).currentFilterList + } + } + + AccountType.DEPOSIT -> { + if ((childFragmentManager.findFragmentByTag(getFragmentTag(0)) + as AccountsFragment).currentFilterList == null) { + accountFilterBottomSheet.filterList = StatusUtils.getDepositAccountsStatusList(context!!) + } else { + accountFilterBottomSheet.filterList = (childFragmentManager + .findFragmentByTag(getFragmentTag(0)) + as AccountsFragment).currentFilterList + } + } + + } + + accountFilterBottomSheet.accountType = accountType + accountFilterBottomSheet.show(childFragmentManager, getString(R.string.filter_accounts)) + } + + /** + * Initializes the search option in [Menu] depending upon `account` + * @param menu Interface for managing the items in a menu. + * @param account An enum of [AccountType] + */ + private fun initSearch(menu: Menu, account: AccountType) { + val manager = activity?.getSystemService(Context.SEARCH_SERVICE) as SearchManager + var search: SearchView? = null + + if (account == AccountType.LOAN) { + search = menu.findItem(R.id.menu_search_loan).actionView as SearchView + } else if (account == AccountType.DEPOSIT) { + search = menu.findItem(R.id.menu_search_deposit).actionView as SearchView + } + + search!!.setSearchableInfo(manager.getSearchableInfo(activity?.componentName)) + search.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + return false + } + + override fun onQueryTextChange(newText: String): Boolean { + + if (account == AccountType.LOAN) { + (childFragmentManager.findFragmentByTag( + getFragmentTag(1)) as AccountsFragment).searchLoanAccount(newText) + } else if (account == AccountType.DEPOSIT) { + (childFragmentManager.findFragmentByTag( + getFragmentTag(0)) as AccountsFragment).searchDepositAccount(newText) + } + + return false + } + }) + } + + override fun showProgress() { + + } + + override fun hideProgress() { + + } + + + override fun onResume() { + super.onResume() + (activity as MifosBaseActivity).hideToolbarElevation() + } + + override fun onPause() { + super.onPause() + (activity as MifosBaseActivity).setToolbarElevation() + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Home.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Home.kt new file mode 100644 index 00000000..7eefcfa4 --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Home.kt @@ -0,0 +1,89 @@ +package org.mifos.mobile.cn.ui.mifos + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.google.android.material.bottomsheet.BottomSheetBehavior +import kotlinx.android.synthetic.main.content_fragment_dashboard.* +import kotlinx.android.synthetic.main.fragment_home.* +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.ui.base.MifosBaseFragment +import org.mifos.mobile.cn.ui.mifos.recentTransactions.RecentTransactionsFragment + + +class Home : MifosBaseFragment(), View.OnClickListener { + + private lateinit var rootView: View + private lateinit var sheetBehavior: BottomSheetBehavior<*> + + companion object { + fun newInstance(): Home = Home() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + rootView = inflater.inflate(R.layout.fragment_home, container, false) + val ft = childFragmentManager.beginTransaction() + val rt = RecentTransactionsFragment() + ft.replace(R.id.fl_recentTransactions, rt) + ft.addToBackStack(null) + ft.commit() + return rootView + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + sheetBehavior = BottomSheetBehavior.from(rt_bottom_sheet) + sheetBehavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { + override fun onStateChanged(bottomSheet: View, newState: Int) { + // React to state change + when (newState) { + BottomSheetBehavior.STATE_HIDDEN -> { + } + BottomSheetBehavior.STATE_EXPANDED -> { + } + BottomSheetBehavior.STATE_COLLAPSED -> { + } + BottomSheetBehavior.STATE_HALF_EXPANDED -> { + } + BottomSheetBehavior.STATE_DRAGGING -> { + } + BottomSheetBehavior.STATE_SETTLING -> { + } + } + } + + override fun onSlide(bottomSheet: View, slideOffset: Float) { + // React to dragging events + } + }) + receive.setOnClickListener(this) + sendit.setOnClickListener(this) + + } + + override fun onClick(view: View) { + + when (view.id) { + R.id.receive ->{ + qrcode() + } + R.id.sendit ->{ + sendmoney() + } + } + } + + private fun sendmoney() { + val intent = Intent(activity, Send::class.java) + startActivity(intent) + } + + private fun qrcode() { + val intent = Intent(activity, QRGenerator::class.java) + startActivity(intent) + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Main.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Main.kt new file mode 100644 index 00000000..f0aae40f --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Main.kt @@ -0,0 +1,75 @@ +package org.mifos.mobile.cn.ui.mifos + +import android.os.Bundle +import androidx.annotation.NonNull +import androidx.fragment.app.Fragment +import com.google.android.material.bottomnavigation.BottomNavigationView +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.enums.AccountType +import org.mifos.mobile.cn.ui.base.MifosBaseActivity +import org.mifos.mobile.cn.ui.utils.ConstantKeys +import android.view.MenuItem as MenuItem1 + + +class Main : MifosBaseActivity(), BottomNavigationView.OnNavigationItemSelectedListener { + private var bottomNavigationView: BottomNavigationView? = null + private var menuItem = -1 + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_home) + + bottomNavigationView = findViewById(R.id.bottom_navigation) + setupNavigationBar() + bottomNavigationView?.run { setSelectedItemId(R.id.action_home) + } + + + } + + override fun onNavigationItemSelected(item: MenuItem1): Boolean { + clearFragmentBackStack() + setToolbarElevation() + menuItem = item.itemId +navigateFragment(item.itemId,false) + return true + } + private fun setupNavigationBar() { + + bottomNavigationView?.setOnNavigationItemSelectedListener { item -> + navigateFragment(item.itemId, false) + true + } + + } + override fun onBackPressed() { + val fragment: Fragment? = supportFragmentManager + .findFragmentById(R.id.bottom_navigation_fragment_container) + if (fragment != null && fragment !is Home && fragment.isVisible()) { + navigateFragment(R.id.action_home, true) + return + } + val count = supportFragmentManager.backStackEntryCount + if (count == 0) { + super.onBackPressed() + //additional code + } else { + supportFragmentManager.popBackStack() + } + } + private fun navigateFragment(id: Int, shouldSelect: Boolean) { + if (shouldSelect) { + bottomNavigationView?.setSelectedItemId(id) + } else { + when (id) { + R.id.action_home -> replaceFragment(Home.newInstance(), false, + R.id.bottom_navigation_fragment_container) + R.id.action_acounts -> replaceFragment(Account.newInstance(AccountType.DEPOSIT), false, + R.id.bottom_navigation_fragment_container) + R.id.action_transfer -> replaceFragment(Transfer.newInstance(), false, + R.id.bottom_navigation_fragment_container) + R.id.action_profile -> replaceFragment(Profile.newInstance(), false, + R.id.bottom_navigation_fragment_container) + } + } + } +} diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Notification.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Notification.kt new file mode 100644 index 00000000..a1cc4d1e --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Notification.kt @@ -0,0 +1,14 @@ +package org.mifos.mobile.cn.ui.mifos + +import android.os.Bundle +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.ui.base.MifosBaseActivity + +class Notification: MifosBaseActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_notification) + showBackButton() + setToolbarTitle(getString(R.string.notification)) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Profile.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Profile.kt new file mode 100644 index 00000000..e7bd605c --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Profile.kt @@ -0,0 +1,57 @@ +package org.mifos.mobile.cn.ui.mifos + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.PopupWindow +import android.widget.RelativeLayout +import kotlinx.android.synthetic.main.fragment_client_accounts.* +import kotlinx.android.synthetic.main.fragment_profile.* +import kotlinx.android.synthetic.main.menu_layout.* +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.ui.base.MifosBaseFragment +import org.mifos.mobile.cn.ui.mifos.beneficiaries.BeneficiariesActivity + + +class Profile : MifosBaseFragment(){ + var mypopupWindow: PopupWindow? = null + companion object { + fun newInstance(): Profile = Profile() + } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + // Inflate the layout for this fragment + getToolbar().setVisibility(View.GONE); + return inflater.inflate(R.layout.fragment_profile, container, false) + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + notify.setOnClickListener { + val intent = Intent(activity, Notification::class.java) + startActivity(intent) + } + setPopUpWindow(view) + val clickListener = View.OnClickListener { view -> + when (view.id) { + R.id.image_menu -> { + mypopupWindow?.showAsDropDown(view,0,0); + } + } + } + + image_menu.setOnClickListener(clickListener) + } + + private fun setPopUpWindow(view: View) { + val view = LayoutInflater.from(context).inflate(R.layout.menu_layout, null) + mypopupWindow = PopupWindow(view, 350, RelativeLayout.LayoutParams.WRAP_CONTENT, true) + val beneficiary = view.findViewById(R.id.text_beneficiary) as RelativeLayout + beneficiary.setOnClickListener(View.OnClickListener { + val intent = Intent(activity, BeneficiariesActivity::class.java) + startActivity(intent) + }) + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/QRCodeHelper.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/QRCodeHelper.kt new file mode 100644 index 00000000..921d60b8 --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/QRCodeHelper.kt @@ -0,0 +1,81 @@ +package org.mifos.mobile.cn.ui.mifos + +import android.content.Context +import android.graphics.Bitmap +import android.util.Log +import androidx.annotation.IntRange +import com.google.zxing.BarcodeFormat +import com.google.zxing.EncodeHintType +import com.google.zxing.WriterException +import com.google.zxing.qrcode.QRCodeWriter +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel +import java.util.* + +class QRCodeHelper private constructor(context: Context) { + private var mErrorCorrectionLevel: ErrorCorrectionLevel? = null + private var mMargin = 0 + private var mContent: String? = null + private var mWidth: Int + private var mHeight: Int + val qRCOde: Bitmap? + get() = generate() + + fun setErrorCorrectionLevel(level: ErrorCorrectionLevel?): QRCodeHelper { + mErrorCorrectionLevel = level + return this + } + fun setContent(content: String?): QRCodeHelper { + mContent = content + return this + } + fun setWidthAndHeight(@IntRange(from = 1) width: Int, @IntRange(from = 1) height: Int): QRCodeHelper { + mWidth = width + mHeight = height + return this + } + fun setMargin(@IntRange(from = 0) margin: Int): QRCodeHelper { + mMargin = margin + return this + } + private fun generate(): Bitmap? { + val hintsMap: MutableMap = HashMap() + hintsMap[EncodeHintType.CHARACTER_SET] = "utf-8" + hintsMap[EncodeHintType.ERROR_CORRECTION] = mErrorCorrectionLevel + hintsMap[EncodeHintType.MARGIN] = mMargin + try { + val bitMatrix = QRCodeWriter().encode(mContent, BarcodeFormat.QR_CODE, mWidth, mHeight, hintsMap) + val pixels = IntArray(mWidth * mHeight) + for (i in 0 until mHeight) { + for (j in 0 until mWidth) { + if (bitMatrix[j, i]) { + pixels[i * mWidth + j] = -0x1000000 + } else { + pixels[i * mWidth + j] = -0x1 + } + } + } + return Bitmap.createBitmap(pixels, mWidth, mHeight, Bitmap.Config.ARGB_8888) + } catch (e: WriterException) { + e.printStackTrace() + } + return null + } + + companion object { + private var qrCodeHelper: QRCodeHelper? = null + + fun newInstance(context: Context): QRCodeHelper? { + if (qrCodeHelper == null) { + qrCodeHelper = QRCodeHelper(context) + } + return qrCodeHelper + } + } + + init { + mHeight = (context.resources.displayMetrics.heightPixels / 2.4).toInt() + mWidth = (context.resources.displayMetrics.widthPixels / 1.3).toInt() + Log.e("Dimension = %s", mHeight.toString() + "") + Log.e("Dimension = %s", mWidth.toString() + "") + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/QRGenerator.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/QRGenerator.kt new file mode 100644 index 00000000..5746f331 --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/QRGenerator.kt @@ -0,0 +1,59 @@ +package org.mifos.mobile.cn.ui.mifos + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.text.TextUtils +import android.view.View +import android.view.inputmethod.InputMethodManager +import android.widget.Toast +import com.google.gson.Gson +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel +import kotlinx.android.synthetic.main.qrgenerator.* +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.ui.base.MifosBaseActivity + +class QRGenerator: MifosBaseActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.qrgenerator) + setToolbarTitle(getString(R.string.home)) + getToolbar().setVisibility(View.GONE) + generateQrCodeButton.setOnClickListener { + if (checkEditText()) { + hideKeyboard() + val user = UserObject(name = fullNameEditText.text.toString(), mobile = mobileEditText.text.toString(),email = emailEditText.text.toString(),accountNumber = accountEditText.text.toString()) + val serializeString = Gson().toJson(user) + setImageBitmap(serializeString) + } + } + } + + private fun setImageBitmap(encryptedString: String?) { + val bitmap = QRCodeHelper.newInstance(this)?.setContent(encryptedString)?.setErrorCorrectionLevel(ErrorCorrectionLevel.Q)?.setMargin(2)?.qRCOde + qrCodeImageView.setImageBitmap(bitmap) + } + + /** + * Hides the soft input keyboard if it is shown to the screen. + */ + + private fun hideKeyboard() { + val view = this.currentFocus + if (view != null) { + val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(view.windowToken, 0) + } + } + + private fun checkEditText(): Boolean { + if (TextUtils.isEmpty(fullNameEditText.text.toString())) { + Toast.makeText(this, "fullName field cannot be empty!", Toast.LENGTH_SHORT).show() + return false + } else if (TextUtils.isEmpty(mobileEditText.text.toString())) { + Toast.makeText(this, "Mobile number field cannot be empty!", Toast.LENGTH_SHORT).show() + return false + } + return true + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Send.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Send.kt new file mode 100644 index 00000000..fb28b637 --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Send.kt @@ -0,0 +1,43 @@ +package org.mifos.mobile.cn.ui.mifos + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import com.hover.sdk.actions.HoverAction +import com.hover.sdk.api.Hover +import com.hover.sdk.api.HoverParameters +import com.hover.sdk.permissions.PermissionActivity +import kotlinx.android.synthetic.main.activity_send.* +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.ui.base.MifosBaseActivity +import java.util.ArrayList + +class Send : MifosBaseActivity(),Hover.DownloadListener { + private val TAG = "SendActivity" + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_send) + showBackButton() + setToolbarTitle(getString(R.string.send_money)) + Hover.initialize(applicationContext,this) + send.setOnClickListener(){ + val intent = Intent(applicationContext, PermissionActivity::class.java) + startActivityForResult(intent, 0) + val i = HoverParameters.Builder(this@Send) + .request("Add action id") // Add your action ID here + .extra("phoneNumber", phonetext.text.toString()) // Uncomment and add your variables if any + .extra("amount", amounttext.text.toString()) + .extra("description", descriptiontext.text.toString()) + .buildIntent() + startActivityForResult(i, 0) + } + } + + override fun onSuccess(actions: ArrayList) { + Log.d(TAG, "Successfully downloaded " + actions.size + " actions") + } + + override fun onError(message: String?) { + Log.e(TAG, "Error: $message") + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/ShowActivity.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/ShowActivity.kt new file mode 100644 index 00000000..0f8c5197 --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/ShowActivity.kt @@ -0,0 +1,13 @@ +package org.mifos.mobile.cn.ui.mifos + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import org.mifos.mobile.cn.R + +class ShowActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_show) + } +} diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Transfer.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Transfer.kt new file mode 100644 index 00000000..59adf29a --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/Transfer.kt @@ -0,0 +1,57 @@ +package org.mifos.mobile.cn.ui.mifos + +import android.Manifest +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import com.google.zxing.Result +import com.karumi.dexter.Dexter +import com.karumi.dexter.PermissionToken +import com.karumi.dexter.listener.PermissionDeniedResponse +import com.karumi.dexter.listener.PermissionGrantedResponse +import com.karumi.dexter.listener.PermissionRequest +import com.karumi.dexter.listener.single.PermissionListener +import kotlinx.android.synthetic.main.fragment_transfer.* +import me.dm7.barcodescanner.zxing.ZXingScannerView +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.ui.base.MifosBaseFragment + +class Transfer : MifosBaseFragment(), ZXingScannerView.ResultHandler { + + companion object { + fun newInstance(): Transfer = Transfer() + } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + // Inflate the layout for this fragment + getToolbar().setVisibility(View.GONE) + + return inflater.inflate(R.layout.fragment_transfer, container, false) + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + Dexter.withActivity(requireActivity()) + .withPermission(Manifest.permission.CAMERA) + .withListener(object:PermissionListener{ + override fun onPermissionGranted(response: PermissionGrantedResponse?) { + qrCodeScanner.setResultHandler(this@Transfer) + qrCodeScanner.setAutoFocus(true) + qrCodeScanner.startCamera() + } + + override fun onPermissionRationaleShouldBeShown(permission: PermissionRequest?, token: PermissionToken?) { + TODO("Not yet implemented") + } + + override fun onPermissionDenied(response: PermissionDeniedResponse?) { + Toast.makeText(requireActivity(),"You should enable this permission",Toast.LENGTH_SHORT).show() + } + + }).check() + } + override fun handleResult(rawResult: Result?) { + Toast.makeText(requireActivity(),rawResult?.text,Toast.LENGTH_SHORT).show() + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/UserObject.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/UserObject.kt new file mode 100644 index 00000000..1170b776 --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/UserObject.kt @@ -0,0 +1,3 @@ +package org.mifos.mobile.cn.ui.mifos + +class UserObject(var name: String, var mobile: String, var email: String, var accountNumber: String) \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/aboutus/AboutUsActivity.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/aboutus/AboutUsActivity.kt index 831e7386..2f186b57 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/aboutus/AboutUsActivity.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/aboutus/AboutUsActivity.kt @@ -1,7 +1,6 @@ package org.mifos.mobile.cn.ui.mifos.aboutus import android.os.Bundle -import kotlinx.android.synthetic.main.globalcontainer.* import org.mifos.mobile.cn.R import org.mifos.mobile.cn.ui.base.MifosBaseActivity diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accounts/AccountsFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accounts/AccountsFragment.kt index 66d67927..9ed2aa49 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accounts/AccountsFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accounts/AccountsFragment.kt @@ -1,14 +1,13 @@ package org.mifos.mobile.cn.ui.mifos.accounts import android.os.Bundle -import android.util.Log -import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler import kotlinx.android.synthetic.main.fragment_accounts.* +import kotlinx.android.synthetic.main.layout_exception_handler.* import org.mifos.mobile.cn.R import org.mifos.mobile.cn.data.models.accounts.deposit.DepositAccount import org.mifos.mobile.cn.data.models.accounts.loan.LoanAccount @@ -19,7 +18,6 @@ import org.mifos.mobile.cn.ui.base.MifosBaseFragment import org.mifos.mobile.cn.ui.utils.ConstantKeys import org.mifos.mobile.cn.ui.utils.Network import javax.inject.Inject -import kotlinx.android.synthetic.main.layout_sweet_exception_handler.* import org.mifos.mobile.cn.data.models.CheckboxStatus import org.mifos.mobile.cn.ui.base.OnItemClickListener import org.mifos.mobile.cn.ui.mifos.customerDepositDetails.CustomerDepositDetailsFragment @@ -115,8 +113,6 @@ class AccountsFragment : MifosBaseFragment(), AccountsContract.View, OnItemClick layoutManager.orientation = LinearLayoutManager.VERTICAL rv_accounts.layoutManager = layoutManager rv_accounts.setHasFixedSize(true) - rv_accounts.addItemDecoration(DividerItemDecoration(activity, - layoutManager.orientation)) btn_try_again.setOnClickListener { retry() } when (accountType) { @@ -143,7 +139,7 @@ class AccountsFragment : MifosBaseFragment(), AccountsContract.View, OnItemClick (activity as MifosBaseActivity).replaceFragment( CustomerDepositDetailsFragment.newInstance( depositAccounts[position].accountIdentifier!!),true,R.id.container - ) + ) } } } diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accounts/AccountsPresenter.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accounts/AccountsPresenter.kt index 4bf6799f..48563beb 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accounts/AccountsPresenter.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accounts/AccountsPresenter.kt @@ -45,14 +45,14 @@ class AccountsPresenter @Inject constructor(@ApplicationContext context: Context override fun loadLoanAccounts() { checkViewAttached() getMvpView.showProgress() - Observable.fromCallable({ FakeRemoteDataSource.getLoanAccountsJson() }).subscribe({ + Observable.fromCallable({ FakeRemoteDataSource.getLoanAccountsJson() }).subscribe { getMvpView.hideProgress() if (it.isEmpty()) { getMvpView.showEmptyAccounts(context.getString(R.string.loan)) } else { getMvpView.showLoanAccounts(it) } - }) + } } /** diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accountsFilter/AccountsFilterBottomSheet.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accountsFilter/AccountsFilterBottomSheet.kt index 19e656c9..526275f3 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accountsFilter/AccountsFilterBottomSheet.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/accountsFilter/AccountsFilterBottomSheet.kt @@ -75,7 +75,7 @@ class AccountsFilterBottomSheet : BottomSheetDialogFragment() { behavior.state = BottomSheetBehavior.STATE_EXPANDED } - override fun onCancel(dialog: DialogInterface?) { + override fun onCancel(dialog: DialogInterface) { super.onCancel(dialog) dismiss() } diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/beneficiaries/BeneficiariesActivity.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/beneficiaries/BeneficiariesActivity.kt new file mode 100644 index 00000000..74d5351c --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/beneficiaries/BeneficiariesActivity.kt @@ -0,0 +1,66 @@ +package org.mifos.mobile.cn.ui.mifos.beneficiaries + +import android.annotation.SuppressLint +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.widget.LinearLayout +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.activity_beneficiaries.* +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.data.models.beneficiaries.Beneficiary +import org.mifos.mobile.cn.ui.adapter.BeneficiariesAdapter + +class BeneficiariesActivity : AppCompatActivity() { + + @SuppressLint("ResourceAsColor") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_beneficiaries) + + val name: String = getString(R.string.name) + val description: String = getString(R.string.description) + val price: String = getString(R.string.dummy_price) + + beneficiariesRecyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false) + + val items = ArrayList() + items.add(Beneficiary(name, description, price)) + items.add(Beneficiary(name, description, price)) + items.add(Beneficiary(name, description, price)) + items.add(Beneficiary(name, description, price)) + items.add(Beneficiary(name, description, price)) + items.add(Beneficiary(name, description, price)) + items.add(Beneficiary(name, description, price)) + items.add(Beneficiary(name, description, price)) + items.add(Beneficiary(name, description, price)) + items.add(Beneficiary(name, description, price)) + + val adapter = BeneficiariesAdapter(items) + beneficiariesRecyclerView.adapter = adapter + + btnListBeneficiary.setTextColor(ContextCompat.getColorStateList(getApplicationContext(), R.color.white)) + btnAddBeneficiary.setTextColor(ContextCompat.getColorStateList(getApplicationContext(), R.color.violet)) + btnAddBeneficiary.setBackgroundTintList(ContextCompat.getColorStateList(getApplicationContext(), R.color.white)) + btnListBeneficiary.setBackgroundTintList(ContextCompat.getColorStateList(getApplicationContext(), R.color.violet)) + + btnAddBeneficiary.setOnClickListener { + mBtnAddFocused.visibility = LinearLayout.VISIBLE + mBtnListFocused.visibility = LinearLayout.INVISIBLE + btnListBeneficiary.setTextColor(ContextCompat.getColorStateList(getApplicationContext(), R.color.violet)) + btnAddBeneficiary.setTextColor(ContextCompat.getColorStateList(getApplicationContext(), R.color.white)) + btnListBeneficiary.setBackgroundTintList(ContextCompat.getColorStateList(getApplicationContext(), R.color.white)) + btnAddBeneficiary.setBackgroundTintList(ContextCompat.getColorStateList(getApplicationContext(), R.color.violet)) + } + + btnListBeneficiary.setOnClickListener { + mBtnAddFocused.visibility = LinearLayout.INVISIBLE + mBtnListFocused.visibility = LinearLayout.VISIBLE + btnAddBeneficiary.setTextColor(ContextCompat.getColorStateList(getApplicationContext(), R.color.violet)) + btnListBeneficiary.setTextColor(ContextCompat.getColorStateList(getApplicationContext(), R.color.white)) + btnListBeneficiary.setBackgroundTintList(ContextCompat.getColorStateList(getApplicationContext(), R.color.violet)) + btnAddBeneficiary.setBackgroundTintList(ContextCompat.getColorStateList(getApplicationContext(), R.color.white)) + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerAccounts/CustomerAccountFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerAccounts/CustomerAccountFragment.kt index 36598fc8..f25d8dd9 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerAccounts/CustomerAccountFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerAccounts/CustomerAccountFragment.kt @@ -2,6 +2,7 @@ package org.mifos.mobile.cn.ui.mifos.customerAccounts import android.app.SearchManager import android.content.Context +import android.content.Intent import android.os.Bundle import androidx.viewpager.widget.ViewPager import androidx.appcompat.widget.SearchView @@ -19,6 +20,7 @@ import org.mifos.mobile.cn.ui.mifos.accounts.AccountsContract import org.mifos.mobile.cn.ui.mifos.accounts.AccountsFragment import org.mifos.mobile.cn.ui.mifos.accounts.AccountsPresenter import org.mifos.mobile.cn.ui.mifos.accountsFilter.AccountsFilterBottomSheet +import org.mifos.mobile.cn.ui.mifos.loanApplication.loanActivity.LoanApplicationActivity import org.mifos.mobile.cn.ui.utils.ConstantKeys import org.mifos.mobile.cn.ui.utils.StatusUtils import javax.inject.Inject @@ -93,6 +95,13 @@ class CustomerAccountFragment : MifosBaseFragment(), AccountsContract.View { AccountType.LOAN -> viewpager.currentItem = 1 } + deposit_toggle_btn.setOnClickListener { + viewpager.currentItem = 0 + } + loan_toggle_btn.setOnClickListener { + viewpager.currentItem = 1 + } + tabs.setupWithViewPager(viewpager) viewpager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrolled(position: Int, positionOffset: Float, @@ -154,15 +163,22 @@ class CustomerAccountFragment : MifosBaseFragment(), AccountsContract.View { } - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater?.inflate(R.menu.menu_account, menu) if (viewpager.currentItem == 1) { + loan_toggle_focus_btn.visibility = View.VISIBLE + deposit_toggle_focus_btn.visibility = View.GONE + iv_apply_for_loan.visibility = View.VISIBLE + applyForLoan() menu?.findItem(R.id.menu_filter_loan)?.isVisible = true menu?.findItem(R.id.menu_filter_deposit)?.isVisible = false menu?.findItem(R.id.menu_search_loan)?.isVisible = true menu?.findItem(R.id.menu_search_deposit)?.isVisible = false initSearch(menu!!, AccountType.LOAN) } else if (viewpager.currentItem == 0) { + deposit_toggle_focus_btn.visibility = View.VISIBLE + loan_toggle_focus_btn.visibility = View.GONE + iv_apply_for_loan.visibility = View.GONE menu?.findItem(R.id.menu_filter_loan)?.isVisible = false menu?.findItem(R.id.menu_filter_deposit)?.isVisible = true menu?.findItem(R.id.menu_search_deposit)?.isVisible = true @@ -173,7 +189,15 @@ class CustomerAccountFragment : MifosBaseFragment(), AccountsContract.View { } - override fun onOptionsItemSelected(item: MenuItem?): Boolean { + private fun applyForLoan() { + iv_apply_for_loan.setOnClickListener(View.OnClickListener { + val intent = Intent(activity, LoanApplicationActivity::class.java) + intent.putExtra(ConstantKeys.CUSTOMER_IDENTIFIER, "customer_identifier") + startActivity(intent) + }) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item?.itemId) { R.id.menu_filter_loan -> showFilterDialog(AccountType.LOAN) R.id.menu_filter_deposit -> showFilterDialog(AccountType.DEPOSIT) diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerDetails/CustomerDetailsPresenter.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerDetails/CustomerDetailsPresenter.kt index 708dafda..9579692d 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerDetails/CustomerDetailsPresenter.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerDetails/CustomerDetailsPresenter.kt @@ -1,21 +1,19 @@ package org.mifos.mobile.cn.ui.mifos.customerDetails import android.content.Context -import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.observers.DisposableObserver import io.reactivex.schedulers.Schedulers import org.mifos.mobile.cn.R -import org.mifos.mobile.cn.data.models.customer.Customer import org.mifos.mobile.cn.data.datamanager.DataManagerCustomer import org.mifos.mobile.cn.data.datamanager.contracts.ManagerCustomer -import org.mifos.mobile.cn.fakesource.FakeRemoteDataSource +import org.mifos.mobile.cn.data.models.customer.Customer import org.mifos.mobile.cn.injection.ApplicationContext import org.mifos.mobile.cn.injection.ConfigPersistent import org.mifos.mobile.cn.ui.base.BasePresenter -import java.util.concurrent.Callable import javax.inject.Inject + @ConfigPersistent class CustomerDetailsPresenter @Inject constructor(@ApplicationContext context: Context, dataManagerCustomer: DataManagerCustomer): BasePresenter(context), CustomerDetailsContract.Presenter { diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerLoanDetails/CustomerLoanDetailsFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerLoanDetails/CustomerLoanDetailsFragment.kt index 3f34bc5d..fb604b5b 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerLoanDetails/CustomerLoanDetailsFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerLoanDetails/CustomerLoanDetailsFragment.kt @@ -178,7 +178,7 @@ class CustomerLoanDetailsFragment : MifosBaseFragment(), CustomerLoanDetailsCont Log.e(context.toString(), message) } - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { if (inflater != null) { inflater.inflate(R.menu.menu_loan_account_details, menu) } diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerProfile/CustomerProfileActivity.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerProfile/CustomerProfileActivity.kt index b9cf039a..0a79ab6e 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerProfile/CustomerProfileActivity.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/customerProfile/CustomerProfileActivity.kt @@ -98,6 +98,10 @@ class CustomerProfileActivity: MifosBaseActivity(),CustomerProfileContract.View resources.getString( R.string.dialog_message_write_permission_for_share_never_ask_again), ConstantKeys.PERMISSIONS_WRITE_EXTERNAL_STORAGE_STATUS) + if (CheckSelfPermissionAndRequest.checkSelfPermission(this, + android.Manifest.permission.WRITE_EXTERNAL_STORAGE)){ + shareImage() + } } override fun loadCustomerPortrait() { diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/identificationdetails/IdentificationDetailsFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/identificationdetails/IdentificationDetailsFragment.kt index b738c489..a9f39674 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/identificationdetails/IdentificationDetailsFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/identificationdetails/IdentificationDetailsFragment.kt @@ -138,7 +138,7 @@ class IdentificationDetailsFragment:MifosBaseFragment(),IdentificationDetailsCon } - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater!!.inflate(R.menu.menu_identification_card,menu) super.onCreateOptionsMenu(menu, inflater) } diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/identificationlist/IdentificationsFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/identificationlist/IdentificationsFragment.kt index a25bf0ac..8859ba04 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/identificationlist/IdentificationsFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/identificationlist/IdentificationsFragment.kt @@ -130,7 +130,7 @@ class IdentificationsFragment : MifosBaseFragment(),IdentificationsContract.View TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) inflater!!.inflate(R.menu.menu_identification_search,menu) setUpSearchInterface(menu) diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/AddDebtIncomeBottomSheet.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/AddDebtIncomeBottomSheet.kt index b84f989f..6ba7d187 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/AddDebtIncomeBottomSheet.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/AddDebtIncomeBottomSheet.kt @@ -136,7 +136,7 @@ class AddDebtIncomeBottomSheet : BottomSheetDialogFragment(), View.OnClickListen behavior?.state = BottomSheetBehavior.STATE_EXPANDED } - override fun onDismiss(dialog: DialogInterface?) { + override fun onDismiss(dialog: DialogInterface) { super.onDismiss(dialog) } } \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/LoanDebtIncome/LoanDebtIncomeFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/LoanDebtIncome/LoanDebtIncomeFragment.kt index e8c8246e..cb75444e 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/LoanDebtIncome/LoanDebtIncomeFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/LoanDebtIncome/LoanDebtIncomeFragment.kt @@ -42,7 +42,7 @@ class LoanDebtIncomeFragment : BaseFragmentDebtIncome(), Step { } - override fun onAttach(context: Context?) { + override fun onAttach(context: Context) { super.onAttach(context) if (context is OnNavigationBarListener.LoanDebtIncomeData){ onNavigationBarListner = context diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/loanDetails/LoanDetailsFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/loanDetails/LoanDetailsFragment.kt index c8f0d27d..5b01c817 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/loanDetails/LoanDetailsFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/loanDetails/LoanDetailsFragment.kt @@ -460,7 +460,7 @@ class LoanDetailsFragment : MifosBaseFragment(), Step, AdapterView.OnItemSelecte } } - override fun onAttach(context: Context?) { + override fun onAttach(context: Context) { super.onAttach(context) if(context is OnNavigationBarListener.LoanDetailsData){onNavigationBarListner = context} else throw RuntimeException("$context must implement OnNavigationBarListener.LoanDetails") diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/loancosigner/LoanCosignerFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/loancosigner/LoanCosignerFragment.kt index ef9ac399..f6cc1ce1 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/loancosigner/LoanCosignerFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/loanApplication/loancosigner/LoanCosignerFragment.kt @@ -41,7 +41,7 @@ class LoanCosignerFragment : BaseFragmentDebtIncome(), Step { } - override fun onAttach(context: Context?) { + override fun onAttach(context: Context) { super.onAttach(context) if(context is OnNavigationBarListener.LoanCoSignerData){onNavigationBarListener = context} else throw RuntimeException("$context must implement OnNavigationBarListener.LoanCoSignerData") diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginActivity.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginActivity.kt index 31a84ca1..2ca3e748 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginActivity.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginActivity.kt @@ -3,16 +3,19 @@ package org.mifos.mobile.cn.ui.mifos.login import android.content.Intent import android.os.Bundle import android.text.TextUtils +import android.util.Log import android.view.View import android.widget.Toast +import kotlinx.android.synthetic.main.activity_login.* import org.mifos.mobile.cn.R import org.mifos.mobile.cn.data.local.PreferencesHelper +import org.mifos.mobile.cn.data.models.Authentication import org.mifos.mobile.cn.ui.base.MifosBaseActivity import org.mifos.mobile.cn.ui.mifos.passcode.PasscodeActivity +import org.mifos.mobile.cn.ui.mifos.signup.SignupActivity import org.mifos.mobile.cn.ui.utils.ConstantKeys import org.mifos.mobile.cn.ui.utils.Toaster import javax.inject.Inject -import kotlinx.android.synthetic.main.activity_login.* class LoginActivity : MifosBaseActivity(), LoginContract.View, View.OnClickListener { @@ -27,51 +30,65 @@ class LoginActivity : MifosBaseActivity(), LoginContract.View, View.OnClickListe override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) - setToolbarTitle(getString(R.string.login)) + //setToolbarTitle(getString(R.string.login)) activityComponent.inject(this) loginPresenter.attachView(this) - preferencesHelper.clear() + //preferencesHelper.clear() //TODO:remove this while implementing API btnLogin.setOnClickListener(this) + create.setOnClickListener(this) } override fun onClick(view: View) { when (view.id) { R.id.btnLogin -> login() + R.id.create -> signup() } } - internal fun login() { + private fun signup() { + val intent = Intent(this, SignupActivity::class.java) + startActivity(intent) + finish() + } + + fun login() { val username = etUsername.text.toString().trim() val password = etPassword.text.toString().trim() - + preferencesHelper.putTenantIdentifier("tn01") + Log.v("Hello","Hello") if(!TextUtils.isEmpty(username)){ - preferencesHelper.putUsername("fineractCn") + // preferencesHelper.putUsername("interopUser") } else{ etUsername.error = "Username required" return } if(!TextUtils.isEmpty(password)){ - preferencesHelper.putPassword("password") + //preferencesHelper.putPassword("intop@d1") } else{ etPassword.error = "Password required" return } + loginPresenter.login(username, password) Toaster.show(findViewById(android.R.id.content), getString(R.string.logging_in), Toaster.SHORT) } //TODO:edit this fun while implementing API - override fun showUserLoginSuccessfully() { + + override fun showUserLoginSuccessfully(user: Authentication) { + preferencesHelper.putAccessToken(user.accessToken) + Log.d("Hello",user.accessToken) + preferencesHelper.putSignInUser(user) + preferencesHelper.putUsername(etUsername.text.toString().trim()) preferencesHelper.putLoginStatus(true) - preferencesHelper.putAccessToken("access_token") Toast.makeText(this, R.string.welcome, Toast.LENGTH_SHORT).show() startPassCodeActivity() } diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginContract.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginContract.kt index ff980c9c..9a7d815f 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginContract.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginContract.kt @@ -1,11 +1,12 @@ package org.mifos.mobile.cn.ui.mifos.login +import org.mifos.mobile.cn.data.models.Authentication import org.mifos.mobile.cn.ui.base.MvpView interface LoginContract { interface View : MvpView { //TODO:edit this for access tokens and other user data - fun showUserLoginSuccessfully() + fun showUserLoginSuccessfully(user: Authentication) fun showUserLoginUnSuccessfully() diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginPresenter.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginPresenter.kt index 02e7e45a..282193e2 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginPresenter.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/login/LoginPresenter.kt @@ -1,45 +1,72 @@ package org.mifos.mobile.cn.ui.mifos.login import android.content.Context +import android.widget.Toast +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.observers.DisposableObserver +import io.reactivex.schedulers.Schedulers import org.mifos.mobile.cn.R -import org.mifos.mobile.cn.data.local.PreferencesHelper +import org.mifos.mobile.cn.data.datamanager.DataManagerAuth +import org.mifos.mobile.cn.data.datamanager.contracts.ManagerCustomer +import org.mifos.mobile.cn.data.models.Authentication import org.mifos.mobile.cn.injection.ApplicationContext import org.mifos.mobile.cn.ui.base.BasePresenter import javax.inject.Inject class LoginPresenter @Inject -constructor(@ApplicationContext context: Context) : +constructor(@ApplicationContext context: Context, dataManagerAuth: DataManagerAuth) : BasePresenter(context), LoginContract.Presenter { - - @Inject + val LOG_TAG = LoginPresenter::class.java.simpleName + var compositeDisposable: CompositeDisposable = CompositeDisposable() + private var dataManagerAuth: DataManagerAuth = dataManagerAuth + override fun detachView() { + super.detachView() + compositeDisposable.clear() + } + /* @Inject internal lateinit var preferencesHelper: PreferencesHelper - +*/ //TODO: edit this while implementing API override fun login(username: String, password: String) { checkViewAttached() getMvpView.showProgress() - if (isCredentialValid(username, password)) { - getMvpView.hideProgress() - if (preferencesHelper.password.equals(password) - && preferencesHelper.username.equals(username)) { - getMvpView.showUserLoginSuccessfully() - } else { - getMvpView.hideProgress() - getMvpView.showUserLoginUnSuccessfully() - } + compositeDisposable.add(dataManagerAuth.login(username, password) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(object : DisposableObserver() { + override fun onNext(user: Authentication) { + getMvpView.hideProgress() + getMvpView.showUserLoginSuccessfully(user) + /*if (isCredentialValid(username, password)) { + getMvpView.hideProgress() + if (preferencesHelper.password.equals(password) + && preferencesHelper.getUserName().equals(username)) { + getMvpView.showUserLoginSuccessfully(user) + } else { + getMvpView.hideProgress() + getMvpView.showUserLoginSuccessfully(user) + } + + }*/ + + } + + override fun onComplete() {} + override fun onError(e: Throwable) { + getMvpView.hideProgress() + Toast.makeText(context, R.string.error_logging_in, Toast.LENGTH_SHORT).show() + } + }) + ) - } } override fun attachView(mvpView: LoginContract.View) { super.attachView(mvpView) } - override fun detachView() { - super.detachView() - } - - fun isCredentialValid(username: String, password: String): Boolean { + /*fun isCredentialValid(username: String, password: String): Boolean { val resources = context.resources val correctUsername = username.trim() @@ -70,5 +97,5 @@ constructor(@ApplicationContext context: Context) : } return true - } + }*/ } \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/passcode/PasscodeActivity.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/passcode/PasscodeActivity.kt index f04d00e1..4a5fafea 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/passcode/PasscodeActivity.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/passcode/PasscodeActivity.kt @@ -1,19 +1,46 @@ package org.mifos.mobile.cn.ui.mifos.passcode +import android.Manifest import android.content.DialogInterface import android.content.Intent +import android.os.Bundle import android.view.View import android.widget.Toast import com.mifos.mobile.passcode.MifosPassCodeActivity import com.mifos.mobile.passcode.utils.EncryptionUtil +import com.mifos.mobile.passcode.utils.PasscodePreferencesHelper import org.mifos.mobile.cn.R import org.mifos.mobile.cn.ui.mifos.DashboardActivity import org.mifos.mobile.cn.ui.mifos.login.LoginActivity +import org.mifos.mobile.cn.ui.utils.CheckSelfPermissionAndRequest.checkSelfPermission +import org.mifos.mobile.cn.ui.utils.CheckSelfPermissionAndRequest.requestPermission +import org.mifos.mobile.cn.ui.utils.ConstantKeys import org.mifos.mobile.cn.ui.utils.MaterialDialog import org.mifos.mobile.cn.ui.utils.Toaster class PasscodeActivity : MifosPassCodeActivity(){ + private var currPass = "" + private var updatePassword = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (!checkSelfPermission(this, + Manifest.permission.READ_PHONE_STATE)) { + requestPermission() + } + } + + private fun requestPermission() { + requestPermission( + this, + Manifest.permission.READ_PHONE_STATE, + ConstantKeys.PERMISSIONS_REQUEST_READ_PHONE_STATE, + resources.getString( + R.string.dialog_message_phone_state_permission_denied_prompt), + resources.getString(R.string.dialog_message_phone_state_permission_never_ask_again), + ConstantKeys.PERMISSIONS_READ_PHONE_STATE_STATUS) + } override fun getLogo(): Int { return R.drawable.mifos_logo_new @@ -49,5 +76,12 @@ class PasscodeActivity : MifosPassCodeActivity(){ override fun getEncryptionType(): Int { return EncryptionUtil.FINERACT_CN } - + override fun onBackPressed() { + super.onBackPressed() + if (updatePassword && !currPass.isEmpty()) { + val helper = PasscodePreferencesHelper(this) + helper.savePassCode(currPass) + } + finish() + } } \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/recentTransactions/RecentTransactionsFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/recentTransactions/RecentTransactionsFragment.kt index 743a3db2..c0ae1fc3 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/recentTransactions/RecentTransactionsFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/recentTransactions/RecentTransactionsFragment.kt @@ -37,7 +37,6 @@ SwipeRefreshLayout.OnRefreshListener{ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setHasOptionsMenu(true) recentTransactionList = ArrayList() } @@ -62,7 +61,6 @@ SwipeRefreshLayout.OnRefreshListener{ } override fun showUserInterface() { - setToolbarTitle("Recent Transactions") val layoutManager = LinearLayoutManager(activity) layoutManager.orientation = RecyclerView.VERTICAL rvRecentTransactions.layoutManager = layoutManager @@ -86,7 +84,7 @@ SwipeRefreshLayout.OnRefreshListener{ showRecyclerView(false) } - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) inflater?.inflate(R.menu.menu_transactions_search,menu) setUpSearchInterface(menu) diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/settings/SettingsFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/settings/SettingsFragment.kt index 21f01cec..7e6913b1 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/settings/SettingsFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/settings/SettingsFragment.kt @@ -1,13 +1,16 @@ package org.mifos.mobile.cn.ui.mifos.settings -import android.content.Context -import android.net.Uri +import android.content.Intent import android.os.Bundle -import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.mifos.mobile.passcode.utils.PasscodePreferencesHelper import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.ui.mifos.passcode.PasscodeActivity +import org.mifos.mobile.cn.ui.utils.ConstantKeys + // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER @@ -27,6 +30,7 @@ class SettingsFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_settings, container, false) } diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/signup/SignupActivity.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/signup/SignupActivity.kt new file mode 100644 index 00000000..1ff853f8 --- /dev/null +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/mifos/signup/SignupActivity.kt @@ -0,0 +1,15 @@ +package org.mifos.mobile.cn.ui.mifos.signup + +import android.os.Bundle +import android.view.View +import kotlinx.android.synthetic.main.activity_login.* +import org.mifos.mobile.cn.R +import org.mifos.mobile.cn.ui.base.MifosBaseActivity +import org.mifos.mobile.cn.ui.mifos.login.LoginContract + +class SignupActivity: MifosBaseActivity(){ + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_signup) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/review/AddLoanReviewFragment.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/review/AddLoanReviewFragment.kt index a83975dd..89229f7a 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/review/AddLoanReviewFragment.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/review/AddLoanReviewFragment.kt @@ -46,7 +46,7 @@ class AddLoanReviewFragment : MifosBaseFragment(),Step { @Inject lateinit var debtCoSignerAdapter: LoanDebtIncomeAdapter - override fun onAttach(context: Context?) { + override fun onAttach(context: Context) { super.onAttach(context) if (context is OnNavigationBarListener.ReviewLoan){ onNavigationBarListener = context diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/ConstantKeys.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/ConstantKeys.kt index 64fabae7..c77dc580 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/ConstantKeys.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/ConstantKeys.kt @@ -10,7 +10,13 @@ object ConstantKeys { const val REQUEST_PERMISSION_SETTING = 254 const val PERMISSION_REQUEST_ALL = 4 const val PERMISSION_REQUEST_CAMERA = 5 - + const val PASSCODE = "Passcode" + const val CURR_PASSWORD = "currentPassword" + const val ERROR_OCCURRED = "Error occurred" + const val FAILED_TO_WRITE_DATA_TO_QR = "Failed to write data to qr" + const val PERMISSIONS_READ_PHONE_STATE_STATUS = "read_phone_status" + const val PERMISSIONS_REQUEST_READ_PHONE_STATE = 2 + const val UPDATE_PASSWORD_KEY = "updatePassword" const val PERMISSIONS_WRITE_EXTERNAL_STORAGE_STATUS = "write_status" const val PERMISSION_READ_EXTERNAL_STORAGE_STATUS = "read_status" const val PERMISSIONS_CAMERA_STATUS = "camera_status" diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/ImageLoaderUtils.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/ImageLoaderUtils.kt index f62490e8..ed46a182 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/ImageLoaderUtils.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/ImageLoaderUtils.kt @@ -31,7 +31,7 @@ class ImageLoaderUtils constructor(var context: Context) { private fun buildGlideUrl(imageUrl : String): GlideUrl{ return GlideUrl(imageUrl,LazyHeaders.Builder() - .addHeader(MifosInterceptor.HEADER_ACCESS_TOKEN,preferencesHelper.accessToken) + .addHeader(MifosInterceptor.HEADER_ACCESS_TOKEN,preferencesHelper.getAccessToken()) .build()) } diff --git a/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/Utils.kt b/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/Utils.kt index 8802c272..5e4fa9a0 100644 --- a/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/Utils.kt +++ b/app/src/main/kotlin/org/mifos/mobile/cn/ui/utils/Utils.kt @@ -1,6 +1,7 @@ package org.mifos.mobile.cn.ui.utils import android.content.Context +import android.content.res.Resources import android.graphics.PorterDuff import android.view.Menu import androidx.core.content.ContextCompat @@ -15,6 +16,13 @@ import java.util.* class Utils { companion object { + fun dpToPx(dp: Int): Int { + return ((dp * Resources.getSystem().displayMetrics.density).toInt()); + } + + fun pxToDp(px: Int, context: Context): Int { + return ((px / Resources.getSystem().displayMetrics.density).toInt()); + } fun getPrecision(aDouble: Double?): String { return String.format(Locale.ENGLISH, "%.2f", aDouble) } diff --git a/app/src/main/res/drawable-v24/arrow.png b/app/src/main/res/drawable-v24/arrow.png new file mode 100644 index 00000000..015dbf8c Binary files /dev/null and b/app/src/main/res/drawable-v24/arrow.png differ diff --git a/app/src/main/res/drawable-v24/circle_arrow.png b/app/src/main/res/drawable-v24/circle_arrow.png new file mode 100644 index 00000000..a04090a9 Binary files /dev/null and b/app/src/main/res/drawable-v24/circle_arrow.png differ diff --git a/app/src/main/res/drawable-v24/drawable_editable_image_hint.xml b/app/src/main/res/drawable-v24/drawable_editable_image_hint.xml new file mode 100644 index 00000000..9790605f --- /dev/null +++ b/app/src/main/res/drawable-v24/drawable_editable_image_hint.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_cam.png b/app/src/main/res/drawable-v24/ic_cam.png new file mode 100644 index 00000000..22a721d6 Binary files /dev/null and b/app/src/main/res/drawable-v24/ic_cam.png differ diff --git a/app/src/main/res/drawable-v24/ic_camera.xml b/app/src/main/res/drawable-v24/ic_camera.xml new file mode 100644 index 00000000..7b9b5cd4 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_camera.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable-v24/ic_error_state.xml b/app/src/main/res/drawable-v24/ic_error_state.xml new file mode 100644 index 00000000..c01af649 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_error_state.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable-v24/ic_transaction.xml b/app/src/main/res/drawable-v24/ic_transaction.xml new file mode 100644 index 00000000..fad1fe3e --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_transaction.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable-v24/nav_drawer.png b/app/src/main/res/drawable-v24/nav_drawer.png new file mode 100644 index 00000000..fe9a429c Binary files /dev/null and b/app/src/main/res/drawable-v24/nav_drawer.png differ diff --git a/app/src/main/res/drawable-v24/outline_button.png b/app/src/main/res/drawable-v24/outline_button.png new file mode 100644 index 00000000..958105dc Binary files /dev/null and b/app/src/main/res/drawable-v24/outline_button.png differ diff --git a/app/src/main/res/drawable-v24/profile.png b/app/src/main/res/drawable-v24/profile.png new file mode 100644 index 00000000..0dcfeb06 Binary files /dev/null and b/app/src/main/res/drawable-v24/profile.png differ diff --git a/app/src/main/res/drawable-v24/shape_bottom_sheet_dialog_grip.xml b/app/src/main/res/drawable-v24/shape_bottom_sheet_dialog_grip.xml new file mode 100644 index 00000000..792c8361 --- /dev/null +++ b/app/src/main/res/drawable-v24/shape_bottom_sheet_dialog_grip.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/bottomview_selector.xml b/app/src/main/res/drawable/bottomview_selector.xml new file mode 100644 index 00000000..b18401d2 --- /dev/null +++ b/app/src/main/res/drawable/bottomview_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/chip_outline.xml b/app/src/main/res/drawable/chip_outline.xml new file mode 100644 index 00000000..4d772740 --- /dev/null +++ b/app/src/main/res/drawable/chip_outline.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/chip_outline_selected.xml b/app/src/main/res/drawable/chip_outline_selected.xml new file mode 100644 index 00000000..0dae89da --- /dev/null +++ b/app/src/main/res/drawable/chip_outline_selected.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gray_box.xml b/app/src/main/res/drawable/gray_box.xml new file mode 100644 index 00000000..a23f364f --- /dev/null +++ b/app/src/main/res/drawable/gray_box.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/greyborder.xml b/app/src/main/res/drawable/greyborder.xml new file mode 100644 index 00000000..4a9acdf3 --- /dev/null +++ b/app/src/main/res/drawable/greyborder.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_account.xml b/app/src/main/res/drawable/ic_account.xml new file mode 100644 index 00000000..b9d5db60 --- /dev/null +++ b/app/src/main/res/drawable/ic_account.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_circle_black_24dp.xml b/app/src/main/res/drawable/ic_add_circle_black_24dp.xml new file mode 100644 index 00000000..be629131 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_circle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flash_off.xml b/app/src/main/res/drawable/ic_flash_off.xml new file mode 100644 index 00000000..51b17693 --- /dev/null +++ b/app/src/main/res/drawable/ic_flash_off.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flash_on.xml b/app/src/main/res/drawable/ic_flash_on.xml new file mode 100644 index 00000000..a3c81cc3 --- /dev/null +++ b/app/src/main/res/drawable/ic_flash_on.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_home.xml b/app/src/main/res/drawable/ic_home.xml new file mode 100644 index 00000000..70fb2910 --- /dev/null +++ b/app/src/main/res/drawable/ic_home.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_profile.xml b/app/src/main/res/drawable/ic_profile.xml new file mode 100644 index 00000000..76785806 --- /dev/null +++ b/app/src/main/res/drawable/ic_profile.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_swap_horiz.xml b/app/src/main/res/drawable/ic_swap_horiz.xml new file mode 100644 index 00000000..f9df11df --- /dev/null +++ b/app/src/main/res/drawable/ic_swap_horiz.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/launcher_background.xml b/app/src/main/res/drawable/launcher_background.xml index 03dd5b62..5aca7c3d 100644 --- a/app/src/main/res/drawable/launcher_background.xml +++ b/app/src/main/res/drawable/launcher_background.xml @@ -4,8 +4,7 @@ - diff --git a/app/src/main/res/drawable/login_bg.png b/app/src/main/res/drawable/login_bg.png new file mode 100644 index 00000000..3fbe488e Binary files /dev/null and b/app/src/main/res/drawable/login_bg.png differ diff --git a/app/src/main/res/drawable/mifos_splash_screen_logo.png b/app/src/main/res/drawable/mifos_splash_screen_logo.png new file mode 100644 index 00000000..c1819abf Binary files /dev/null and b/app/src/main/res/drawable/mifos_splash_screen_logo.png differ diff --git a/app/src/main/res/drawable/more_icon.png b/app/src/main/res/drawable/more_icon.png new file mode 100644 index 00000000..82f45f34 Binary files /dev/null and b/app/src/main/res/drawable/more_icon.png differ diff --git a/app/src/main/res/drawable/notification.xml b/app/src/main/res/drawable/notification.xml new file mode 100644 index 00000000..3ebf17e7 --- /dev/null +++ b/app/src/main/res/drawable/notification.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/notification_circle.xml b/app/src/main/res/drawable/notification_circle.xml index f112527e..721e9c80 100644 --- a/app/src/main/res/drawable/notification_circle.xml +++ b/app/src/main/res/drawable/notification_circle.xml @@ -2,7 +2,7 @@ + android:width="35dp" + android:height="35dp" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/pick_contact.png b/app/src/main/res/drawable/pick_contact.png new file mode 100644 index 00000000..0a33393a Binary files /dev/null and b/app/src/main/res/drawable/pick_contact.png differ diff --git a/app/src/main/res/drawable/qrcode.png b/app/src/main/res/drawable/qrcode.png new file mode 100644 index 00000000..c9fef9c3 Binary files /dev/null and b/app/src/main/res/drawable/qrcode.png differ diff --git a/app/src/main/res/drawable/round_gray.xml b/app/src/main/res/drawable/round_gray.xml new file mode 100644 index 00000000..81cf96d7 --- /dev/null +++ b/app/src/main/res/drawable/round_gray.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_shape.xml b/app/src/main/res/drawable/rounded_shape.xml new file mode 100644 index 00000000..1f0b683a --- /dev/null +++ b/app/src/main/res/drawable/rounded_shape.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_tab.xml b/app/src/main/res/drawable/selector_tab.xml new file mode 100644 index 00000000..6cc08e7d --- /dev/null +++ b/app/src/main/res/drawable/selector_tab.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/violet_concave.xml b/app/src/main/res/drawable/violet_concave.xml new file mode 100644 index 00000000..518afafc --- /dev/null +++ b/app/src/main/res/drawable/violet_concave.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/violet_round.xml b/app/src/main/res/drawable/violet_round.xml new file mode 100644 index 00000000..30cca1a2 --- /dev/null +++ b/app/src/main/res/drawable/violet_round.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/white_card.xml b/app/src/main/res/drawable/white_card.xml new file mode 100644 index 00000000..57a1b6f1 --- /dev/null +++ b/app/src/main/res/drawable/white_card.xml @@ -0,0 +1,15 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/font/airbnb_cereal_black.ttf b/app/src/main/res/font/airbnb_cereal_black.ttf new file mode 100644 index 00000000..238b1c34 Binary files /dev/null and b/app/src/main/res/font/airbnb_cereal_black.ttf differ diff --git a/app/src/main/res/font/airbnb_cereal_book.ttf b/app/src/main/res/font/airbnb_cereal_book.ttf new file mode 100644 index 00000000..528274dc Binary files /dev/null and b/app/src/main/res/font/airbnb_cereal_book.ttf differ diff --git a/app/src/main/res/font/airbnb_cereal_extra_bold.ttf b/app/src/main/res/font/airbnb_cereal_extra_bold.ttf new file mode 100644 index 00000000..3168f843 Binary files /dev/null and b/app/src/main/res/font/airbnb_cereal_extra_bold.ttf differ diff --git a/app/src/main/res/font/airbnb_cereal_light.ttf b/app/src/main/res/font/airbnb_cereal_light.ttf new file mode 100644 index 00000000..558fb679 Binary files /dev/null and b/app/src/main/res/font/airbnb_cereal_light.ttf differ diff --git a/app/src/main/res/font/productsans.ttf b/app/src/main/res/font/productsans.ttf new file mode 100644 index 00000000..c0442ee2 Binary files /dev/null and b/app/src/main/res/font/productsans.ttf differ diff --git a/app/src/main/res/font/productsans_bold.ttf b/app/src/main/res/font/productsans_bold.ttf new file mode 100644 index 00000000..d847195c Binary files /dev/null and b/app/src/main/res/font/productsans_bold.ttf differ diff --git a/app/src/main/res/layout/activity_amount.xml b/app/src/main/res/layout/activity_amount.xml new file mode 100644 index 00000000..df43bae2 --- /dev/null +++ b/app/src/main/res/layout/activity_amount.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_beneficiaries.xml b/app/src/main/res/layout/activity_beneficiaries.xml new file mode 100644 index 00000000..2be7d0c8 --- /dev/null +++ b/app/src/main/res/layout/activity_beneficiaries.xml @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml new file mode 100644 index 00000000..1377e128 --- /dev/null +++ b/app/src/main/res/layout/activity_home.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_loan_application.xml b/app/src/main/res/layout/activity_loan_application.xml index 20819ace..a59bb838 100644 --- a/app/src/main/res/layout/activity_loan_application.xml +++ b/app/src/main/res/layout/activity_loan_application.xml @@ -1,24 +1,48 @@ + android:layout_width="match_parent" + android:background="@color/violet"> + + - - - + + + + - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 5f9704e1..598de8a6 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -1,98 +1,105 @@ - - + - - - - - - - + android:layout_height="wrap_content" + android:fontFamily="@font/productsans" + android:text="@string/mifos_mobile_cn" + android:textAlignment="center" + android:textColor="@color/white" + android:textSize="@dimen/text_size_35sp" /> + android:layout_marginBottom="@dimen/layout_padding_20dp" + android:backgroundTint="@color/white" + android:textColorHint="@color/white"> - + android:fontFamily="@font/productsans" + android:hint="@string/username" + android:inputType="text" + android:textColor="@color/white" /> + android:layout_height="wrap_content" + android:backgroundTint="@color/white" + android:textColorHint="@color/white" + app:passwordToggleEnabled="true" + app:passwordToggleTint="@color/white"> - + android:fontFamily="@font/productsans" + android:hint="@string/password" + android:inputType="textPassword" + android:textColor="@color/white" + android:textColorHighlight="@color/white" /> -