mirror of
https://github.com/openMF/mifos-mobile.git
synced 2026-02-06 11:26:51 +00:00
Refactor- Final Cleanup (#2694)
Jira Tasks - [MM-82](https://mifosforge.jira.com/browse/MM-82)
This commit is contained in:
parent
25389dd8a9
commit
9c0a9b684e
188
.github/workflows/feature_branch_ci.yml
vendored
188
.github/workflows/feature_branch_ci.yml
vendored
@ -7,28 +7,180 @@ on:
|
||||
- '!development'
|
||||
- '!master'
|
||||
|
||||
concurrency:
|
||||
group: build-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build APK
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checking out repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Set up JDK
|
||||
- name: Set Up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
- uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
# Install NDK
|
||||
- name: Install NDK
|
||||
run: echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;20.0.5594570" --sdk_root=${ANDROID_SDK_ROOT}
|
||||
- name: Cache Gradle and build outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
build
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: ${{ runner.os }}-gradle-
|
||||
|
||||
# Update Gradle Permission
|
||||
- name: Change gradlew Permission
|
||||
run: chmod +x gradlew
|
||||
checks:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
check: [ build_logic, spotless, detekt ]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
- name: Run ${{ matrix.check }}
|
||||
id: run_check
|
||||
run: |
|
||||
if [ "${{ matrix.check }}" = "build_logic" ]; then
|
||||
./gradlew check -p build-logic
|
||||
elif [ "${{ matrix.check }}" = "spotless" ]; then
|
||||
./gradlew spotlessCheck --no-configuration-cache --no-daemon
|
||||
elif [ "${{ matrix.check }}" = "detekt" ]; then
|
||||
./gradlew detekt
|
||||
fi
|
||||
|
||||
# Build App
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew assemble
|
||||
- name: Upload Detekt Reports
|
||||
if: ${{ matrix.check == 'detekt' && steps.run_check.outcome == 'success' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: detekt-reports
|
||||
path: |
|
||||
**/build/reports/detekt/detekt.md
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
dependency_guard:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
|
||||
- name: Check Dependency Guard
|
||||
id: dependencyguard_verify
|
||||
continue-on-error: true
|
||||
run: ./gradlew dependencyGuard
|
||||
|
||||
- name: Prevent updating Dependency Guard baselines if this is a fork
|
||||
id: checkfork_dependencyguard
|
||||
if: steps.dependencyguard_verify.outcome == 'failure' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
run: |
|
||||
echo "::error::Dependency Guard failed, please update baselines with: ./gradlew dependencyGuardBaseline" && exit 1
|
||||
|
||||
# Runs if previous job failed
|
||||
- name: Generate new Dependency Guard baselines if verification failed and it's a PR
|
||||
id: dependencyguard_baseline
|
||||
if: steps.dependencyguard_verify.outcome == 'failure' && github.event_name == 'pull_request'
|
||||
run: |
|
||||
./gradlew dependencyGuardBaseline
|
||||
|
||||
- name: Push new Dependency Guard baselines if available
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
if: steps.dependencyguard_baseline.outcome == 'success'
|
||||
with:
|
||||
file_pattern: '**/dependencies/*.txt'
|
||||
disable_globbing: true
|
||||
commit_message: "🤖 Updates baselines for Dependency Guard"
|
||||
|
||||
tests_and_lint:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
./gradlew testDebug :lint:test :androidApp:lintRelease :lint:lint
|
||||
|
||||
- name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-and-lint-reports
|
||||
path: |
|
||||
**/build/reports/lint-results-*.html
|
||||
**/build/test-results/test*UnitTest/**.xml
|
||||
|
||||
|
||||
# Add `createProdDebugUnitTestCoverageReport` if we ever add JVM tests for prod
|
||||
- name: Generate coverage reports for Debug variants (only API 30)
|
||||
run: ./gradlew createDebugCombinedCoverageReport
|
||||
|
||||
- name: Upload test reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-${{ matrix.api-level }}
|
||||
path: '**/build/reports/androidTests'
|
||||
|
||||
- name: Display local test coverage (only API 30)
|
||||
id: jacoco
|
||||
uses: madrapps/jacoco-report@v1.6.1
|
||||
with:
|
||||
title: Combined test coverage report
|
||||
min-coverage-overall: 40
|
||||
min-coverage-changed-files: 60
|
||||
paths: |
|
||||
${{ github.workspace }}/**/build/reports/jacoco/**/*Report.xml
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload local coverage reports (XML + HTML) (only API 30)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-reports
|
||||
if-no-files-found: error
|
||||
compression-level: 1
|
||||
overwrite: false
|
||||
path: '**/build/reports/jacoco/'
|
||||
|
||||
build:
|
||||
needs: [ checks, dependency_guard, tests_and_lint ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
|
||||
- name: Build APKs
|
||||
run: ./gradlew :androidApp:assembleDebug
|
||||
|
||||
- name: Check badging
|
||||
run: ./gradlew :androidApp:checkReleaseBadging
|
||||
|
||||
- name: Upload APKs
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: APKs
|
||||
path: '**/build/outputs/apk/**/*.apk'
|
||||
170
.github/workflows/master_dev_ci.yml
vendored
170
.github/workflows/master_dev_ci.yml
vendored
@ -7,22 +7,24 @@ on:
|
||||
- 'development'
|
||||
- 'master'
|
||||
|
||||
concurrency:
|
||||
group: build-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build APK
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
- uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Cache Gradle and build outputs
|
||||
uses: actions/cache@v4
|
||||
@ -34,7 +36,151 @@ jobs:
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: ${{ runner.os }}-gradle-
|
||||
|
||||
- name: Build With Gradle
|
||||
run: ./gradlew assembleDebug
|
||||
checks:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
check: [ build_logic, spotless, detekt ]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
- name: Run ${{ matrix.check }}
|
||||
id: run_check
|
||||
run: |
|
||||
if [ "${{ matrix.check }}" = "build_logic" ]; then
|
||||
./gradlew check -p build-logic
|
||||
elif [ "${{ matrix.check }}" = "spotless" ]; then
|
||||
./gradlew spotlessCheck --no-configuration-cache --no-daemon
|
||||
elif [ "${{ matrix.check }}" = "detekt" ]; then
|
||||
./gradlew detekt
|
||||
fi
|
||||
|
||||
- name: Upload Detekt Reports
|
||||
if: ${{ matrix.check == 'detekt' && steps.run_check.outcome == 'success' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: detekt-reports
|
||||
path: |
|
||||
**/build/reports/detekt/detekt.md
|
||||
|
||||
|
||||
|
||||
|
||||
dependency_guard:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
|
||||
- name: Check Dependency Guard
|
||||
id: dependencyguard_verify
|
||||
continue-on-error: true
|
||||
run: ./gradlew dependencyGuard
|
||||
|
||||
- name: Prevent updating Dependency Guard baselines if this is a fork
|
||||
id: checkfork_dependencyguard
|
||||
if: steps.dependencyguard_verify.outcome == 'failure' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
run: |
|
||||
echo "::error::Dependency Guard failed, please update baselines with: ./gradlew dependencyGuardBaseline" && exit 1
|
||||
|
||||
# Runs if previous job failed
|
||||
- name: Generate new Dependency Guard baselines if verification failed and it's a PR
|
||||
id: dependencyguard_baseline
|
||||
if: steps.dependencyguard_verify.outcome == 'failure' && github.event_name == 'pull_request'
|
||||
run: |
|
||||
./gradlew dependencyGuardBaseline
|
||||
|
||||
- name: Push new Dependency Guard baselines if available
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
if: steps.dependencyguard_baseline.outcome == 'success'
|
||||
with:
|
||||
file_pattern: '**/dependencies/*.txt'
|
||||
disable_globbing: true
|
||||
commit_message: "🤖 Updates baselines for Dependency Guard"
|
||||
|
||||
tests_and_lint:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
./gradlew testDebug :lint:test :androidApp:lintRelease :lint:lint
|
||||
|
||||
- name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-and-lint-reports
|
||||
path: |
|
||||
**/build/reports/lint-results-*.html
|
||||
**/build/test-results/test*UnitTest/**.xml
|
||||
|
||||
|
||||
# Add `createDebugUnitTestCoverageReport` if we ever add JVM tests for prod
|
||||
- name: Generate coverage reports for Debug variants (only API 30)
|
||||
run: ./gradlew createDebugCombinedCoverageReport
|
||||
|
||||
- name: Upload test reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-${{ matrix.api-level }}
|
||||
path: '**/build/reports/androidTests'
|
||||
|
||||
- name: Display local test coverage (only API 30)
|
||||
id: jacoco
|
||||
uses: madrapps/jacoco-report@v1.6.1
|
||||
with:
|
||||
title: Combined test coverage report
|
||||
min-coverage-overall: 40
|
||||
min-coverage-changed-files: 60
|
||||
paths: |
|
||||
${{ github.workspace }}/**/build/reports/jacoco/**/*Report.xml
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload local coverage reports (XML + HTML) (only API 30)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-reports
|
||||
if-no-files-found: error
|
||||
compression-level: 1
|
||||
overwrite: false
|
||||
path: '**/build/reports/jacoco/'
|
||||
|
||||
build:
|
||||
needs: [ checks, dependency_guard, tests_and_lint ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
|
||||
- name: Build APKs
|
||||
run: ./gradlew :androidApp:assembleDebug
|
||||
|
||||
- name: Check badging
|
||||
run: ./gradlew :androidApp:checkReleaseBadging
|
||||
|
||||
- name: Upload APKs
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: APKs
|
||||
path: '**/build/outputs/apk/**/*.apk'
|
||||
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -26,12 +26,8 @@ build/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
# Windows thumbnail db
|
||||
.DS_Store
|
||||
|
||||
# IDEA/Android Studio project files, because
|
||||
# the project can be imported from settings.gradle.kts
|
||||
*.iml
|
||||
.idea/*
|
||||
!.idea/copyright
|
||||
# Keep the code styles.
|
||||
@ -40,8 +36,6 @@ build/
|
||||
!/.idea/codeStyles/Project.xml
|
||||
!/.idea/codeStyles/codeStyleConfig.xml
|
||||
|
||||
# Gradle cache
|
||||
.gradle
|
||||
|
||||
# Kotlin
|
||||
.kotlin
|
||||
|
||||
@ -1,27 +1,34 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
plugins {
|
||||
alias(libs.plugins.mifos.android.application)
|
||||
alias(libs.plugins.mifos.android.application.compose)
|
||||
alias(libs.plugins.mifos.android.hilt)
|
||||
alias(libs.plugins.mifos.android.application.firebase)
|
||||
id("com.google.android.gms.oss-licenses-plugin")
|
||||
id("kotlin-parcelize")
|
||||
alias(libs.plugins.roborazzi)
|
||||
}
|
||||
|
||||
apply(from = "../config/quality/quality.gradle")
|
||||
|
||||
android {
|
||||
namespace = "org.mifos.mobile"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "org.mifos.mobile"
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
applicationId = "org.mifos.mobile"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled = true
|
||||
ndk {
|
||||
abiFilters.addAll(arrayOf("armeabi-v7a", "x86", "x86_64", "arm64-v8a"))
|
||||
}
|
||||
multiDexEnabled = true
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
@ -42,40 +49,19 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
val commonTestDir = "src/commonTest/java"
|
||||
getByName("main"){
|
||||
java.srcDir(commonTestDir)
|
||||
}
|
||||
getByName("androidTest"){
|
||||
java.srcDir(commonTestDir)
|
||||
}
|
||||
getByName("test"){
|
||||
java.srcDir(commonTestDir)
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
dataBinding = true
|
||||
viewBinding = true
|
||||
compose = true
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
lint {
|
||||
abortOnError = false
|
||||
disable.add("InvalidPackage")
|
||||
}
|
||||
}
|
||||
|
||||
dependencyGuard {
|
||||
configuration("debugCompileClasspath")
|
||||
configuration("debugRuntimeClasspath")
|
||||
configuration("releaseCompileClasspath")
|
||||
configuration("releaseRuntimeClasspath")
|
||||
configuration("releaseRuntimeClasspath"){
|
||||
modules = true
|
||||
tree = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation (projects.shared)
|
||||
@ -108,120 +94,40 @@ dependencies {
|
||||
implementation(projects.feature.auth)
|
||||
implementation(projects.feature.userProfile)
|
||||
|
||||
implementation(libs.androidx.legacy.support.v4)
|
||||
implementation(libs.androidx.lifecycle.ktx)
|
||||
implementation(libs.androidx.lifecycle.extensions)
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.material)
|
||||
implementation(libs.androidx.preference)
|
||||
|
||||
|
||||
// DBFlow
|
||||
implementation(libs.dbflow)
|
||||
kapt(libs.dbflow.processor)
|
||||
implementation(libs.dbflow.core)
|
||||
|
||||
implementation(libs.androidx.recyclerview)
|
||||
implementation(libs.androidx.vectordrawable)
|
||||
implementation(libs.google.oss.licenses)
|
||||
|
||||
// implementation(libs.simplecropview)
|
||||
|
||||
implementation(libs.androidx.activity.ktx)
|
||||
implementation(libs.androidx.fragment.ktx)
|
||||
|
||||
//Country Code picker
|
||||
// implementation(libs.ccp)
|
||||
// implementation(libs.countrycodechooser)
|
||||
|
||||
//Square dependencies
|
||||
implementation(libs.squareup.retrofit2) {
|
||||
// exclude Retrofit’s OkHttp peer-dependency module and define your own module import
|
||||
exclude(module = "okhttp")
|
||||
}
|
||||
implementation(libs.squareup.retrofit.adapter.rxjava)
|
||||
implementation(libs.squareup.retrofit.converter.gson)
|
||||
implementation(libs.squareup.okhttp)
|
||||
implementation(libs.squareup.logging.interceptor)
|
||||
|
||||
//rxjava Dependencies
|
||||
implementation(libs.reactivex.rxjava2.android)
|
||||
implementation(libs.reactivex.rxjava2)
|
||||
|
||||
//Butter Knife
|
||||
implementation(libs.jakewharton.butterknife)
|
||||
implementation(libs.jakewharton.compiler)
|
||||
|
||||
//Annotation library
|
||||
implementation(libs.androidx.annotation)
|
||||
|
||||
//qr code
|
||||
// implementation(libs.zxing.core)
|
||||
// implementation(libs.zxing)
|
||||
|
||||
//sweet error dependency
|
||||
implementation(libs.sweet.error)
|
||||
|
||||
//mifos passcode
|
||||
implementation(libs.mifos.passcode)
|
||||
|
||||
//multidex
|
||||
implementation(libs.androidx.multidex)
|
||||
|
||||
//TableView
|
||||
// implementation(libs.tableview)
|
||||
|
||||
//Biometric Authentication
|
||||
implementation(libs.androidx.biometric)
|
||||
|
||||
// Coroutines
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
testImplementation(libs.kotlinx.coroutines.test)
|
||||
|
||||
// Unit tests dependencies
|
||||
testImplementation(libs.junit)
|
||||
testImplementation(libs.mockito.core)
|
||||
implementation(libs.mockito.core)
|
||||
//turbine
|
||||
testImplementation(libs.turbine)
|
||||
implementation(libs.mockito.android)
|
||||
androidTestImplementation((libs.junit))
|
||||
androidTestImplementation(libs.mockito.core)
|
||||
androidTestImplementation(libs.mockito.android)
|
||||
androidTestImplementation(libs.androidx.annotation)
|
||||
implementation(libs.androidx.core.testing)
|
||||
androidTestImplementation(libs.androidx.espresso.contrib)
|
||||
androidTestImplementation(libs.espresso.core)
|
||||
androidTestImplementation(libs.androidx.runner)
|
||||
androidTestImplementation(libs.androidx.rules)
|
||||
|
||||
implementation(libs.uihouse)
|
||||
implementation(projects.libs.mifosPasscode)
|
||||
|
||||
// Jetpack Compose
|
||||
api(libs.androidx.activity.compose)
|
||||
api(platform(libs.androidx.compose.bom))
|
||||
api(libs.androidx.compose.material3)
|
||||
api(libs.androidx.compose.material)
|
||||
api(libs.androidx.compose.foundation)
|
||||
api(libs.androidx.compose.foundation.layout)
|
||||
api(libs.androidx.compose.material.iconsExtended)
|
||||
api(libs.androidx.compose.runtime)
|
||||
api(libs.androidx.compose.ui.tooling.preview)
|
||||
api(libs.androidx.compose.ui.util)
|
||||
api(libs.androidx.lifecycle.runtimeCompose)
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.androidx.activity.ktx)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(platform(libs.androidx.compose.bom))
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.material)
|
||||
implementation(libs.androidx.compose.foundation)
|
||||
implementation(libs.androidx.compose.foundation.layout)
|
||||
implementation(libs.androidx.compose.material.iconsExtended)
|
||||
implementation(libs.androidx.compose.runtime)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.androidx.compose.ui.util)
|
||||
implementation(libs.androidx.lifecycle.runtimeCompose)
|
||||
implementation(libs.androidx.hilt.navigation.compose)
|
||||
|
||||
implementation(libs.androidx.core.splashscreen)
|
||||
|
||||
implementation(libs.androidx.tracing.ktx)
|
||||
implementation(libs.androidx.profileinstaller)
|
||||
implementation(libs.google.oss.licenses)
|
||||
implementation(libs.androidx.multidex)
|
||||
|
||||
testImplementation(projects.core.testing)
|
||||
testImplementation(libs.hilt.android.testing)
|
||||
testImplementation(libs.work.testing)
|
||||
|
||||
androidTestImplementation(kotlin("test"))
|
||||
androidTestImplementation(projects.core.testing)
|
||||
androidTestImplementation(libs.androidx.test.espresso.core)
|
||||
androidTestImplementation(libs.androidx.navigation.testing)
|
||||
androidTestImplementation(libs.hilt.android.testing)
|
||||
|
||||
debugApi(libs.androidx.compose.ui.tooling)
|
||||
api(libs.androidx.hilt.navigation.compose)
|
||||
|
||||
|
||||
//image cropper
|
||||
implementation(libs.android.image.cropper)
|
||||
|
||||
// Google Bar code scanner
|
||||
implementation(libs.google.app.code.scanner)
|
||||
|
||||
//cameraX
|
||||
implementation(libs.androidx.camera.camera2)
|
||||
implementation(libs.androidx.camera.lifecycle)
|
||||
implementation(libs.androidx.camera.view)
|
||||
implementation(libs.androidx.camera.core)
|
||||
}
|
||||
1630
androidApp/dependencies/releaseRuntimeClasspath.tree.txt
Normal file
1630
androidApp/dependencies/releaseRuntimeClasspath.tree.txt
Normal file
File diff suppressed because it is too large
Load Diff
278
androidApp/dependencies/releaseRuntimeClasspath.txt
Normal file
278
androidApp/dependencies/releaseRuntimeClasspath.txt
Normal file
@ -0,0 +1,278 @@
|
||||
:core:common
|
||||
:core:data
|
||||
:core:datastore
|
||||
:core:designsystem
|
||||
:core:logs
|
||||
:core:model
|
||||
:core:network
|
||||
:core:qrcode
|
||||
:core:ui
|
||||
:feature:about
|
||||
:feature:account
|
||||
:feature:auth
|
||||
:feature:beneficiary
|
||||
:feature:client-charge
|
||||
:feature:guarantor
|
||||
:feature:help
|
||||
:feature:home
|
||||
:feature:loan
|
||||
:feature:location
|
||||
:feature:notification
|
||||
:feature:qr
|
||||
:feature:recent-transaction
|
||||
:feature:savings
|
||||
:feature:settings
|
||||
:feature:third-party-transfer
|
||||
:feature:transfer-process
|
||||
:feature:update-password
|
||||
:feature:user-profile
|
||||
:libs:country-code-picker
|
||||
:libs:mifos-passcode
|
||||
:libs:pullrefresh
|
||||
:shared
|
||||
androidx.activity:activity-compose:1.9.1
|
||||
androidx.activity:activity-ktx:1.9.1
|
||||
androidx.activity:activity:1.9.1
|
||||
androidx.annotation:annotation-experimental:1.4.1
|
||||
androidx.annotation:annotation-jvm:1.8.1
|
||||
androidx.annotation:annotation:1.8.1
|
||||
androidx.appcompat:appcompat-resources:1.7.0
|
||||
androidx.appcompat:appcompat:1.7.0
|
||||
androidx.arch.core:core-common:2.2.0
|
||||
androidx.arch.core:core-runtime:2.2.0
|
||||
androidx.autofill:autofill:1.0.0
|
||||
androidx.camera:camera-camera2:1.3.4
|
||||
androidx.camera:camera-core:1.3.4
|
||||
androidx.camera:camera-lifecycle:1.3.4
|
||||
androidx.camera:camera-video:1.3.4
|
||||
androidx.camera:camera-view:1.3.4
|
||||
androidx.collection:collection-jvm:1.4.2
|
||||
androidx.collection:collection-ktx:1.4.2
|
||||
androidx.collection:collection:1.4.2
|
||||
androidx.compose.animation:animation-android:1.7.0-rc01
|
||||
androidx.compose.animation:animation-core-android:1.7.0-rc01
|
||||
androidx.compose.animation:animation-core:1.7.0-rc01
|
||||
androidx.compose.animation:animation:1.7.0-rc01
|
||||
androidx.compose.foundation:foundation-android:1.7.0-rc01
|
||||
androidx.compose.foundation:foundation-layout-android:1.7.0-rc01
|
||||
androidx.compose.foundation:foundation-layout:1.7.0-rc01
|
||||
androidx.compose.foundation:foundation:1.7.0-rc01
|
||||
androidx.compose.material3:material3-android:1.2.1
|
||||
androidx.compose.material3:material3:1.2.1
|
||||
androidx.compose.material:material-android:1.6.8
|
||||
androidx.compose.material:material-icons-core-android:1.6.8
|
||||
androidx.compose.material:material-icons-core:1.6.8
|
||||
androidx.compose.material:material-icons-extended-android:1.6.8
|
||||
androidx.compose.material:material-icons-extended:1.6.8
|
||||
androidx.compose.material:material-ripple-android:1.6.8
|
||||
androidx.compose.material:material-ripple:1.6.8
|
||||
androidx.compose.material:material:1.6.8
|
||||
androidx.compose.runtime:runtime-android:1.7.0-rc01
|
||||
androidx.compose.runtime:runtime-saveable-android:1.7.0-rc01
|
||||
androidx.compose.runtime:runtime-saveable:1.7.0-rc01
|
||||
androidx.compose.runtime:runtime:1.7.0-rc01
|
||||
androidx.compose.ui:ui-android:1.7.0-rc01
|
||||
androidx.compose.ui:ui-geometry-android:1.7.0-rc01
|
||||
androidx.compose.ui:ui-geometry:1.7.0-rc01
|
||||
androidx.compose.ui:ui-graphics-android:1.7.0-rc01
|
||||
androidx.compose.ui:ui-graphics:1.7.0-rc01
|
||||
androidx.compose.ui:ui-text-android:1.7.0-rc01
|
||||
androidx.compose.ui:ui-text:1.7.0-rc01
|
||||
androidx.compose.ui:ui-tooling-preview-android:1.7.0-rc01
|
||||
androidx.compose.ui:ui-tooling-preview:1.7.0-rc01
|
||||
androidx.compose.ui:ui-unit-android:1.7.0-rc01
|
||||
androidx.compose.ui:ui-unit:1.7.0-rc01
|
||||
androidx.compose.ui:ui-util-android:1.7.0-rc01
|
||||
androidx.compose.ui:ui-util:1.7.0-rc01
|
||||
androidx.compose.ui:ui:1.7.0-rc01
|
||||
androidx.compose:compose-bom:2024.08.00
|
||||
androidx.concurrent:concurrent-futures:1.1.0
|
||||
androidx.core:core-ktx:1.13.1
|
||||
androidx.core:core-splashscreen:1.0.1
|
||||
androidx.core:core:1.13.1
|
||||
androidx.cursoradapter:cursoradapter:1.0.0
|
||||
androidx.customview:customview-poolingcontainer:1.0.0
|
||||
androidx.customview:customview:1.0.0
|
||||
androidx.databinding:viewbinding:7.4.2
|
||||
androidx.datastore:datastore-core:1.0.0
|
||||
androidx.datastore:datastore-preferences-core:1.0.0
|
||||
androidx.datastore:datastore-preferences:1.0.0
|
||||
androidx.datastore:datastore:1.0.0
|
||||
androidx.documentfile:documentfile:1.0.0
|
||||
androidx.drawerlayout:drawerlayout:1.0.0
|
||||
androidx.emoji2:emoji2-views-helper:1.3.0
|
||||
androidx.emoji2:emoji2:1.3.0
|
||||
androidx.exifinterface:exifinterface:1.3.2
|
||||
androidx.fragment:fragment-ktx:1.7.1
|
||||
androidx.fragment:fragment:1.7.1
|
||||
androidx.graphics:graphics-path:1.0.1
|
||||
androidx.hilt:hilt-navigation-compose:1.2.0
|
||||
androidx.hilt:hilt-navigation:1.2.0
|
||||
androidx.interpolator:interpolator:1.0.0
|
||||
androidx.legacy:legacy-support-core-utils:1.0.0
|
||||
androidx.lifecycle:lifecycle-common-java8:2.8.4
|
||||
androidx.lifecycle:lifecycle-common-jvm:2.8.4
|
||||
androidx.lifecycle:lifecycle-common:2.8.4
|
||||
androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4
|
||||
androidx.lifecycle:lifecycle-livedata-core:2.8.4
|
||||
androidx.lifecycle:lifecycle-livedata:2.8.4
|
||||
androidx.lifecycle:lifecycle-process:2.8.4
|
||||
androidx.lifecycle:lifecycle-runtime-android:2.8.4
|
||||
androidx.lifecycle:lifecycle-runtime-compose-android:2.8.4
|
||||
androidx.lifecycle:lifecycle-runtime-compose:2.8.4
|
||||
androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.4
|
||||
androidx.lifecycle:lifecycle-runtime-ktx:2.8.4
|
||||
androidx.lifecycle:lifecycle-runtime:2.8.4
|
||||
androidx.lifecycle:lifecycle-viewmodel-android:2.8.4
|
||||
androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.4
|
||||
androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4
|
||||
androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4
|
||||
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4
|
||||
androidx.lifecycle:lifecycle-viewmodel:2.8.4
|
||||
androidx.loader:loader:1.0.0
|
||||
androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
|
||||
androidx.metrics:metrics-performance:1.0.0-beta01
|
||||
androidx.multidex:multidex:2.0.1
|
||||
androidx.navigation:navigation-common-ktx:2.8.0-rc01
|
||||
androidx.navigation:navigation-common:2.8.0-rc01
|
||||
androidx.navigation:navigation-compose:2.8.0-rc01
|
||||
androidx.navigation:navigation-runtime-ktx:2.8.0-rc01
|
||||
androidx.navigation:navigation-runtime:2.8.0-rc01
|
||||
androidx.print:print:1.0.0
|
||||
androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05
|
||||
androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05
|
||||
androidx.profileinstaller:profileinstaller:1.3.1
|
||||
androidx.resourceinspection:resourceinspection-annotation:1.0.1
|
||||
androidx.savedstate:savedstate-ktx:1.2.1
|
||||
androidx.savedstate:savedstate:1.2.1
|
||||
androidx.startup:startup-runtime:1.1.1
|
||||
androidx.tracing:tracing-ktx:1.2.0
|
||||
androidx.tracing:tracing:1.2.0
|
||||
androidx.vectordrawable:vectordrawable-animated:1.1.0
|
||||
androidx.vectordrawable:vectordrawable:1.1.0
|
||||
androidx.versionedparcelable:versionedparcelable:1.1.1
|
||||
androidx.viewpager:viewpager:1.0.0
|
||||
app.cash.turbine:turbine-jvm:1.1.0
|
||||
app.cash.turbine:turbine:1.1.0
|
||||
co.touchlab:stately-concurrency-jvm:2.0.6
|
||||
co.touchlab:stately-concurrency:2.0.6
|
||||
co.touchlab:stately-concurrent-collections-jvm:2.0.6
|
||||
co.touchlab:stately-concurrent-collections:2.0.6
|
||||
co.touchlab:stately-strict-jvm:2.0.6
|
||||
co.touchlab:stately-strict:2.0.6
|
||||
com.github.Raizlabs.DBFlow:dbflow-core:4.2.4
|
||||
com.github.Raizlabs.DBFlow:dbflow:4.2.4
|
||||
com.google.accompanist:accompanist-pager:0.34.0
|
||||
com.google.accompanist:accompanist-permissions:0.34.0
|
||||
com.google.android.datatransport:transport-api:3.2.0
|
||||
com.google.android.datatransport:transport-backend-cct:3.3.0
|
||||
com.google.android.datatransport:transport-runtime:3.3.0
|
||||
com.google.android.gms:play-services-ads-identifier:18.0.0
|
||||
com.google.android.gms:play-services-base:18.5.0
|
||||
com.google.android.gms:play-services-basement:18.4.0
|
||||
com.google.android.gms:play-services-cloud-messaging:17.2.0
|
||||
com.google.android.gms:play-services-maps:18.2.0
|
||||
com.google.android.gms:play-services-measurement-api:22.1.0
|
||||
com.google.android.gms:play-services-measurement-base:22.1.0
|
||||
com.google.android.gms:play-services-measurement-impl:22.1.0
|
||||
com.google.android.gms:play-services-measurement-sdk-api:22.1.0
|
||||
com.google.android.gms:play-services-measurement-sdk:22.1.0
|
||||
com.google.android.gms:play-services-measurement:22.1.0
|
||||
com.google.android.gms:play-services-oss-licenses:17.1.0
|
||||
com.google.android.gms:play-services-stats:17.0.2
|
||||
com.google.android.gms:play-services-tasks:18.2.0
|
||||
com.google.auto.value:auto-value-annotations:1.6.3
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.code.gson:gson:2.10.1
|
||||
com.google.dagger:dagger-lint-aar:2.52
|
||||
com.google.dagger:dagger:2.52
|
||||
com.google.dagger:hilt-android:2.52
|
||||
com.google.dagger:hilt-core:2.52
|
||||
com.google.errorprone:error_prone_annotations:2.26.0
|
||||
com.google.firebase:firebase-abt:21.1.1
|
||||
com.google.firebase:firebase-analytics-ktx:22.1.0
|
||||
com.google.firebase:firebase-analytics:22.1.0
|
||||
com.google.firebase:firebase-annotations:16.2.0
|
||||
com.google.firebase:firebase-bom:33.2.0
|
||||
com.google.firebase:firebase-common-ktx:21.0.0
|
||||
com.google.firebase:firebase-common:21.0.0
|
||||
com.google.firebase:firebase-components:18.0.0
|
||||
com.google.firebase:firebase-config-interop:16.0.1
|
||||
com.google.firebase:firebase-config:22.0.0
|
||||
com.google.firebase:firebase-crashlytics-ktx:19.0.3
|
||||
com.google.firebase:firebase-crashlytics:19.0.3
|
||||
com.google.firebase:firebase-datatransport:19.0.0
|
||||
com.google.firebase:firebase-encoders-json:18.0.1
|
||||
com.google.firebase:firebase-encoders-proto:16.0.0
|
||||
com.google.firebase:firebase-encoders:17.0.0
|
||||
com.google.firebase:firebase-iid-interop:17.1.0
|
||||
com.google.firebase:firebase-installations-interop:17.2.0
|
||||
com.google.firebase:firebase-installations:18.0.0
|
||||
com.google.firebase:firebase-measurement-connector:20.0.1
|
||||
com.google.firebase:firebase-messaging-ktx:24.0.1
|
||||
com.google.firebase:firebase-messaging:24.0.1
|
||||
com.google.firebase:firebase-perf-ktx:21.0.1
|
||||
com.google.firebase:firebase-perf:21.0.1
|
||||
com.google.firebase:firebase-sessions:2.0.3
|
||||
com.google.firebase:protolite-well-known-types:18.0.0
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:31.1-android
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.maps.android:maps-compose:4.4.1
|
||||
com.google.maps.android:maps-ktx:5.0.0
|
||||
com.google.protobuf:protobuf-javalite:3.21.11
|
||||
com.google.zxing:core:3.5.3
|
||||
com.squareup.okhttp3:logging-interceptor:4.12.0
|
||||
com.squareup.okhttp3:okhttp:4.12.0
|
||||
com.squareup.okio:okio-jvm:3.6.0
|
||||
com.squareup.okio:okio:3.6.0
|
||||
com.squareup.retrofit2:adapter-rxjava2:2.11.0
|
||||
com.squareup.retrofit2:converter-gson:2.11.0
|
||||
com.squareup.retrofit2:retrofit:2.11.0
|
||||
dev.chrisbanes.snapper:snapper:0.2.2
|
||||
io.github.mr0xf00:easycrop:0.1.1
|
||||
io.insert-koin:koin-android:3.6.0-Beta4
|
||||
io.insert-koin:koin-androidx-compose:3.6.0-Beta4
|
||||
io.insert-koin:koin-compose-jvm:1.2.0-Beta4
|
||||
io.insert-koin:koin-compose-viewmodel-jvm:1.2.0-Beta4
|
||||
io.insert-koin:koin-compose-viewmodel:1.2.0-Beta4
|
||||
io.insert-koin:koin-compose:1.2.0-Beta4
|
||||
io.insert-koin:koin-core-jvm:3.6.0-Beta4
|
||||
io.insert-koin:koin-core:3.6.0-Beta4
|
||||
io.michaelrocks:libphonenumber-android:8.13.35
|
||||
io.reactivex.rxjava2:rxandroid:2.1.1
|
||||
io.reactivex.rxjava2:rxjava:2.2.21
|
||||
jakarta.inject:jakarta.inject-api:2.0.1
|
||||
javax.inject:javax.inject:1
|
||||
net.bytebuddy:byte-buddy-agent:1.14.5
|
||||
net.bytebuddy:byte-buddy:1.14.5
|
||||
org.checkerframework:checker-qual:3.12.0
|
||||
org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0-rc03
|
||||
org.jetbrains.androidx.navigation:navigation-compose:2.7.0-alpha06
|
||||
org.jetbrains.compose.material3:material3:1.6.11
|
||||
org.jetbrains.compose.material:material:1.6.11
|
||||
org.jetbrains.compose.runtime:runtime:1.6.10-rc03
|
||||
org.jetbrains.compose.ui:ui-tooling-preview:1.6.11
|
||||
org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.20
|
||||
org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:2.0.20
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10
|
||||
org.jetbrains.kotlin:kotlin-stdlib:2.0.20
|
||||
org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.7
|
||||
org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.3
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.6.3
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3
|
||||
org.jetbrains:annotations:23.0.0
|
||||
org.mockito:mockito-core:5.4.0
|
||||
org.objenesis:objenesis:3.3
|
||||
org.reactivestreams:reactive-streams:1.0.4
|
||||
46876
androidApp/lint-baseline.xml
Normal file
46876
androidApp/lint-baseline.xml
Normal file
File diff suppressed because it is too large
Load Diff
138
androidApp/release-badging.txt
Normal file
138
androidApp/release-badging.txt
Normal file
@ -0,0 +1,138 @@
|
||||
package: name='org.mifos.mobile' versionCode='1' versionName='1.0' platformBuildVersionName='14' platformBuildVersionCode='34' compileSdkVersion='34' compileSdkVersionCodename='14'
|
||||
sdkVersion:'26'
|
||||
targetSdkVersion:'34'
|
||||
uses-permission: name='android.permission.INTERNET'
|
||||
uses-permission: name='android.permission.READ_MEDIA_IMAGES'
|
||||
uses-permission: name='android.permission.CAMERA'
|
||||
uses-permission: name='android.permission.READ_PHONE_STATE'
|
||||
uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'
|
||||
uses-permission: name='android.permission.READ_EXTERNAL_STORAGE'
|
||||
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'
|
||||
uses-permission: name='android.permission.VIBRATE'
|
||||
uses-permission: name='android.permission.POST_NOTIFICATIONS'
|
||||
uses-permission: name='android.permission.WAKE_LOCK'
|
||||
uses-permission: name='com.google.android.c2dm.permission.RECEIVE'
|
||||
uses-permission: name='com.google.android.gms.permission.AD_ID'
|
||||
uses-permission: name='android.permission.ACCESS_ADSERVICES_ATTRIBUTION'
|
||||
uses-permission: name='android.permission.ACCESS_ADSERVICES_AD_ID'
|
||||
uses-permission: name='com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE'
|
||||
uses-permission: name='org.mifos.mobile.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION'
|
||||
application-label:'Mifos Mobile'
|
||||
application-label-af:'Mifos Mobile'
|
||||
application-label-am:'Mifos Mobile'
|
||||
application-label-ar:'ميفوس موبايل'
|
||||
application-label-as:'Mifos Mobile'
|
||||
application-label-az:'Mifos Mobile'
|
||||
application-label-be:'Mifos Mobile'
|
||||
application-label-bg:'Mifos Mobile'
|
||||
application-label-bn:'Mifos Mobile'
|
||||
application-label-bs:'Mifos Mobile'
|
||||
application-label-ca:'Mifos Mobile'
|
||||
application-label-cs:'Mifos Mobile'
|
||||
application-label-da:'Mifos Mobile'
|
||||
application-label-de:'Mifos Mobile'
|
||||
application-label-el:'Mifos Mobile'
|
||||
application-label-en-AU:'Mifos Mobile'
|
||||
application-label-en-CA:'Mifos Mobile'
|
||||
application-label-en-GB:'Mifos Mobile'
|
||||
application-label-en-IN:'Mifos Mobile'
|
||||
application-label-en-XC:'Mifos Mobile'
|
||||
application-label-es:'Mifos Mobile'
|
||||
application-label-es-US:'Mifos Mobile'
|
||||
application-label-et:'Mifos Mobile'
|
||||
application-label-eu:'Mifos Mobile'
|
||||
application-label-fa:'Mifos Mobile'
|
||||
application-label-fa-AF:'Mifos Mobile'
|
||||
application-label-fi:'Mifos Mobile'
|
||||
application-label-fr:'Mifos Mobile'
|
||||
application-label-fr-CA:'Mifos Mobile'
|
||||
application-label-gl:'Mifos Mobile'
|
||||
application-label-gu:'Mifos Mobile'
|
||||
application-label-hi:'Mifos Mobile'
|
||||
application-label-hr:'Mifos Mobile'
|
||||
application-label-hu:'Mifos Mobile'
|
||||
application-label-hy:'Mifos Mobile'
|
||||
application-label-in:'Mifos Mobile'
|
||||
application-label-is:'Mifos Mobile'
|
||||
application-label-it:'Mifos Mobile'
|
||||
application-label-it-IT:'Mifos Mobile'
|
||||
application-label-iw:'Mifos Mobile'
|
||||
application-label-ja:'Mifos Mobile'
|
||||
application-label-ka:'Mifos Mobile'
|
||||
application-label-kk:'Mifos Mobile'
|
||||
application-label-km:'Mifos Mobile'
|
||||
application-label-kn:'Mifos Mobile'
|
||||
application-label-ko:'Mifos Mobile'
|
||||
application-label-ky:'Mifos Mobile'
|
||||
application-label-lo:'Mifos Mobile'
|
||||
application-label-lt:'Mifos Mobile'
|
||||
application-label-lv:'Mifos Mobile'
|
||||
application-label-mk:'Mifos Mobile'
|
||||
application-label-ml:'Mifos Mobile'
|
||||
application-label-mn:'Mifos Mobile'
|
||||
application-label-mr:'Mifos Mobile'
|
||||
application-label-ms:'Mifos Mobile'
|
||||
application-label-my:'Mifos မိုဘိုင်း'
|
||||
application-label-nb:'Mifos Mobile'
|
||||
application-label-ne:'Mifos Mobile'
|
||||
application-label-nl:'Mifos Mobile'
|
||||
application-label-or:'Mifos Mobile'
|
||||
application-label-pa:'Mifos Mobile'
|
||||
application-label-pl:'Mifos Mobile'
|
||||
application-label-pt:'Mifos Mobile'
|
||||
application-label-pt-BR:'Mifos Mobile'
|
||||
application-label-pt-PT:'Mifos Mobile'
|
||||
application-label-ro:'Mifos Mobile'
|
||||
application-label-ru:'Mifos Mobile'
|
||||
application-label-ru-RU:'Mifos Mobile'
|
||||
application-label-si:'Mifos Mobile'
|
||||
application-label-sk:'Mifos Mobile'
|
||||
application-label-sl:'Mifos Mobile'
|
||||
application-label-so:'Mifos Mobile'
|
||||
application-label-sq:'Mifos Mobile'
|
||||
application-label-sr:'Mifos Mobile'
|
||||
application-label-sr-Latn:'Mifos Mobile'
|
||||
application-label-sv:'Mifos Mobile'
|
||||
application-label-sw:'Mifos Mobile'
|
||||
application-label-ta:'Mifos Mobile'
|
||||
application-label-te:'Mifos Mobile'
|
||||
application-label-th:'Mifos Mobile'
|
||||
application-label-tl:'Mifos Mobile'
|
||||
application-label-tr:'Mifos Mobile'
|
||||
application-label-tr-TR:'Mifos Mobile'
|
||||
application-label-uk:'Mifos Mobile'
|
||||
application-label-ur:'Mifos موبائل'
|
||||
application-label-uz:'Mifos Mobile'
|
||||
application-label-vi:'Mifos Mobile'
|
||||
application-label-zh:'Mifos Mobile'
|
||||
application-label-zh-CN:'Mifos Mobile'
|
||||
application-label-zh-HK:'Mifos Mobile'
|
||||
application-label-zh-TW:'Mifos Mobile'
|
||||
application-label-zu:'Mifos Mobile'
|
||||
application-icon-120:'res/mipmap-anydpi-v26/ic_launcher.xml'
|
||||
application-icon-160:'res/mipmap-anydpi-v26/ic_launcher.xml'
|
||||
application-icon-240:'res/mipmap-anydpi-v26/ic_launcher.xml'
|
||||
application-icon-320:'res/mipmap-anydpi-v26/ic_launcher.xml'
|
||||
application-icon-480:'res/mipmap-anydpi-v26/ic_launcher.xml'
|
||||
application-icon-640:'res/mipmap-anydpi-v26/ic_launcher.xml'
|
||||
application-icon-65534:'res/mipmap-anydpi-v26/ic_launcher.xml'
|
||||
application: label='Mifos Mobile' icon='res/mipmap-anydpi-v26/ic_launcher.xml'
|
||||
launchable-activity: name='org.mifos.mobile.HomeActivity' label='' icon=''
|
||||
uses-library-not-required:'org.apache.http.legacy'
|
||||
property: name='android.adservices.AD_SERVICES_CONFIG' resource='res/xml/ga_ad_services_config.xml'
|
||||
uses-library-not-required:'android.ext.adservices'
|
||||
feature-group: label=''
|
||||
uses-gl-es: '0x20000'
|
||||
uses-feature-not-required: name='android.hardware.camera'
|
||||
uses-feature: name='android.hardware.camera.any'
|
||||
uses-feature: name='android.hardware.faketouch'
|
||||
uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
|
||||
main
|
||||
other-activities
|
||||
other-receivers
|
||||
other-services
|
||||
supports-screens: 'small' 'normal' 'large' 'xlarge'
|
||||
supports-any-density: 'true'
|
||||
locales: '--_--' 'af' 'am' 'ar' 'as' 'az' 'be' 'bg' 'bn' 'bs' 'ca' 'cs' 'da' 'de' 'el' 'en-AU' 'en-CA' 'en-GB' 'en-IN' 'en-XC' 'es' 'es-US' 'et' 'eu' 'fa' 'fa-AF' 'fi' 'fr' 'fr-CA' 'gl' 'gu' 'hi' 'hr' 'hu' 'hy' 'in' 'is' 'it' 'it-IT' 'iw' 'ja' 'ka' 'kk' 'km' 'kn' 'ko' 'ky' 'lo' 'lt' 'lv' 'mk' 'ml' 'mn' 'mr' 'ms' 'my' 'nb' 'ne' 'nl' 'or' 'pa' 'pl' 'pt' 'pt-BR' 'pt-PT' 'ro' 'ru' 'ru-RU' 'si' 'sk' 'sl' 'so' 'sq' 'sr' 'sr-Latn' 'sv' 'sw' 'ta' 'te' 'th' 'tl' 'tr' 'tr-TR' 'uk' 'ur' 'uz' 'vi' 'zh' 'zh-CN' 'zh-HK' 'zh-TW' 'zu'
|
||||
densities: '120' '160' '240' '320' '480' '640' '65534'
|
||||
native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64'
|
||||
@ -1,3 +1,12 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile
|
||||
|
||||
import androidx.test.InstrumentationRegistry
|
||||
@ -1,5 +0,0 @@
|
||||
<resources>
|
||||
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">
|
||||
AIzaSyBbeT2BaMWLj-lReCgYoNmXs_TIyRLr9qQ
|
||||
</string>
|
||||
</resources>
|
||||
@ -1,7 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2024 Mifos Initiative
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file,
|
||||
You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.mifos.mobile">
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
@ -10,7 +18,9 @@
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera.any" />
|
||||
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
@ -18,53 +28,32 @@
|
||||
<application
|
||||
android:name=".MifosSelfServiceApp"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/core_common_mifos_icon"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:label="@string/feature_about_app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<meta-data
|
||||
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||
android:value="barcode_ui"/>
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
<meta-data
|
||||
android:name="com.google.android.geo.API_KEY"
|
||||
android:value="@string/google_maps_key" />
|
||||
|
||||
android:theme="@style/Theme.MifosSplash">
|
||||
<activity
|
||||
android:name=".ui.activities.LoginActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/feature_about_app_name"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<activity android:name="com.canhub.cropper.CropImageActivity"
|
||||
android:theme="@style/Base.Theme.AppCompat"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".ui.activities.SplashActivity"
|
||||
android:name=".HomeActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/SplashTheme">
|
||||
android:theme="@style/Theme.MifosSplash"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.activities.HomeActivity"
|
||||
android:configChanges="screenLayout|screenSize|orientation"
|
||||
android:label="@string/home"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity
|
||||
android:name=".ui.activities.PassCodeActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||
android:value="barcode_ui" />
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
<meta-data
|
||||
android:name="com.google.android.geo.API_KEY"
|
||||
android:value="@string/google_maps_key" />
|
||||
<activity
|
||||
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
@ -73,21 +62,6 @@
|
||||
android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<receiver
|
||||
android:name=".ui.widgets.ChargeAppWidget"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/charge_app_widget_info" />
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".ui.widgets.ChargeWidgetService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
@ -98,18 +72,6 @@
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/fileproviderpath" />
|
||||
</provider>
|
||||
|
||||
<service
|
||||
android:name=".utils.fcm.MifosFirebaseMessagingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name=".utils.fcm.RegistrationIntentService"
|
||||
android:exported="false" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
BIN
androidApp/src/main/ic_launcher-playstore.png
Normal file
BIN
androidApp/src/main/ic_launcher-playstore.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
@ -1,51 +0,0 @@
|
||||
package org.mifos.mobile
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.multidex.MultiDex
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.raizlabs.android.dbflow.config.FlowConfig
|
||||
import com.raizlabs.android.dbflow.config.FlowManager
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import org.mifos.mobile.core.common.utils.LanguageHelper.onAttach
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
import org.mifos.mobile.feature.settings.applySavedTheme
|
||||
|
||||
/**
|
||||
* @author ishan
|
||||
* @since 08/07/16
|
||||
*/
|
||||
@HiltAndroidApp
|
||||
class MifosSelfServiceApp : MultiDexApplication() {
|
||||
|
||||
companion object {
|
||||
private var instance: MifosSelfServiceApp? = null
|
||||
operator fun get(context: Context): MifosSelfServiceApp {
|
||||
return context.applicationContext as MifosSelfServiceApp
|
||||
}
|
||||
|
||||
val context: Context?
|
||||
get() = instance
|
||||
|
||||
init {
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
MultiDex.install(this)
|
||||
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true)
|
||||
instance = this
|
||||
FlowManager.init(FlowConfig.Builder(this).build())
|
||||
PreferencesHelper(this).applySavedTheme()
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
context?.let { onAttach(it) }
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
package org.mifos.mobile.di
|
||||
|
||||
import android.content.Context
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import org.mifos.mobile.core.datastore.DatabaseHelper
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
import org.mifos.mobile.core.network.BaseApiManager
|
||||
import org.mifos.mobile.core.network.DataManager
|
||||
import org.mifos.mobile.core.network.services.AuthenticationService
|
||||
import org.mifos.mobile.core.network.services.BeneficiaryService
|
||||
import org.mifos.mobile.core.network.services.ClientChargeService
|
||||
import org.mifos.mobile.core.network.services.ClientService
|
||||
import org.mifos.mobile.core.network.services.GuarantorService
|
||||
import org.mifos.mobile.core.network.services.LoanAccountsListService
|
||||
import org.mifos.mobile.core.network.services.NotificationService
|
||||
import org.mifos.mobile.core.network.services.RecentTransactionsService
|
||||
import org.mifos.mobile.core.network.services.RegistrationService
|
||||
import org.mifos.mobile.core.network.services.SavingAccountsListService
|
||||
import org.mifos.mobile.core.network.services.ThirdPartyTransferService
|
||||
import org.mifos.mobile.core.network.services.UserDetailsService
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* @author ishan
|
||||
* @since 08/07/16
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object ApplicationModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providePrefManager(@ApplicationContext context: Context?): PreferencesHelper {
|
||||
return PreferencesHelper(context)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideBaseApiManager(
|
||||
authenticationService: AuthenticationService,
|
||||
clientsService: ClientService,
|
||||
savingAccountsListService: SavingAccountsListService,
|
||||
loanAccountsListService: LoanAccountsListService,
|
||||
recentTransactionsService: RecentTransactionsService,
|
||||
clientChargeService: ClientChargeService,
|
||||
beneficiaryService: BeneficiaryService,
|
||||
thirdPartyTransferService: ThirdPartyTransferService,
|
||||
registrationService: RegistrationService,
|
||||
notificationService: NotificationService,
|
||||
userDetailsService: UserDetailsService,
|
||||
guarantorService: GuarantorService
|
||||
): BaseApiManager {
|
||||
return BaseApiManager(
|
||||
authenticationService,
|
||||
clientsService,
|
||||
savingAccountsListService,
|
||||
loanAccountsListService,
|
||||
recentTransactionsService,
|
||||
clientChargeService,
|
||||
beneficiaryService,
|
||||
thirdPartyTransferService,
|
||||
registrationService,
|
||||
notificationService,
|
||||
userDetailsService,
|
||||
guarantorService
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesDataManager(
|
||||
preferencesHelper: PreferencesHelper,
|
||||
baseApiManager: BaseApiManager,
|
||||
databaseHelper: DatabaseHelper
|
||||
): DataManager {
|
||||
return DataManager(preferencesHelper, baseApiManager, databaseHelper)
|
||||
}
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
package org.mifos.mobile.ui.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.provider.Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import org.mifos.mobile.R
|
||||
import org.mifos.mobile.core.model.enums.BiometricCapability
|
||||
|
||||
open class BiometricAuthentication(
|
||||
val context: FragmentActivity,
|
||||
) {
|
||||
private val executor = ContextCompat.getMainExecutor(context)
|
||||
private val callback = object : BiometricPrompt.AuthenticationCallback() {
|
||||
|
||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||
super.onAuthenticationSucceeded(result)
|
||||
val intent = Intent(context, HomeActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
context.startActivity(intent)
|
||||
context.finish()
|
||||
}
|
||||
}
|
||||
|
||||
private val biometricPrompt = BiometricPrompt(context, executor, callback)
|
||||
|
||||
fun launchBiometricEnrollment(resultLauncher: ActivityResultLauncher<Intent>) {
|
||||
val intent: Intent = when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
|
||||
Intent(Settings.ACTION_BIOMETRIC_ENROLL).putExtra(
|
||||
EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
|
||||
BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.BIOMETRIC_WEAK,
|
||||
)
|
||||
}
|
||||
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P -> {
|
||||
Intent(Settings.ACTION_FINGERPRINT_ENROLL)
|
||||
}
|
||||
|
||||
else -> {
|
||||
Intent(Settings.ACTION_SECURITY_SETTINGS)
|
||||
}
|
||||
}
|
||||
resultLauncher.launch(intent)
|
||||
}
|
||||
|
||||
fun getBiometricCapabilities(): BiometricCapability {
|
||||
val biometricManager = BiometricManager.from(context)
|
||||
return when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK or BiometricManager.Authenticators.DEVICE_CREDENTIAL)) {
|
||||
BiometricManager.BIOMETRIC_SUCCESS -> {
|
||||
BiometricCapability.HAS_BIOMETRIC_AUTH
|
||||
}
|
||||
|
||||
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
|
||||
BiometricCapability.NOT_ENROLLED
|
||||
}
|
||||
|
||||
else -> {
|
||||
BiometricCapability.NOT_SUPPORTED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun authenticateWithBiometrics() {
|
||||
val promptInfo = BiometricPrompt.PromptInfo.Builder().apply {
|
||||
setTitle(context.getString(R.string.sign_in_fingerprint))
|
||||
setDescription(context.getString(R.string.scan_your_fingerprint))
|
||||
setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_WEAK or BiometricManager.Authenticators.DEVICE_CREDENTIAL)
|
||||
}.build()
|
||||
|
||||
biometricPrompt.authenticate(promptInfo)
|
||||
}
|
||||
}
|
||||
@ -1,135 +0,0 @@
|
||||
package org.mifos.mobile.ui.activities
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.GoogleApiAvailability
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.mifos.mobile.R
|
||||
import org.mifos.mobile.core.common.Constants
|
||||
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
|
||||
import org.mifos.mobile.feature.home.navigation.HomeNavigation
|
||||
import org.mifos.mobile.feature.user.profile.viewmodel.UserDetailViewModel
|
||||
import org.mifos.mobile.navigation.RootNavGraph
|
||||
import org.mifos.mobile.utils.Toaster
|
||||
import org.mifos.mobile.utils.fcm.RegistrationIntentService
|
||||
|
||||
/**
|
||||
* @author Vishwajeet
|
||||
* @since 14/07/2016
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class HomeActivity : ComponentActivity() {
|
||||
|
||||
private val viewModel: UserDetailViewModel by viewModels()
|
||||
private var isReceiverRegistered = false
|
||||
private var doubleBackToExitPressedOnce = false
|
||||
private lateinit var navHostController: NavHostController
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (checkPlayServices()) {
|
||||
// Start IntentService to register this application with GCM.
|
||||
val intent = Intent(this, RegistrationIntentService::class.java)
|
||||
startService(intent)
|
||||
}
|
||||
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
MifosMobileTheme {
|
||||
navHostController = rememberNavController()
|
||||
RootNavGraph(
|
||||
startDestination = HomeNavigation.HomeBase.route,
|
||||
navController = navHostController,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(registerReceiver)
|
||||
isReceiverRegistered = false
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (!isReceiverRegistered) {
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||
registerReceiver,
|
||||
IntentFilter(Constants.REGISTER_ON_SERVER),
|
||||
)
|
||||
isReceiverRegistered = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handling back press
|
||||
*/
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onBackPressed() {
|
||||
val currentRoute = navHostController.currentBackStackEntry?.destination?.route
|
||||
|
||||
if (currentRoute == HomeNavigation.HomeScreen.route) {
|
||||
// if (doubleBackToExitPressedOnce && stackCount() == 0) {
|
||||
// finish()
|
||||
// return
|
||||
// }
|
||||
doubleBackToExitPressedOnce = true
|
||||
Toaster.show(findViewById(android.R.id.content), getString(R.string.exit_message))
|
||||
Handler().postDelayed({ doubleBackToExitPressedOnce = false }, 2000)
|
||||
}
|
||||
|
||||
super.onBackPressed()
|
||||
|
||||
// if (stackCount() != 0) {
|
||||
// super.onBackPressed()
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check the device to make sure it has the Google Play Services APK. If
|
||||
* it doesn't, display a dialog that allows users to download the APK from
|
||||
* the Google Play Store or enable it in the device's system settings.
|
||||
*/
|
||||
private fun checkPlayServices(): Boolean {
|
||||
val apiAvailability = GoogleApiAvailability.getInstance()
|
||||
val resultCode = apiAvailability.isGooglePlayServicesAvailable(this)
|
||||
if (resultCode != ConnectionResult.SUCCESS) {
|
||||
if (apiAvailability.isUserResolvableError(resultCode)) {
|
||||
apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
|
||||
?.show()
|
||||
} else {
|
||||
Log.i(HomeActivity::class.java.name, "This device is not supported.")
|
||||
finish()
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private val registerReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val token = intent.getStringExtra(Constants.TOKEN)
|
||||
token?.let { viewModel.registerNotification(it) }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val PLAY_SERVICES_RESOLUTION_REQUEST = 9000
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package org.mifos.mobile.ui.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
|
||||
import org.mifos.mobile.feature.auth.navigation.AuthenticationNavigation
|
||||
import org.mifos.mobile.navigation.RootNavGraph
|
||||
|
||||
/**
|
||||
* @author Vishwajeet
|
||||
* @since 05/06/16
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class LoginActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
MifosMobileTheme {
|
||||
val navController = rememberNavController()
|
||||
RootNavGraph(
|
||||
startDestination = AuthenticationNavigation.AuthenticationBase.route,
|
||||
navController = navController,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package org.mifos.mobile.ui.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
|
||||
import org.mifos.mobile.navigation.PASSCODE_SCREEN
|
||||
import org.mifos.mobile.navigation.RootNavGraph
|
||||
|
||||
@AndroidEntryPoint
|
||||
class PassCodeActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
MifosMobileTheme {
|
||||
val navController = rememberNavController()
|
||||
|
||||
Box(modifier = Modifier.statusBarsPadding()) {
|
||||
RootNavGraph(
|
||||
startDestination = PASSCODE_SCREEN,
|
||||
navController = navController,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package org.mifos.mobile.ui.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
|
||||
/*
|
||||
* Created by saksham on 01/June/2018
|
||||
*/
|
||||
class SplashActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
// TODO:: check for user logged in or not, and if logged in move to PasscodeActivity instead.
|
||||
val intent = Intent(this, LoginActivity::class.java)
|
||||
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
package org.mifos.mobile.ui.views
|
||||
|
||||
/**
|
||||
* @author Rajan Maurya
|
||||
*/
|
||||
interface BaseActivityCallback {
|
||||
|
||||
fun showProgressDialog(message: String?)
|
||||
|
||||
fun hideProgressDialog()
|
||||
|
||||
fun setToolbarTitle(title: String?)
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
package org.mifos.mobile.ui.widgets
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProvider
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.widget.RemoteViews
|
||||
import org.mifos.mobile.R
|
||||
|
||||
/**
|
||||
* Implementation of App Widget functionality.
|
||||
*/
|
||||
class ChargeAppWidget : AppWidgetProvider() {
|
||||
|
||||
override fun onUpdate(
|
||||
context: Context,
|
||||
appWidgetManager: AppWidgetManager,
|
||||
appWidgetIds: IntArray,
|
||||
) {
|
||||
// There may be multiple widgets active, so update all of them
|
||||
for (appWidgetId in appWidgetIds) {
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId)
|
||||
}
|
||||
super.onUpdate(context, appWidgetManager, appWidgetIds)
|
||||
}
|
||||
|
||||
override fun onEnabled(context: Context) {
|
||||
// Enter relevant functionality for when the first widget is created
|
||||
}
|
||||
|
||||
override fun onDisabled(context: Context) {
|
||||
// Enter relevant functionality for when the last widget is disabled
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun updateAppWidget(
|
||||
context: Context,
|
||||
appWidgetManager: AppWidgetManager,
|
||||
appWidgetId: Int,
|
||||
) {
|
||||
val views = RemoteViews(context.packageName, R.layout.charge_app_widget)
|
||||
|
||||
// Set up the collection
|
||||
setRemoteAdapter(context, views)
|
||||
// Instruct the widget manager to update the widget
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the remote adapter used to fill in the list items
|
||||
*
|
||||
* @param views RemoteViews to set the RemoteAdapter
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
private fun setRemoteAdapter(context: Context, views: RemoteViews) {
|
||||
views.setRemoteAdapter(
|
||||
R.id.lv_charges,
|
||||
Intent(context, ChargeWidgetService::class.java),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,110 +0,0 @@
|
||||
package org.mifos.mobile.ui.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.RemoteViews
|
||||
import android.widget.RemoteViewsService.RemoteViewsFactory
|
||||
import android.widget.Toast
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import org.mifos.mobile.R
|
||||
import org.mifos.mobile.core.data.repository.ClientChargeRepository
|
||||
import org.mifos.mobile.core.datastore.model.Charge
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* ChargeWidgetDataProvider acts as the adapter for the collection view widget,
|
||||
* providing RemoteViews to the widget in the getViewAt method.
|
||||
*/
|
||||
class ChargeWidgetDataProvider(@param:ApplicationContext private val context: Context) :
|
||||
RemoteViewsFactory {
|
||||
|
||||
@Inject
|
||||
lateinit var clientChargeRepository: ClientChargeRepository
|
||||
|
||||
|
||||
private var charges: List<Charge?>?
|
||||
private val `object`: ReentrantLock = ReentrantLock()
|
||||
private val condition = `object`.newCondition()
|
||||
|
||||
override fun onCreate() {
|
||||
|
||||
}
|
||||
|
||||
override fun onDataSetChanged() {
|
||||
// TODO Make ClientId Dynamic
|
||||
//clientChargeViewModel.loadClientLocalCharges()
|
||||
synchronized(`object`) {
|
||||
try {
|
||||
// Calling wait() will block this thread until another thread
|
||||
// calls notify() on the object.
|
||||
condition.await()
|
||||
} catch (e: InterruptedException) {
|
||||
// Happens if someone interrupts your thread.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCount(): Int {
|
||||
return if (charges != null) {
|
||||
charges!!.size
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewAt(position: Int): RemoteViews {
|
||||
val charge = charges?.get(position)
|
||||
val itemId = R.layout.item_widget_client_charge
|
||||
val view = RemoteViews(context.packageName, itemId)
|
||||
view.setTextViewText(R.id.tv_charge_name, charge?.name)
|
||||
view.setTextViewText(R.id.tv_charge_amount, charge?.amount.toString())
|
||||
view.setImageViewResource(R.id.circle_status, R.drawable.ic_attach_money_black_24dp)
|
||||
return view
|
||||
}
|
||||
|
||||
override fun getLoadingView(): RemoteViews? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getViewTypeCount(): Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
return position.toLong()
|
||||
}
|
||||
|
||||
override fun hasStableIds(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
fun showErrorFetchingClientCharges(message: String?) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.error_client_charge_loading),
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
}
|
||||
|
||||
fun showClientCharges(clientChargesList: List<Charge?>?) {
|
||||
charges = clientChargesList
|
||||
synchronized(`object`) {
|
||||
condition.signal()
|
||||
}
|
||||
}
|
||||
|
||||
fun showProgress() {}
|
||||
|
||||
fun hideProgress() {}
|
||||
|
||||
override fun onDestroy() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG_TAG = ChargeWidgetDataProvider::class.java.simpleName
|
||||
}
|
||||
|
||||
init {
|
||||
charges = ArrayList()
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package org.mifos.mobile.ui.widgets
|
||||
|
||||
import android.content.Intent
|
||||
import android.widget.RemoteViewsService
|
||||
|
||||
/**
|
||||
* ChargeWidgetService is the [RemoteViewsService] that will return our RemoteViewsFactory
|
||||
*/
|
||||
class ChargeWidgetService : RemoteViewsService() {
|
||||
|
||||
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
|
||||
return ChargeWidgetDataProvider(this)
|
||||
}
|
||||
}
|
||||
@ -1,152 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.mifos.mobile.R
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 14/7/17.
|
||||
*/
|
||||
object CheckSelfPermissionAndRequest {
|
||||
/**
|
||||
* This Method Check the Permission is granted or not to the App. If the Permission granted,
|
||||
* returns true and If not permission denied then returns false.
|
||||
*
|
||||
* @param context Context
|
||||
* @param permission Manifest.permission...Permission...
|
||||
* @return Boolean True or False.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun checkSelfPermission(context: Context?, permission: String?): Boolean {
|
||||
return ContextCompat.checkSelfPermission(context!!, permission!!) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
/**
|
||||
* This Method is requesting to device to grant the permission. When App is trying to
|
||||
* request the device to grant the permission, then their is Three cases.
|
||||
* 1. First case Device Prompt the Permission Dialog to user and user accepted or denied the
|
||||
* Permission.
|
||||
* 2. Second case will come, if user will denied the permission, after onclick dialog denied
|
||||
* button and next time App ask for permission, It will show a Material Dialog and there
|
||||
* will be a message to tell the user that you have denied the permission before, So do
|
||||
* you want to give this permission to app or not, If yes then click on Re-Try dialog button
|
||||
* and if not then click on Dialog button "I'm Sure", to not to give this permission to the
|
||||
* app.
|
||||
*
|
||||
*
|
||||
* And as user will click on "Re-Try" dialog button, he will be prompt with the with
|
||||
* permission dialog with "[-] never ask again" and have two options first one to click on
|
||||
* denied button again and put Un check the never ask check box. In this case, user will
|
||||
* prompt with permission dialog with "[-] never ask again" in the loop, whenever app ask
|
||||
* for that permission.
|
||||
*
|
||||
*
|
||||
* and If user will click on "[_/] never ask again" check box then permission dialog with
|
||||
* that permission will not prompt to the user.
|
||||
* 3. Third case will came. when user have denied to accept permission with never ask again.
|
||||
* then user will prompt with dialog and message that you have denied this permission with
|
||||
* never ask again. but this is necessary permission to this app feature. and to grant
|
||||
* this permission please click on dialog app settings button and give the permission to
|
||||
* work with this feature.
|
||||
*
|
||||
* @param activity AppCompatActivity
|
||||
* @param permission Manifest.permission...Permission...
|
||||
* @param permissionRequestCode Permission Request Code.
|
||||
* @param dialogMessageRetry Dialog Message Retry
|
||||
* @param messageNeverAskAgain Dialog Message Never Ask Again
|
||||
* @param permissionDeniedStatus Permission Denied Status
|
||||
*/
|
||||
@JvmStatic
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
fun requestPermission(
|
||||
activity: AppCompatActivity,
|
||||
permission: String,
|
||||
permissionRequestCode: Int,
|
||||
dialogMessageRetry: String?,
|
||||
messageNeverAskAgain: String?,
|
||||
permissionDeniedStatus: String?,
|
||||
) {
|
||||
// Should we show an explanation?
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
|
||||
// Show an explanation to the user *asynchronously* -- don't block
|
||||
// this thread waiting for the user's response! After the user
|
||||
// sees the explanation, try again to request the permission.
|
||||
MaterialDialog.Builder().init(activity)
|
||||
.setTitle(R.string.dialog_permission_denied)
|
||||
.setMessage(dialogMessageRetry)
|
||||
.setPositiveButton(
|
||||
R.string.dialog_action_re_try,
|
||||
DialogInterface.OnClickListener { _, _ ->
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
arrayOf(permission),
|
||||
permissionRequestCode,
|
||||
)
|
||||
},
|
||||
)
|
||||
.setNegativeButton(R.string.dialog_action_i_am_sure)
|
||||
.createMaterialDialog()
|
||||
.show()
|
||||
} else {
|
||||
// Requesting Permission, first time to the device.
|
||||
val preferencesHelper = PreferencesHelper(activity.applicationContext)
|
||||
if (preferencesHelper.getBoolean(permissionDeniedStatus, true) == true) {
|
||||
preferencesHelper.putBoolean(permissionDeniedStatus, false)
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
arrayOf(permission),
|
||||
permissionRequestCode,
|
||||
)
|
||||
} else {
|
||||
// Requesting Permission, more the one time and opening the setting to change
|
||||
// the Permission in App Settings.
|
||||
MaterialDialog.Builder().init(activity)
|
||||
.setMessage(messageNeverAskAgain)
|
||||
.setNegativeButton(R.string.dialog_action_cancel)
|
||||
.setPositiveButton(
|
||||
R.string.dialog_action_app_settings,
|
||||
DialogInterface.OnClickListener { _, _ -> // Making the Intent to grant the permission
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||
val uri = Uri.fromParts(
|
||||
activity.resources.getString(
|
||||
R.string.package_name,
|
||||
),
|
||||
activity.packageName,
|
||||
null,
|
||||
)
|
||||
intent.data = uri
|
||||
val pm = activity.packageManager
|
||||
if (intent.resolveActivity(pm) != null) {
|
||||
activity.startActivityForResult(
|
||||
intent,
|
||||
org.mifos.mobile.core.common.Constants.REQUEST_PERMISSION_SETTING,
|
||||
)
|
||||
} else {
|
||||
Toast.makeText(
|
||||
activity,
|
||||
activity.getString(
|
||||
R.string.msg_setting_activity_not_found,
|
||||
),
|
||||
Toast.LENGTH_LONG,
|
||||
).show()
|
||||
}
|
||||
},
|
||||
)
|
||||
.createMaterialDialog()
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import org.mifos.mobile.core.model.entity.accounts.Account
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 14/6/17.
|
||||
*/
|
||||
open class ComparatorBasedOnId : Comparator<Account?> {
|
||||
/**
|
||||
* Compares [Account] based on their Id
|
||||
* @param o1 the first object to be compared.
|
||||
* @param o2 the second object to be compared.
|
||||
* @return a negative integer, zero, or a positive integer as the
|
||||
* first argument is less than, equal to, or greater than the
|
||||
* second.
|
||||
*/
|
||||
override fun compare(o1: Account?, o2: Account?): Int {
|
||||
return if (o1 != null && o2 != null) {
|
||||
o2.id.toFloat().compareTo(o1.id.toFloat())
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,130 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import androidx.preference.DialogPreference.TargetFragment
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceDialogFragmentCompat
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import org.mifos.mobile.R
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
import org.mifos.mobile.ui.activities.LoginActivity
|
||||
import java.net.MalformedURLException
|
||||
import java.net.URL
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 11/03/18.
|
||||
*/
|
||||
class ConfigurationDialogFragmentCompat :
|
||||
PreferenceDialogFragmentCompat(),
|
||||
TargetFragment,
|
||||
TextWatcher {
|
||||
@JvmField
|
||||
@BindView(R.id.et_tenant)
|
||||
var etTenant: EditText? = null
|
||||
|
||||
@JvmField
|
||||
@BindView(R.id.et_base_url)
|
||||
var etBaseUrl: EditText? = null
|
||||
|
||||
@JvmField
|
||||
@BindView(R.id.til_tenant)
|
||||
var tilTenant: TextInputLayout? = null
|
||||
|
||||
@JvmField
|
||||
@BindView(R.id.til_base_url)
|
||||
var tilBaseUrl: TextInputLayout? = null
|
||||
private var preferencesHelper: PreferencesHelper? = null
|
||||
override fun onCreateDialogView(context: Context): View {
|
||||
return LayoutInflater.from(context).inflate(R.layout.preference_configuration, null)
|
||||
}
|
||||
|
||||
override fun onBindDialogView(view: View) {
|
||||
super.onBindDialogView(view)
|
||||
ButterKnife.bind(this, view)
|
||||
preferencesHelper = PreferencesHelper(context)
|
||||
val preference = preference as ConfigurationPreference
|
||||
etBaseUrl?.setText(preference.baseUrl)
|
||||
etTenant?.setText(preference.tenant)
|
||||
etBaseUrl?.text?.length?.let { etBaseUrl?.setSelection(it) }
|
||||
etTenant?.addTextChangedListener(this)
|
||||
etBaseUrl?.addTextChangedListener(this)
|
||||
}
|
||||
|
||||
override fun onDialogClosed(positiveResult: Boolean) {
|
||||
if (positiveResult && !isFieldEmpty && isUrlValid) {
|
||||
val preference = preference as ConfigurationPreference
|
||||
if (!(
|
||||
preference.baseUrl.toString()
|
||||
.equals(etBaseUrl!!.text.toString()) && preference.tenant.toString()
|
||||
.equals(etTenant!!.text.toString())
|
||||
)
|
||||
) {
|
||||
preference.updateConfigurations(
|
||||
etBaseUrl?.text.toString(),
|
||||
etTenant?.text.toString(),
|
||||
)
|
||||
preferencesHelper?.clear()
|
||||
val loginIntent = Intent(activity, LoginActivity::class.java)
|
||||
loginIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
startActivity(loginIntent)
|
||||
activity?.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun findPreference(key: CharSequence): Preference {
|
||||
return preference
|
||||
}
|
||||
|
||||
val isFieldEmpty: Boolean
|
||||
get() {
|
||||
if (etBaseUrl?.text.toString().trim { it <= ' ' }.isEmpty()) {
|
||||
return true
|
||||
}
|
||||
return etTenant?.text.toString().trim { it <= ' ' }.isEmpty()
|
||||
}
|
||||
val isUrlValid: Boolean
|
||||
get() = try {
|
||||
URL(etBaseUrl?.text.toString())
|
||||
true
|
||||
} catch (e: MalformedURLException) {
|
||||
false
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
if (s.toString().isEmpty()) {
|
||||
if (etBaseUrl?.text.toString().isEmpty()) {
|
||||
tilBaseUrl?.isErrorEnabled = true
|
||||
tilBaseUrl?.error = getString(
|
||||
R.string.error_validation_blank,
|
||||
getString(R.string.base_url),
|
||||
)
|
||||
}
|
||||
if (etTenant?.text.toString().isEmpty()) {
|
||||
tilTenant?.isErrorEnabled = true
|
||||
tilTenant?.error = getString(
|
||||
R.string.error_validation_blank,
|
||||
getString(R.string.tenant),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (etBaseUrl?.text.toString().length != 0) {
|
||||
tilBaseUrl?.isErrorEnabled = false
|
||||
}
|
||||
if (etTenant?.text.toString().length != 0) {
|
||||
tilTenant?.isErrorEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable) {}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.preference.DialogPreference
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 11/03/18.
|
||||
*/
|
||||
class ConfigurationPreference : DialogPreference {
|
||||
private var preferencesHelper: PreferencesHelper? = null
|
||||
|
||||
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr,
|
||||
) {
|
||||
init()
|
||||
}
|
||||
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
|
||||
init()
|
||||
}
|
||||
|
||||
constructor(context: Context?) : super(context) {
|
||||
init()
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
isPersistent = false
|
||||
preferencesHelper = PreferencesHelper(context)
|
||||
}
|
||||
|
||||
val baseUrl: String?
|
||||
get() = preferencesHelper?.baseUrl
|
||||
|
||||
fun updateConfigurations(baseUrl: String?, tenant: String?) {
|
||||
preferencesHelper?.updateConfiguration(baseUrl, tenant)
|
||||
}
|
||||
|
||||
val tenant: String?
|
||||
get() = preferencesHelper?.tenant
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 6/3/17.
|
||||
*/
|
||||
enum class DatePick {
|
||||
START, END
|
||||
}
|
||||
@ -1,110 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
|
||||
abstract class EndlessRecyclerViewScrollListener : RecyclerView.OnScrollListener {
|
||||
// The minimum amount of items to have below your current scroll position
|
||||
// before loading more.
|
||||
private var visibleThreshold = 5
|
||||
|
||||
// The current offset index of data you have loaded
|
||||
private var currentPage = 0
|
||||
|
||||
// The total number of items in the dataset after the last load
|
||||
private var previousTotalItemCount = 0
|
||||
|
||||
// True if we are still waiting for the last set of data to load.
|
||||
private var loading = true
|
||||
|
||||
// Sets the starting page index
|
||||
private val startingPageIndex = 0
|
||||
var mLayoutManager: RecyclerView.LayoutManager
|
||||
|
||||
constructor(layoutManager: LinearLayoutManager) {
|
||||
mLayoutManager = layoutManager
|
||||
}
|
||||
|
||||
constructor(layoutManager: GridLayoutManager) {
|
||||
mLayoutManager = layoutManager
|
||||
visibleThreshold = visibleThreshold * layoutManager.spanCount
|
||||
}
|
||||
|
||||
constructor(layoutManager: StaggeredGridLayoutManager) {
|
||||
mLayoutManager = layoutManager
|
||||
visibleThreshold = visibleThreshold * layoutManager.spanCount
|
||||
}
|
||||
|
||||
fun getLastVisibleItem(lastVisibleItemPositions: IntArray): Int {
|
||||
var maxSize = 0
|
||||
for (i in lastVisibleItemPositions.indices) {
|
||||
if (i == 0) {
|
||||
maxSize = lastVisibleItemPositions[i]
|
||||
} else if (lastVisibleItemPositions[i] > maxSize) {
|
||||
maxSize = lastVisibleItemPositions[i]
|
||||
}
|
||||
}
|
||||
return maxSize
|
||||
}
|
||||
|
||||
// This happens many times a second during a scroll, so be wary of the code you place here.
|
||||
// We are given a few useful parameters to help us work out if we need to load some more data,
|
||||
// but first we check if we are waiting for the previous load to finish.
|
||||
override fun onScrolled(view: RecyclerView, dx: Int, dy: Int) {
|
||||
var lastVisibleItemPosition = 0
|
||||
val totalItemCount = mLayoutManager.itemCount
|
||||
if (mLayoutManager is StaggeredGridLayoutManager) {
|
||||
val lastVisibleItemPositions =
|
||||
(mLayoutManager as StaggeredGridLayoutManager).findLastVisibleItemPositions(
|
||||
null,
|
||||
)
|
||||
// get maximum element within the list
|
||||
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions)
|
||||
} else if (mLayoutManager is GridLayoutManager) {
|
||||
lastVisibleItemPosition =
|
||||
(mLayoutManager as GridLayoutManager).findLastVisibleItemPosition()
|
||||
} else if (mLayoutManager is LinearLayoutManager) {
|
||||
lastVisibleItemPosition =
|
||||
(mLayoutManager as LinearLayoutManager).findLastVisibleItemPosition()
|
||||
}
|
||||
|
||||
// If the total item count is zero and the previous isn't, assume the
|
||||
// list is invalidated and should be reset back to initial state
|
||||
if (totalItemCount < previousTotalItemCount) {
|
||||
currentPage = startingPageIndex
|
||||
previousTotalItemCount = totalItemCount
|
||||
if (totalItemCount == 0) {
|
||||
loading = true
|
||||
}
|
||||
}
|
||||
// If it’s still loading, we check to see if the dataset count has
|
||||
// changed, if so we conclude it has finished loading and update the current page
|
||||
// number and total item count.
|
||||
if (loading && totalItemCount > previousTotalItemCount) {
|
||||
loading = false
|
||||
previousTotalItemCount = totalItemCount
|
||||
}
|
||||
|
||||
// If it isn’t currently loading, we check to see if we have breached
|
||||
// the visibleThreshold and need to reload more data.
|
||||
// If we do need to reload some more data, we execute onLoadMore to fetch the data.
|
||||
// threshold should reflect how many total columns there are too
|
||||
if (!loading && lastVisibleItemPosition + visibleThreshold > totalItemCount) {
|
||||
currentPage++
|
||||
onLoadMore(currentPage, totalItemCount, view)
|
||||
loading = true
|
||||
}
|
||||
}
|
||||
|
||||
// Call this method whenever performing new searches
|
||||
fun resetState() {
|
||||
currentPage = startingPageIndex
|
||||
previousTotalItemCount = 0
|
||||
loading = true
|
||||
}
|
||||
|
||||
// Defines the process for actually loading more data based on page
|
||||
abstract fun onLoadMore(page: Int, totalItemsCount: Int, view: RecyclerView?)
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import org.mifos.mobile.core.model.entity.guarantor.GuarantorApplicationPayload
|
||||
import org.mifos.mobile.core.model.entity.guarantor.GuarantorPayload
|
||||
import org.mifos.mobile.core.model.entity.guarantor.GuarantorTemplatePayload
|
||||
|
||||
sealed class GuarantorUiState {
|
||||
object Loading : GuarantorUiState()
|
||||
|
||||
data class ShowError(val message: String?) : GuarantorUiState()
|
||||
|
||||
data class GuarantorDeletedSuccessfully(val message: String?) : GuarantorUiState()
|
||||
|
||||
data class GuarantorUpdatedSuccessfully(val message: String?) : GuarantorUiState()
|
||||
|
||||
data class ShowGuarantorListSuccessfully(val payload: List<GuarantorPayload?>?) :
|
||||
GuarantorUiState()
|
||||
|
||||
data class ShowGuarantorApplication(val template: GuarantorTemplatePayload?) :
|
||||
GuarantorUiState()
|
||||
|
||||
data class ShowGuarantorUpdation(val template: GuarantorTemplatePayload?) : GuarantorUiState()
|
||||
|
||||
data class SubmittedSuccessfully(
|
||||
val message: String?,
|
||||
val payload: GuarantorApplicationPayload?
|
||||
) : GuarantorUiState()
|
||||
}
|
||||
@ -1,136 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Paint
|
||||
import android.util.Log
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 10/8/17.
|
||||
*/
|
||||
class ImageUtil {
|
||||
// Default width and height
|
||||
fun compressImage(decodedBytes: ByteArray): Bitmap? {
|
||||
return compress(decodedBytes, 816.0f, 612.0f)
|
||||
}
|
||||
|
||||
fun compressImage(decodedBytes: ByteArray, maxHeight: Float, maxWidth: Float): Bitmap? {
|
||||
return compress(decodedBytes, maxHeight, maxWidth)
|
||||
}
|
||||
|
||||
private fun compress(decodedBytes: ByteArray, maxHeight: Float, maxWidth: Float): Bitmap? {
|
||||
var scaledBitmap: Bitmap? = null
|
||||
val options = BitmapFactory.Options()
|
||||
|
||||
// by setting this field as true, the actual bitmap pixels are not loaded in the memory.
|
||||
// Just the bounds are loaded. If
|
||||
// you try the use the bitmap here, you will get null.
|
||||
options.inJustDecodeBounds = true
|
||||
var bmp = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size, options)
|
||||
var actualHeight = options.outHeight
|
||||
var actualWidth = options.outWidth
|
||||
var imgRatio = actualWidth / actualHeight.toFloat()
|
||||
val maxRatio = maxWidth / maxHeight
|
||||
|
||||
// width and height values are set maintaining the aspect ratio of the image
|
||||
if (actualHeight > maxHeight || actualWidth > maxWidth) {
|
||||
if (imgRatio < maxRatio) {
|
||||
imgRatio = maxHeight / actualHeight
|
||||
actualWidth = (imgRatio * actualWidth).toInt()
|
||||
actualHeight = maxHeight.toInt()
|
||||
} else if (imgRatio > maxRatio) {
|
||||
imgRatio = maxWidth / actualWidth
|
||||
actualHeight = (imgRatio * actualHeight).toInt()
|
||||
actualWidth = maxWidth.toInt()
|
||||
} else {
|
||||
actualHeight = maxHeight.toInt()
|
||||
actualWidth = maxWidth.toInt()
|
||||
}
|
||||
}
|
||||
|
||||
// setting inSampleSize value allows to load a scaled down version of the original image
|
||||
options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight)
|
||||
|
||||
// inJustDecodeBounds set to false to load the actual bitmap
|
||||
options.inJustDecodeBounds = false
|
||||
|
||||
// this options allow android to claim the bitmap memory if it runs low on memory
|
||||
options.inPurgeable = true
|
||||
options.inInputShareable = true
|
||||
options.inTempStorage = ByteArray(16 * 1024)
|
||||
try {
|
||||
bmp = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size, options)
|
||||
} catch (exception: OutOfMemoryError) {
|
||||
Log.e(ImageUtil::class.java.name, exception.toString())
|
||||
}
|
||||
try {
|
||||
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888)
|
||||
} catch (exception: OutOfMemoryError) {
|
||||
Log.e(ImageUtil::class.java.name, exception.toString())
|
||||
}
|
||||
val ratioX = actualWidth / options.outWidth.toFloat()
|
||||
val ratioY = actualHeight / options.outHeight.toFloat()
|
||||
val middleX = actualWidth / 2.0f
|
||||
val middleY = actualHeight / 2.0f
|
||||
val scaleMatrix = Matrix()
|
||||
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY)
|
||||
val canvas = Canvas(scaledBitmap!!)
|
||||
canvas.setMatrix(scaleMatrix)
|
||||
canvas.drawBitmap(
|
||||
bmp,
|
||||
middleX - bmp.width / 2,
|
||||
middleY - bmp.height / 2,
|
||||
Paint(Paint.FILTER_BITMAP_FLAG),
|
||||
)
|
||||
scaledBitmap = Bitmap.createBitmap(
|
||||
scaledBitmap,
|
||||
0,
|
||||
0,
|
||||
scaledBitmap.width,
|
||||
scaledBitmap.height,
|
||||
null,
|
||||
true,
|
||||
)
|
||||
return scaledBitmap
|
||||
}
|
||||
|
||||
private fun calculateInSampleSize(
|
||||
options: BitmapFactory.Options,
|
||||
reqWidth: Int,
|
||||
reqHeight: Int,
|
||||
): Int {
|
||||
val height = options.outHeight
|
||||
val width = options.outWidth
|
||||
var inSampleSize = 1
|
||||
if (height > reqHeight || width > reqWidth) {
|
||||
val heightRatio = Math.round(height.toFloat() / reqHeight.toFloat())
|
||||
val widthRatio = Math.round(width.toFloat() / reqWidth.toFloat())
|
||||
inSampleSize = if (heightRatio < widthRatio) heightRatio else widthRatio
|
||||
}
|
||||
val totalPixels = width * height.toFloat()
|
||||
val totalReqPixelsCap = reqWidth * reqHeight * 2.toFloat()
|
||||
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
|
||||
inSampleSize++
|
||||
}
|
||||
return inSampleSize
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Reference : https://developer.android.com/topic/performance/graphics/load-bitmap.html
|
||||
* And for scaling :
|
||||
* https://stackoverflow.com/questions/8722359/scale-rotate-bitmap-using-matrix-in-android/8722592#8722592
|
||||
*/
|
||||
@JvmStatic
|
||||
var instance: ImageUtil? = null
|
||||
get() {
|
||||
if (field == null) {
|
||||
field = ImageUtil()
|
||||
}
|
||||
return field
|
||||
}
|
||||
private set
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import com.google.gson.Gson
|
||||
import io.reactivex.plugins.RxJavaPlugins
|
||||
import org.mifos.mobile.core.model.entity.mifoserror.MifosError
|
||||
import retrofit2.HttpException
|
||||
|
||||
object MFErrorParser {
|
||||
const val LOG_TAG = "MFErrorParser"
|
||||
private val gson = Gson()
|
||||
fun parseError(serverResponse: String?): MifosError {
|
||||
return gson.fromJson(serverResponse, MifosError::class.java)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun errorMessage(throwableError: Throwable?): String? {
|
||||
var errorMessage: String? = ""
|
||||
try {
|
||||
if (throwableError is HttpException) {
|
||||
errorMessage = throwableError.response()?.errorBody()?.string()
|
||||
errorMessage = parseError(errorMessage).errors[0].defaultUserMessage
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
RxJavaPlugins.getErrorHandler()
|
||||
}
|
||||
return errorMessage
|
||||
}
|
||||
}
|
||||
@ -1,205 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.mifos.mobile.R
|
||||
|
||||
/**
|
||||
* This Class is the Material Dialog Builder Class
|
||||
* Created by Rajan Maurya on 03/08/16.
|
||||
*/
|
||||
class MaterialDialog {
|
||||
|
||||
class Builder {
|
||||
|
||||
private var mMaterialDialogBuilder: AlertDialog.Builder? = null
|
||||
private var context: Context? = null
|
||||
|
||||
// This is the Default Builder Initialization with Material Style
|
||||
fun init(context: Context?): Builder {
|
||||
mMaterialDialogBuilder = MaterialAlertDialogBuilder(context!!)
|
||||
this.context = context
|
||||
return this
|
||||
}
|
||||
|
||||
// This method set the custom Material Style
|
||||
fun init(context: Context?, theme: Int): Builder {
|
||||
mMaterialDialogBuilder = AlertDialog.Builder(context!!, theme)
|
||||
this.context = context
|
||||
return this
|
||||
}
|
||||
|
||||
// This method set the String Title
|
||||
fun setTitle(title: String?): Builder {
|
||||
mMaterialDialogBuilder?.setTitle(title)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method set the String Resources to Title
|
||||
fun setTitle(@StringRes title: Int): Builder {
|
||||
mMaterialDialogBuilder?.setTitle(title)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method set the String Message
|
||||
fun setMessage(message: String?): Builder {
|
||||
mMaterialDialogBuilder?.setMessage(message)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method set the String Resources message
|
||||
fun setMessage(@StringRes message: Int): Builder {
|
||||
mMaterialDialogBuilder?.setMessage(message)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method set String Test to the Positive Button and set the Onclick null
|
||||
fun setPositiveButton(positiveText: String?): Builder {
|
||||
mMaterialDialogBuilder?.setPositiveButton(positiveText, null)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method Set the String Resources Text To Positive Button
|
||||
fun setPositiveButton(@StringRes positiveText: Int): Builder {
|
||||
mMaterialDialogBuilder?.setPositiveButton(positiveText, null)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method set the String Text to Positive Button and set the OnClick Event to it
|
||||
fun setPositiveButton(
|
||||
positiveText: String?,
|
||||
listener: DialogInterface.OnClickListener?,
|
||||
): Builder {
|
||||
mMaterialDialogBuilder?.setPositiveButton(positiveText, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
// This method set the String Resources text To Positive button and set the Onclick Event
|
||||
fun setPositiveButton(
|
||||
@StringRes positiveText: Int,
|
||||
listener: DialogInterface.OnClickListener?,
|
||||
): Builder {
|
||||
mMaterialDialogBuilder?.setPositiveButton(positiveText, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method the String Text to Negative Button and Set the onclick event to null
|
||||
fun setNegativeButton(negativeText: String?): Builder {
|
||||
mMaterialDialogBuilder?.setNegativeButton(negativeText, null)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method set the String Resources Text to Negative button
|
||||
// and set the onclick event to null
|
||||
fun setNegativeButton(@StringRes negativeText: Int): Builder {
|
||||
mMaterialDialogBuilder?.setNegativeButton(negativeText, null)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method set String Text to Negative Button and
|
||||
// Set the Onclick event
|
||||
fun setNegativeButton(
|
||||
negativeText: String?,
|
||||
listener: DialogInterface.OnClickListener?,
|
||||
): Builder {
|
||||
mMaterialDialogBuilder?.setNegativeButton(negativeText, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
// This method set String Resources Text to Negative Button and set Onclick Event
|
||||
fun setNegativeButton(
|
||||
@StringRes negativeText: Int,
|
||||
listener: DialogInterface.OnClickListener?,
|
||||
): Builder {
|
||||
mMaterialDialogBuilder?.setNegativeButton(negativeText, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method the String Text to Neutral Button and Set the onclick event to null
|
||||
fun setNeutralButton(neutralText: String?): Builder {
|
||||
mMaterialDialogBuilder?.setNeutralButton(neutralText, null)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method set the String Resources Text to Neutral button
|
||||
// and set the onclick event to null
|
||||
fun setNeutralButton(@StringRes neutralText: Int): Builder {
|
||||
mMaterialDialogBuilder?.setNeutralButton(neutralText, null)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method set String Text to Neutral Button and
|
||||
// Set the Onclick event
|
||||
fun setNeutralButton(
|
||||
neutralText: String?,
|
||||
listener: DialogInterface.OnClickListener?,
|
||||
): Builder {
|
||||
mMaterialDialogBuilder?.setNeutralButton(neutralText, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
// This method set String Resources Text to Neutral Button and set Onclick Event
|
||||
fun setNeutralButton(
|
||||
@StringRes neutralText: Int,
|
||||
listener: DialogInterface.OnClickListener?,
|
||||
): Builder {
|
||||
mMaterialDialogBuilder?.setNeutralButton(neutralText, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
fun setCancelable(cancelable: Boolean?): Builder {
|
||||
mMaterialDialogBuilder?.setCancelable(cancelable!!)
|
||||
return this
|
||||
}
|
||||
|
||||
fun setItems(items: Int, listener: DialogInterface.OnClickListener?): Builder {
|
||||
mMaterialDialogBuilder?.setItems(items, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
fun setItems(items: Array<String>?, listener: DialogInterface.OnClickListener?): Builder {
|
||||
mMaterialDialogBuilder?.setItems(items, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
fun addView(view: View?): Builder {
|
||||
mMaterialDialogBuilder?.setView(view)
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method Create the Final Material Dialog
|
||||
fun createMaterialDialog(): Builder {
|
||||
mMaterialDialogBuilder?.create()
|
||||
return this
|
||||
}
|
||||
|
||||
// This Method Show the Dialog
|
||||
fun show(): Builder {
|
||||
val dialog = mMaterialDialogBuilder?.show()
|
||||
dialog?.getButton(DialogInterface.BUTTON_POSITIVE)?.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
context!!,
|
||||
R.color.accent,
|
||||
),
|
||||
)
|
||||
dialog?.getButton(DialogInterface.BUTTON_NEGATIVE)?.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
context!!,
|
||||
R.color.gray_dark,
|
||||
),
|
||||
)
|
||||
dialog?.getButton(DialogInterface.BUTTON_NEUTRAL)?.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
context!!,
|
||||
R.color.black,
|
||||
),
|
||||
)
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,72 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.mifos.mobile.R
|
||||
import org.mifos.mobile.ui.getThemeAttributeColor
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 30/6/17.
|
||||
*/
|
||||
class ProcessView : View {
|
||||
private var valueStr: String? = null
|
||||
private var textPaint: Paint? = null
|
||||
private var backgroundPaint: Paint? = null
|
||||
|
||||
constructor(context: Context?) : super(context, null)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ProcessView)
|
||||
valueStr = typedArray.getString(R.styleable.ProcessView_value)
|
||||
typedArray.recycle()
|
||||
textPaint = Paint()
|
||||
textPaint?.color = getColorCompat(android.R.color.white)
|
||||
textPaint?.isAntiAlias = true
|
||||
textPaint?.style = Paint.Style.FILL
|
||||
textPaint?.strokeWidth = 1f
|
||||
textPaint?.textSize = 40f
|
||||
backgroundPaint = Paint()
|
||||
backgroundPaint?.color = getColorCompat(R.color.gray_dark)
|
||||
backgroundPaint?.isAntiAlias = true
|
||||
backgroundPaint?.style = Paint.Style.FILL
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
val xPos =
|
||||
canvas.width / 2 - (textPaint?.measureText(valueStr.toString())?.div(2))?.toInt()!!
|
||||
val yPos = (
|
||||
canvas.height / 2 - (
|
||||
(
|
||||
textPaint?.descent()
|
||||
?.plus(textPaint?.ascent()!!)
|
||||
)?.div(2)
|
||||
)!!
|
||||
).toInt()
|
||||
val usableWidth = width - (paddingLeft + paddingRight)
|
||||
val usableHeight = height - (paddingTop + paddingBottom)
|
||||
val radius = usableWidth.coerceAtMost(usableHeight) / 2
|
||||
val cx = paddingLeft + usableWidth / 2
|
||||
val cy = paddingTop + usableHeight / 2
|
||||
canvas.drawCircle(cx.toFloat(), cy.toFloat(), radius.toFloat(), backgroundPaint!!)
|
||||
canvas.drawText(valueStr!!, xPos.toFloat(), yPos.toFloat(), textPaint!!)
|
||||
}
|
||||
|
||||
fun setCurrentActive() {
|
||||
backgroundPaint?.color = context.getThemeAttributeColor(R.attr.colorPrimary)
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun setCurrentCompleted() {
|
||||
backgroundPaint?.color = context.getThemeAttributeColor(R.attr.colorPrimary)
|
||||
valueStr = "\u2713"
|
||||
invalidate()
|
||||
}
|
||||
|
||||
private fun getColorCompat(colorId: Int): Int {
|
||||
return ContextCompat.getColor(context, colorId)
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.Protocol
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.HttpException
|
||||
import retrofit2.Response
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 29/7/17.
|
||||
*/
|
||||
object RetrofitUtils {
|
||||
fun getResponseForError(errorCode: Int): Exception {
|
||||
val message = if (errorCode == 401) "UnAuthorized" else "Not Found"
|
||||
val responseBody =
|
||||
ResponseBody.create(MediaType.parse("application/json"), "{\"message\":\"$message\"}")
|
||||
val response = okhttp3.Response.Builder().code(errorCode)
|
||||
.message(message)
|
||||
.protocol(Protocol.HTTP_1_1)
|
||||
.request(okhttp3.Request.Builder().url("http://localhost/").build())
|
||||
.build()
|
||||
return HttpException(Response.error<Any>(responseBody, response))
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
|
||||
/*
|
||||
* Created by saksham on 31/July/2018
|
||||
*/
|
||||
|
||||
object RxBus {
|
||||
|
||||
@JvmStatic
|
||||
private val publisher = PublishSubject.create<Any>()
|
||||
|
||||
@JvmStatic
|
||||
fun publish(event: Any?) {
|
||||
if (event != null) publisher.onNext(event)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun <T> listen(eventType: Class<T>): Observable<T> {
|
||||
return publisher.ofType(eventType)
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import org.mifos.mobile.core.model.entity.guarantor.GuarantorApplicationPayload
|
||||
|
||||
/*
|
||||
* Created by saksham on 29/July/2018
|
||||
*/
|
||||
|
||||
class RxEvent {
|
||||
|
||||
data class AddGuarantorEvent(var payload: GuarantorApplicationPayload?, var index: Int?)
|
||||
|
||||
data class DeleteGuarantorEvent(var index: Int?)
|
||||
|
||||
data class UpdateGuarantorEvent(var payload: GuarantorApplicationPayload?, var index: Int?)
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations
|
||||
import org.mifos.mobile.core.model.entity.accounts.savings.Transactions
|
||||
import org.mifos.mobile.core.model.entity.templates.account.AccountOptionsTemplate
|
||||
import org.mifos.mobile.core.model.entity.templates.savings.SavingsAccountTemplate
|
||||
|
||||
sealed class SavingsAccountUiState {
|
||||
object Initial : SavingsAccountUiState()
|
||||
object Loading : SavingsAccountUiState()
|
||||
object Error : SavingsAccountUiState()
|
||||
data class SuccessLoadingSavingsWithAssociations(val savingAccount: SavingsWithAssociations) :
|
||||
SavingsAccountUiState()
|
||||
|
||||
data class ShowFilteredTransactionsList(val savingAccountsTransactionList: List<Transactions?>?) :
|
||||
SavingsAccountUiState()
|
||||
|
||||
object SavingsAccountUpdateSuccess : SavingsAccountUiState()
|
||||
object SavingsAccountApplicationSuccess : SavingsAccountUiState()
|
||||
data class ShowUserInterfaceSavingAccountUpdate(val template: SavingsAccountTemplate) :
|
||||
SavingsAccountUiState()
|
||||
|
||||
data class ShowUserInterfaceSavingAccountApplication(val template: SavingsAccountTemplate) :
|
||||
SavingsAccountUiState()
|
||||
|
||||
data class ErrorMessage(val error: Throwable) : SavingsAccountUiState()
|
||||
object HideProgress : SavingsAccountUiState()
|
||||
object SavingsAccountWithdrawSuccess : SavingsAccountUiState()
|
||||
|
||||
data class ShowSavingsAccountTemplate(val accountOptionsTemplate: AccountOptionsTemplate) : SavingsAccountUiState()
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.view.ViewCompat
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton.OnVisibilityChangedListener
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 23/8/17.
|
||||
*/
|
||||
class ScrollFabBehavior(context: Context?, attrs: AttributeSet?) : FloatingActionButton.Behavior() {
|
||||
override fun onStartNestedScroll(
|
||||
coordinatorLayout: CoordinatorLayout,
|
||||
child: FloatingActionButton,
|
||||
directTargetChild: View,
|
||||
target: View,
|
||||
nestedScrollAxes: Int,
|
||||
): Boolean {
|
||||
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL ||
|
||||
super.onStartNestedScroll(
|
||||
coordinatorLayout,
|
||||
child,
|
||||
directTargetChild,
|
||||
target,
|
||||
nestedScrollAxes,
|
||||
)
|
||||
}
|
||||
|
||||
override fun onNestedScroll(
|
||||
coordinatorLayout: CoordinatorLayout,
|
||||
child: FloatingActionButton,
|
||||
target: View,
|
||||
dxConsumed: Int,
|
||||
dyConsumed: Int,
|
||||
dxUnconsumed: Int,
|
||||
dyUnconsumed: Int,
|
||||
) {
|
||||
super.onNestedScroll(
|
||||
coordinatorLayout,
|
||||
child,
|
||||
target,
|
||||
dxConsumed,
|
||||
dyConsumed,
|
||||
dxUnconsumed,
|
||||
dyUnconsumed,
|
||||
)
|
||||
if (dyConsumed > 0 && child.visibility == View.VISIBLE) {
|
||||
// Reason to set fab visiblity as INVISIBLE :
|
||||
// https://stackoverflow.com/a/41386278/4672688
|
||||
child.hide(object : OnVisibilityChangedListener() {
|
||||
override fun onHidden(fab: FloatingActionButton) {
|
||||
super.onHidden(fab)
|
||||
fab.visibility = View.INVISIBLE
|
||||
}
|
||||
})
|
||||
} else if (dyConsumed < 0 && child.visibility != View.VISIBLE) {
|
||||
child.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.mifos.mobile.R
|
||||
import org.mifos.mobile.core.model.entity.CheckboxStatus
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 3/7/17.
|
||||
*/
|
||||
object StatusUtils {
|
||||
|
||||
fun getSavingsAccountTransactionList(context: Context?): List<CheckboxStatus> {
|
||||
val arrayList = ArrayList<CheckboxStatus>()
|
||||
arrayList.add(
|
||||
CheckboxStatus(
|
||||
context?.getString(R.string.feature_account_deposit),
|
||||
ContextCompat
|
||||
.getColor(context!!, R.color.deposit_green),
|
||||
),
|
||||
)
|
||||
arrayList.add(
|
||||
CheckboxStatus(
|
||||
context.getString(R.string.feature_account_dividend_payout),
|
||||
ContextCompat
|
||||
.getColor(context, R.color.red_light),
|
||||
),
|
||||
)
|
||||
arrayList.add(
|
||||
CheckboxStatus(
|
||||
context.getString(R.string.feature_account_withdrawal),
|
||||
ContextCompat
|
||||
.getColor(context, R.color.red_light),
|
||||
),
|
||||
)
|
||||
arrayList.add(
|
||||
CheckboxStatus(
|
||||
context.getString(R.string.feature_account_interest_posting),
|
||||
ContextCompat.getColor(context, R.color.green_light),
|
||||
),
|
||||
)
|
||||
arrayList.add(
|
||||
CheckboxStatus(
|
||||
context.getString(R.string.feature_account_fee_deduction),
|
||||
ContextCompat
|
||||
.getColor(context, R.color.red_light),
|
||||
),
|
||||
)
|
||||
arrayList.add(
|
||||
CheckboxStatus(
|
||||
context.getString(R.string.feature_account_withdrawal_transfer),
|
||||
ContextCompat.getColor(context, R.color.red_light),
|
||||
),
|
||||
)
|
||||
arrayList.add(
|
||||
CheckboxStatus(
|
||||
context.getString(R.string.feature_account_rejected_transfer),
|
||||
ContextCompat.getColor(context, R.color.green_light),
|
||||
),
|
||||
)
|
||||
arrayList.add(
|
||||
CheckboxStatus(
|
||||
context.getString(R.string.feature_account_overdraft_fee),
|
||||
ContextCompat
|
||||
.getColor(context, R.color.red_light),
|
||||
),
|
||||
)
|
||||
return arrayList
|
||||
}
|
||||
}
|
||||
@ -1,281 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.RectF
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.ShapeDrawable
|
||||
import android.graphics.drawable.shapes.OvalShape
|
||||
import android.graphics.drawable.shapes.RectShape
|
||||
import android.graphics.drawable.shapes.RoundRectShape
|
||||
import java.util.Locale
|
||||
|
||||
class TextDrawable private constructor(builder: Builder) : ShapeDrawable(builder.shape) {
|
||||
private val textPaint: Paint
|
||||
private val borderPaint: Paint
|
||||
private val text: String
|
||||
private val color: Int
|
||||
private val shape: RectShape
|
||||
private val height: Int
|
||||
private val width: Int
|
||||
private val fontSize: Int
|
||||
private val radius: Float
|
||||
private val borderThickness: Int
|
||||
private fun getDarkerShade(color: Int): Int {
|
||||
return Color.rgb(
|
||||
(SHADE_FACTOR * Color.red(color)).toInt(),
|
||||
(SHADE_FACTOR * Color.green(color)).toInt(),
|
||||
(SHADE_FACTOR * Color.blue(color)).toInt(),
|
||||
)
|
||||
}
|
||||
|
||||
override fun draw(canvas: Canvas) {
|
||||
super.draw(canvas)
|
||||
val r = bounds
|
||||
|
||||
// draw border
|
||||
if (borderThickness > 0) {
|
||||
drawBorder(canvas)
|
||||
}
|
||||
val count = canvas.save()
|
||||
canvas.translate(r.left.toFloat(), r.top.toFloat())
|
||||
|
||||
// draw text
|
||||
val width = if (width < 0) r.width() else width
|
||||
val height = if (height < 0) r.height() else height
|
||||
val fontSize = if (fontSize < 0) Math.min(width, height) / 2 else fontSize
|
||||
textPaint.textSize = fontSize.toFloat()
|
||||
canvas.drawText(
|
||||
text,
|
||||
width / 2.toFloat(),
|
||||
height / 2 - (textPaint.descent() + textPaint.ascent()) / 2,
|
||||
textPaint,
|
||||
)
|
||||
canvas.restoreToCount(count)
|
||||
}
|
||||
|
||||
private fun drawBorder(canvas: Canvas) {
|
||||
val rect = RectF(bounds)
|
||||
rect.inset(borderThickness / 2.toFloat(), borderThickness / 2.toFloat())
|
||||
if (shape is OvalShape) {
|
||||
canvas.drawOval(rect, borderPaint)
|
||||
} else if (shape is RoundRectShape) {
|
||||
canvas.drawRoundRect(rect, radius, radius, borderPaint)
|
||||
} else {
|
||||
canvas.drawRect(rect, borderPaint)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setAlpha(alpha: Int) {
|
||||
textPaint.alpha = alpha
|
||||
}
|
||||
|
||||
override fun setColorFilter(cf: ColorFilter?) {
|
||||
textPaint.colorFilter = cf
|
||||
}
|
||||
|
||||
override fun getOpacity(): Int {
|
||||
return PixelFormat.TRANSLUCENT
|
||||
}
|
||||
|
||||
override fun getIntrinsicWidth(): Int {
|
||||
return width
|
||||
}
|
||||
|
||||
override fun getIntrinsicHeight(): Int {
|
||||
return height
|
||||
}
|
||||
|
||||
class Builder : IConfigBuilder, IShapeBuilder, IBuilder {
|
||||
var text = ""
|
||||
var color: Int
|
||||
var borderThickness: Int
|
||||
var iconWidth: Int
|
||||
var iconHeight: Int
|
||||
var font: Typeface
|
||||
var shape: RectShape
|
||||
var iconTextColor: Int
|
||||
var iconFontSize: Int
|
||||
var isBold: Boolean
|
||||
var iconToUpperCase: Boolean
|
||||
var radius = 0f
|
||||
override fun width(width: Int): IConfigBuilder {
|
||||
iconWidth = width
|
||||
return this
|
||||
}
|
||||
|
||||
override fun height(height: Int): IConfigBuilder {
|
||||
iconHeight = height
|
||||
return this
|
||||
}
|
||||
|
||||
override fun textColor(color: Int): IConfigBuilder {
|
||||
iconTextColor = color
|
||||
return this
|
||||
}
|
||||
|
||||
override fun withBorder(thickness: Int): IConfigBuilder {
|
||||
borderThickness = thickness
|
||||
return this
|
||||
}
|
||||
|
||||
override fun useFont(font: Typeface): IConfigBuilder {
|
||||
this.font = font
|
||||
return this
|
||||
}
|
||||
|
||||
override fun fontSize(size: Int): IConfigBuilder {
|
||||
iconFontSize = size
|
||||
return this
|
||||
}
|
||||
|
||||
override fun bold(): IConfigBuilder {
|
||||
isBold = true
|
||||
return this
|
||||
}
|
||||
|
||||
override fun toUpperCase(): IConfigBuilder {
|
||||
iconToUpperCase = true
|
||||
return this
|
||||
}
|
||||
|
||||
override fun beginConfig(): IConfigBuilder {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun endConfig(): IShapeBuilder {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun rect(): IBuilder {
|
||||
shape = RectShape()
|
||||
return this
|
||||
}
|
||||
|
||||
override fun round(): IBuilder {
|
||||
shape = OvalShape()
|
||||
return this
|
||||
}
|
||||
|
||||
override fun roundRect(radius: Int): IBuilder {
|
||||
this.radius = radius.toFloat()
|
||||
val radii = floatArrayOf(
|
||||
radius.toFloat(),
|
||||
radius.toFloat(),
|
||||
radius.toFloat(),
|
||||
radius.toFloat(),
|
||||
radius.toFloat(),
|
||||
radius.toFloat(),
|
||||
radius.toFloat(),
|
||||
radius.toFloat(),
|
||||
)
|
||||
shape = RoundRectShape(radii, null, null)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun buildRect(text: String, color: Int): TextDrawable {
|
||||
rect()
|
||||
return build(text, color)
|
||||
}
|
||||
|
||||
override fun buildRoundRect(text: String, color: Int, radius: Int): TextDrawable {
|
||||
roundRect(radius)
|
||||
return build(text, color)
|
||||
}
|
||||
|
||||
override fun buildRound(text: String?, color: Int): TextDrawable {
|
||||
round()
|
||||
return build(text!!, color)
|
||||
}
|
||||
|
||||
override fun build(text: String, color: Int): TextDrawable {
|
||||
this.color = color
|
||||
this.text = text
|
||||
return TextDrawable(this)
|
||||
}
|
||||
|
||||
init {
|
||||
color = Color.GRAY
|
||||
iconTextColor = Color.WHITE
|
||||
borderThickness = 0
|
||||
iconWidth = -1
|
||||
iconHeight = -1
|
||||
shape = RectShape()
|
||||
font = Typeface.create("sans-serif-light", Typeface.NORMAL)
|
||||
iconFontSize = -1
|
||||
isBold = false
|
||||
iconToUpperCase = false
|
||||
}
|
||||
}
|
||||
|
||||
interface IConfigBuilder {
|
||||
fun width(width: Int): IConfigBuilder
|
||||
fun height(height: Int): IConfigBuilder
|
||||
fun textColor(color: Int): IConfigBuilder
|
||||
fun withBorder(thickness: Int): IConfigBuilder
|
||||
fun useFont(font: Typeface): IConfigBuilder
|
||||
fun fontSize(size: Int): IConfigBuilder
|
||||
fun bold(): IConfigBuilder
|
||||
fun toUpperCase(): IConfigBuilder
|
||||
fun endConfig(): IShapeBuilder
|
||||
}
|
||||
|
||||
interface IBuilder {
|
||||
fun build(text: String, color: Int): TextDrawable
|
||||
}
|
||||
|
||||
interface IShapeBuilder {
|
||||
fun beginConfig(): IConfigBuilder
|
||||
fun rect(): IBuilder
|
||||
fun round(): IBuilder
|
||||
fun roundRect(radius: Int): IBuilder
|
||||
fun buildRect(text: String, color: Int): TextDrawable
|
||||
fun buildRoundRect(text: String, color: Int, radius: Int): TextDrawable
|
||||
fun buildRound(text: String?, color: Int): TextDrawable
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SHADE_FACTOR = 0.9f
|
||||
fun builder(): IShapeBuilder {
|
||||
return Builder()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
|
||||
// shape properties
|
||||
shape = builder.shape
|
||||
height = builder.iconHeight
|
||||
width = builder.iconWidth
|
||||
radius = builder.radius
|
||||
|
||||
// text and color
|
||||
text = if (builder.iconToUpperCase) builder.text.uppercase(Locale.ROOT) else builder.text
|
||||
color = builder.color
|
||||
|
||||
// text paint settings
|
||||
fontSize = builder.iconFontSize
|
||||
textPaint = Paint()
|
||||
textPaint.color = builder.iconTextColor
|
||||
textPaint.isAntiAlias = true
|
||||
textPaint.isFakeBoldText = builder.isBold
|
||||
textPaint.style = Paint.Style.FILL
|
||||
textPaint.typeface = builder.font
|
||||
textPaint.textAlign = Paint.Align.CENTER
|
||||
textPaint.strokeWidth = builder.borderThickness.toFloat()
|
||||
|
||||
// border paint settings
|
||||
borderThickness = builder.borderThickness
|
||||
borderPaint = Paint()
|
||||
borderPaint.color = getDarkerShade(color)
|
||||
borderPaint.style = Paint.Style.STROKE
|
||||
borderPaint.strokeWidth = borderThickness.toFloat()
|
||||
|
||||
// drawable paint color
|
||||
val paint = paint
|
||||
paint.color = color
|
||||
}
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
package org.mifos.mobile.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.mifos.mobile.MifosSelfServiceApp
|
||||
|
||||
object Toaster {
|
||||
|
||||
private val snackbarsQueue = ArrayList<Snackbar>()
|
||||
|
||||
@JvmOverloads
|
||||
fun show(view: View?, text: String?, duration: Int = Snackbar.LENGTH_LONG) {
|
||||
val imm =
|
||||
MifosSelfServiceApp.context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(view?.windowToken, 0)
|
||||
val snackbar = Snackbar.make(view!!, text!!, duration)
|
||||
snackbar.setAction("OK") { }
|
||||
snackbar.addCallback(object : Snackbar.Callback() {
|
||||
|
||||
override fun onDismissed(transientBottomBar: Snackbar, event: Int) {
|
||||
super.onDismissed(transientBottomBar, event)
|
||||
if (snackbarsQueue.isNotEmpty()) {
|
||||
snackbarsQueue.removeAt(0)
|
||||
if (snackbarsQueue.isNotEmpty()) {
|
||||
snackbarsQueue[0].show()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
snackbarsQueue.add(snackbar)
|
||||
if (!snackbarsQueue[0].isShown) {
|
||||
snackbarsQueue[0].show()
|
||||
}
|
||||
}
|
||||
|
||||
fun show(view: View, res: Int, duration: Int) {
|
||||
show(view, MifosSelfServiceApp.context?.resources?.getString(res), duration)
|
||||
}
|
||||
|
||||
fun cancelTransfer(
|
||||
view: View?,
|
||||
text: String?,
|
||||
buttonText: String?,
|
||||
listener: View.OnClickListener?,
|
||||
) {
|
||||
val snackbar = Snackbar.make(view!!, text!!, Snackbar.LENGTH_LONG)
|
||||
snackbar.setAction(buttonText, listener)
|
||||
snackbar.show()
|
||||
}
|
||||
|
||||
fun show(view: View?, res: Int) {
|
||||
show(view, MifosSelfServiceApp.context?.resources?.getString(res))
|
||||
}
|
||||
}
|
||||
@ -1,94 +0,0 @@
|
||||
/**
|
||||
* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mifos.mobile.utils.fcm
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.RingtoneManager
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
import org.mifos.mobile.R
|
||||
import org.mifos.mobile.ui.activities.HomeActivity
|
||||
|
||||
class MifosFirebaseMessagingService : FirebaseMessagingService() {
|
||||
// [START receive_message]
|
||||
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
||||
val from = remoteMessage.from
|
||||
val data = remoteMessage.data
|
||||
val message = data[getString(R.string.message)]
|
||||
if ((from?.startsWith("/topics/") == true)) {
|
||||
// message received from some topic.
|
||||
} else {
|
||||
// normal downstream message.
|
||||
}
|
||||
sendNotification(message)
|
||||
val registrationComplete = Intent(org.mifos.mobile.core.common.Constants.NOTIFY_HOME_FRAGMENT)
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete)
|
||||
}
|
||||
// [END receive_message]
|
||||
/**
|
||||
* Create and show a simple notification containing the received FCM message.
|
||||
*
|
||||
* @param message FCM message received.
|
||||
*/
|
||||
private fun sendNotification(message: String?) {
|
||||
val intent = Intent(this, HomeActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
intent.putExtra(getString(R.string.notification), true)
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
this,
|
||||
0 /* Request code */,
|
||||
intent,
|
||||
PendingIntent.FLAG_ONE_SHOT,
|
||||
)
|
||||
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
||||
val notificationBuilder = NotificationCompat.Builder(this)
|
||||
.setSmallIcon(R.mipmap.core_common_mifos_icon)
|
||||
.setContentTitle(getString(R.string.feature_about_app_name))
|
||||
.setContentText(message)
|
||||
.setAutoCancel(true)
|
||||
.setSound(defaultSoundUri)
|
||||
.setContentIntent(pendingIntent)
|
||||
val notificationManager =
|
||||
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
val notification = org.mifos.mobile.core.datastore.model.MifosNotification()
|
||||
notification.msg = message
|
||||
notification.timeStamp = System.currentTimeMillis()
|
||||
notification.setRead(false)
|
||||
notificationManager.notify(0, notificationBuilder.build())
|
||||
}
|
||||
|
||||
/**
|
||||
* Called if InstanceID token is updated. This may occur if the security of
|
||||
* the previous token had been compromised. Note that this is called when the InstanceID token
|
||||
* is initially generated so this is where you would retrieve the token.
|
||||
*/
|
||||
override fun onNewToken(s: String) {
|
||||
super.onNewToken(s)
|
||||
Log.d(TAG, "Refreshed token: $s")
|
||||
val intent = Intent(this, RegistrationIntentService::class.java)
|
||||
startService(intent)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = MifosFirebaseMessagingService::class.java.simpleName
|
||||
}
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mifos.mobile.utils.fcm
|
||||
|
||||
import android.app.IntentService
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.google.android.gms.tasks.OnCompleteListener
|
||||
import com.google.firebase.messaging.FirebaseMessaging
|
||||
|
||||
class RegistrationIntentService : IntentService(TAG) {
|
||||
override fun onHandleIntent(intent: Intent?) {
|
||||
FirebaseMessaging.getInstance().token
|
||||
.addOnCompleteListener(
|
||||
OnCompleteListener { task ->
|
||||
if (!task.isSuccessful) {
|
||||
Log.w(TAG, "getInstanceId failed", task.exception)
|
||||
return@OnCompleteListener
|
||||
}
|
||||
|
||||
// Get new Instance ID token
|
||||
val token = task.result
|
||||
sendRegistrationToServer(token)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendRegistrationToServer(token: String?) {
|
||||
val registrationComplete = Intent(org.mifos.mobile.core.common.Constants.REGISTER_ON_SERVER)
|
||||
registrationComplete.putExtra(org.mifos.mobile.core.common.Constants.TOKEN, token)
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "RegIntentService"
|
||||
}
|
||||
}
|
||||
105
androidApp/src/main/kotlin/org/mifos/mobile/HomeActivity.kt
Normal file
105
androidApp/src/main/kotlin/org/mifos/mobile/HomeActivity.kt
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.mifos.mobile.HomeActivityUiState.Success
|
||||
import org.mifos.mobile.core.data.utils.NetworkMonitor
|
||||
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
|
||||
import org.mifos.mobile.navigation.MifosNavGraph.AUTH_GRAPH
|
||||
import org.mifos.mobile.navigation.MifosNavGraph.PASSCODE_GRAPH
|
||||
import org.mifos.mobile.navigation.RootNavGraph
|
||||
import org.mifos.mobile.ui.rememberMifosMobileState
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class HomeActivity : ComponentActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var networkMonitor: NetworkMonitor
|
||||
|
||||
private val viewModel: HomeActivityViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
val splashScreen = installSplashScreen()
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
var uiState: HomeActivityUiState by mutableStateOf(HomeActivityUiState.Loading)
|
||||
|
||||
// Update the uiState
|
||||
lifecycleScope.launch {
|
||||
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewModel.uiState
|
||||
.onEach { uiState = it }
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
splashScreen.setKeepOnScreenCondition {
|
||||
when (uiState) {
|
||||
HomeActivityUiState.Loading -> true
|
||||
is Success -> false
|
||||
}
|
||||
}
|
||||
|
||||
enableEdgeToEdge()
|
||||
|
||||
setContent {
|
||||
val navController = rememberNavController()
|
||||
|
||||
val appState = rememberMifosMobileState(networkMonitor = networkMonitor)
|
||||
|
||||
val navDestination = when (uiState) {
|
||||
is Success -> if ((uiState as Success).userData.isAuthenticated) {
|
||||
PASSCODE_GRAPH
|
||||
} else {
|
||||
AUTH_GRAPH
|
||||
}
|
||||
|
||||
else -> AUTH_GRAPH
|
||||
}
|
||||
|
||||
CompositionLocalProvider {
|
||||
MifosMobileTheme {
|
||||
RootNavGraph(
|
||||
appState = appState,
|
||||
navHostController = navController,
|
||||
startDestination = navDestination,
|
||||
onClickLogout = {
|
||||
viewModel.logOut()
|
||||
navController.navigate(AUTH_GRAPH) {
|
||||
popUpTo(navController.graph.id) {
|
||||
inclusive = true
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.mifos.library.passcode.data.PasscodeManager
|
||||
import org.mifos.mobile.core.data.repository.UserDataRepository
|
||||
import org.mifos.mobile.core.model.UserData
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class HomeActivityViewModel @Inject constructor(
|
||||
private val userDataRepository: UserDataRepository,
|
||||
private val passcodeManager: PasscodeManager,
|
||||
) : ViewModel() {
|
||||
|
||||
val uiState: StateFlow<HomeActivityUiState> = userDataRepository.userData.map {
|
||||
HomeActivityUiState.Success(it)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
initialValue = HomeActivityUiState.Loading,
|
||||
started = SharingStarted.WhileSubscribed(5_000),
|
||||
)
|
||||
|
||||
fun logOut() {
|
||||
viewModelScope.launch {
|
||||
userDataRepository.logOut()
|
||||
passcodeManager.clearPasscode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface HomeActivityUiState {
|
||||
data object Loading : HomeActivityUiState
|
||||
data class Success(val userData: UserData) : HomeActivityUiState
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile
|
||||
|
||||
import androidx.multidex.MultiDex
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
import org.mifos.mobile.feature.settings.applySavedTheme
|
||||
|
||||
@HiltAndroidApp
|
||||
class MifosSelfServiceApp : MultiDexApplication() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
MultiDex.install(this)
|
||||
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true)
|
||||
PreferencesHelper(this).applySavedTheme()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.navigation
|
||||
|
||||
internal object MifosNavGraph {
|
||||
const val ROOT_GRAPH = "root_graph"
|
||||
const val AUTH_GRAPH = "auth_graph"
|
||||
const val PASSCODE_GRAPH = "passcode_graph"
|
||||
const val MAIN_GRAPH = "main_graph"
|
||||
}
|
||||
@ -1,3 +1,12 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.navigation
|
||||
|
||||
import android.app.Activity
|
||||
@ -7,16 +16,14 @@ import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
|
||||
import com.mifos.compose.component.PasscodeScreen
|
||||
import org.mifos.mobile.HomeActivity
|
||||
import org.mifos.mobile.R
|
||||
import org.mifos.mobile.core.common.Constants.INTIAL_LOGIN
|
||||
import org.mifos.mobile.core.common.Constants.TRANSFER_PAY_TO
|
||||
import org.mifos.mobile.core.model.enums.AccountType
|
||||
import org.mifos.mobile.core.model.enums.ChargeType
|
||||
@ -24,7 +31,6 @@ import org.mifos.mobile.feature.about.navigation.aboutUsNavGraph
|
||||
import org.mifos.mobile.feature.about.navigation.navigateToAboutUsScreen
|
||||
import org.mifos.mobile.feature.account.navigation.clientAccountsNavGraph
|
||||
import org.mifos.mobile.feature.account.navigation.navigateToClientAccountsScreen
|
||||
import org.mifos.mobile.feature.auth.navigation.authenticationNavGraph
|
||||
import org.mifos.mobile.feature.auth.navigation.navigateToLoginScreen
|
||||
import org.mifos.mobile.feature.beneficiary.navigation.beneficiaryNavGraph
|
||||
import org.mifos.mobile.feature.beneficiary.navigation.navigateToAddBeneficiaryScreen
|
||||
@ -37,8 +43,8 @@ import org.mifos.mobile.feature.guarantor.navigation.navigateToGuarantorScreen
|
||||
import org.mifos.mobile.feature.help.navigation.helpNavGraph
|
||||
import org.mifos.mobile.feature.help.navigation.navigateToHelpScreen
|
||||
import org.mifos.mobile.feature.home.navigation.HomeDestinations
|
||||
import org.mifos.mobile.feature.home.navigation.HomeNavigation
|
||||
import org.mifos.mobile.feature.home.navigation.homeNavGraph
|
||||
import org.mifos.mobile.feature.home.navigation.navigateToHomeScreen
|
||||
import org.mifos.mobile.feature.loan.navigation.loanNavGraph
|
||||
import org.mifos.mobile.feature.loan.navigation.navigateToLoanApplication
|
||||
import org.mifos.mobile.feature.loan.navigation.navigateToLoanDetailScreen
|
||||
@ -62,51 +68,44 @@ import org.mifos.mobile.feature.transaction.navigation.navigateToRecentTransacti
|
||||
import org.mifos.mobile.feature.transaction.navigation.recentTransactionNavGraph
|
||||
import org.mifos.mobile.feature.transfer.process.navigation.navigateToTransferProcessScreen
|
||||
import org.mifos.mobile.feature.transfer.process.navigation.transferProcessNavGraph
|
||||
import org.mifos.mobile.feature.update_password.navigation.navigateToUpdatePassword
|
||||
import org.mifos.mobile.feature.update_password.navigation.updatePasswordNavGraph
|
||||
import org.mifos.mobile.feature.update.password.navigation.navigateToUpdatePassword
|
||||
import org.mifos.mobile.feature.update.password.navigation.updatePasswordNavGraph
|
||||
import org.mifos.mobile.feature.user.profile.navigation.navigateToUserProfile
|
||||
import org.mifos.mobile.feature.user.profile.navigation.userProfileNavGraph
|
||||
import org.mifos.mobile.ui.activities.HomeActivity
|
||||
import org.mifos.mobile.ui.activities.PassCodeActivity
|
||||
|
||||
|
||||
@Composable
|
||||
fun RootNavGraph(
|
||||
startDestination: String,
|
||||
navController: NavHostController,
|
||||
fun MifosNavHost(
|
||||
onClickLogout: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val navController = rememberNavController()
|
||||
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = startDestination,
|
||||
route = MifosNavGraph.MAIN_GRAPH,
|
||||
startDestination = HomeNavigation.HomeBase.route,
|
||||
modifier = modifier,
|
||||
) {
|
||||
homeNavGraph(
|
||||
onNavigate = { handleHomeNavigation(navController, it, context) },
|
||||
onNavigate = { handleHomeNavigation(navController, it, onClickLogout, context) },
|
||||
callHelpline = { callHelpline(context) },
|
||||
mailHelpline = { mailHelpline(context) }
|
||||
mailHelpline = { mailHelpline(context) },
|
||||
)
|
||||
|
||||
authenticationNavGraph(
|
||||
navController = navController,
|
||||
navigateToPasscodeScreen = { startPassCodeActivity(context = context) }
|
||||
)
|
||||
|
||||
guarantorNavGraph(
|
||||
navController = navController,
|
||||
)
|
||||
guarantorNavGraph(navController = navController)
|
||||
|
||||
loanNavGraph(
|
||||
navController = navController,
|
||||
viewQr = navController::navigateToQrDisplayScreen,
|
||||
viewGuarantor = navController::navigateToGuarantorScreen,
|
||||
viewCharges = navController::navigateToClientChargeScreen,
|
||||
makePayment = navController::navigateToSavingsMakeTransfer
|
||||
makePayment = navController::navigateToSavingsMakeTransfer,
|
||||
)
|
||||
|
||||
userProfileNavGraph(
|
||||
navigateBack = navController::popBackStack,
|
||||
navigateToChangePassword = navController::navigateToUpdatePassword
|
||||
navigateToChangePassword = navController::navigateToUpdatePassword,
|
||||
)
|
||||
|
||||
updatePasswordNavGraph(navigateBack = navController::popBackStack)
|
||||
@ -114,24 +113,20 @@ fun RootNavGraph(
|
||||
thirdPartyTransferNavGraph(
|
||||
navigateBack = navController::popBackStack,
|
||||
addBeneficiary = navController::navigateToAddBeneficiaryScreen,
|
||||
reviewTransfer = navController::navigateToTransferProcessScreen
|
||||
reviewTransfer = navController::navigateToTransferProcessScreen,
|
||||
)
|
||||
|
||||
settingsNavGraph(
|
||||
navigateBack = navController::popBackStack,
|
||||
changePassword = navController::navigateToUpdatePassword,
|
||||
changePasscode = {}, // { navigateToUpdatePasscodeActivity(it, context) },
|
||||
changePasscode = {},
|
||||
navigateToLoginScreen = navController::navigateToLoginScreen,
|
||||
languageChanged = { startActivity(context, HomeActivity::class.java) }
|
||||
languageChanged = { startActivity(context, HomeActivity::class.java) },
|
||||
)
|
||||
|
||||
recentTransactionNavGraph(
|
||||
navigateBack = navController::popBackStack
|
||||
)
|
||||
recentTransactionNavGraph(navigateBack = navController::popBackStack)
|
||||
|
||||
notificationNavGraph(
|
||||
navigateBack = navController::popBackStack
|
||||
)
|
||||
notificationNavGraph(navigateBack = navController::popBackStack)
|
||||
|
||||
locationsNavGraph()
|
||||
|
||||
@ -139,16 +134,16 @@ fun RootNavGraph(
|
||||
findLocations = navController::navigateToLocationsScreen,
|
||||
navigateBack = navController::popBackStack,
|
||||
callHelpline = { callHelpline(context) },
|
||||
mailHelpline = { mailHelpline(context) }
|
||||
mailHelpline = { mailHelpline(context) },
|
||||
)
|
||||
|
||||
clientChargeNavGraph(
|
||||
navigateBack = navController::popBackStack
|
||||
)
|
||||
clientChargeNavGraph(navigateBack = navController::popBackStack)
|
||||
|
||||
aboutUsNavGraph(
|
||||
navController = navController,
|
||||
navigateToOssLicense = { startActivity(context, OssLicensesMenuActivity::class.java) }
|
||||
navigateToOssLicense = {
|
||||
context.startActivity(Intent(context, OssLicensesMenuActivity::class.java))
|
||||
},
|
||||
)
|
||||
|
||||
transferProcessNavGraph(navigateBack = navController::popBackStack)
|
||||
@ -156,7 +151,7 @@ fun RootNavGraph(
|
||||
beneficiaryNavGraph(
|
||||
navController = navController,
|
||||
openQrImportScreen = navController::navigateToQrImportScreen,
|
||||
openQrReaderScreen = navController::navigateToQrReaderScreen
|
||||
openQrReaderScreen = navController::navigateToQrReaderScreen,
|
||||
)
|
||||
|
||||
qrNavGraph(
|
||||
@ -169,7 +164,7 @@ fun RootNavGraph(
|
||||
viewCharges = navController::navigateToClientChargeScreen,
|
||||
viewQrCode = navController::navigateToQrDisplayScreen,
|
||||
callHelpline = { callHelpline(context) },
|
||||
reviewTransfer = navController::navigateToTransferProcessScreen
|
||||
reviewTransfer = navController::navigateToTransferProcessScreen,
|
||||
)
|
||||
|
||||
clientAccountsNavGraph(
|
||||
@ -182,38 +177,28 @@ fun RootNavGraph(
|
||||
AccountType.LOAN -> navController.navigateToLoanDetailScreen(loanId = id)
|
||||
AccountType.SHARE -> {}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
composable(PASSCODE_SCREEN) {
|
||||
PasscodeScreen(
|
||||
onForgotButton = navController::navigateToHomeScreen,
|
||||
onSkipButton = navController::navigateToHomeScreen,
|
||||
onPasscodeConfirm = {
|
||||
navController.navigateToHomeScreen()
|
||||
},
|
||||
onPasscodeRejected = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const val PASSCODE_SCREEN = "passcode_screen"
|
||||
|
||||
fun NavController.navigateToPasscodeScreen(navOptions: NavOptions? = null) {
|
||||
return this.navigate(PASSCODE_SCREEN, navOptions)
|
||||
}
|
||||
|
||||
fun handleHomeNavigation(
|
||||
navController: NavHostController,
|
||||
homeDestinations: HomeDestinations,
|
||||
context: Context
|
||||
onClickLogout: () -> Unit,
|
||||
context: Context,
|
||||
) {
|
||||
when (homeDestinations) {
|
||||
HomeDestinations.HOME -> Unit
|
||||
HomeDestinations.ACCOUNTS -> navController.navigateToClientAccountsScreen()
|
||||
HomeDestinations.LOAN_ACCOUNT -> navController.navigateToClientAccountsScreen(accountType = AccountType.LOAN)
|
||||
HomeDestinations.SAVINGS_ACCOUNT -> navController.navigateToClientAccountsScreen(accountType = AccountType.SAVINGS)
|
||||
HomeDestinations.LOAN_ACCOUNT -> {
|
||||
navController.navigateToClientAccountsScreen(accountType = AccountType.LOAN)
|
||||
}
|
||||
|
||||
HomeDestinations.SAVINGS_ACCOUNT -> {
|
||||
navController.navigateToClientAccountsScreen(accountType = AccountType.SAVINGS)
|
||||
}
|
||||
|
||||
HomeDestinations.RECENT_TRANSACTIONS -> navController.navigateToRecentTransaction()
|
||||
HomeDestinations.CHARGES -> navController.navigateToClientChargeScreen(ChargeType.CLIENT)
|
||||
HomeDestinations.THIRD_PARTY_TRANSFER -> navController.navigateToThirdPartyTransfer()
|
||||
@ -228,10 +213,10 @@ fun handleHomeNavigation(
|
||||
openAppInfo(context)
|
||||
}
|
||||
|
||||
HomeDestinations.LOGOUT -> navController.navigateToLoginScreen()
|
||||
HomeDestinations.LOGOUT -> onClickLogout.invoke()
|
||||
HomeDestinations.TRANSFER -> navController.navigateToSavingsMakeTransfer(
|
||||
accountId = 1,
|
||||
transferType = TRANSFER_PAY_TO
|
||||
transferType = TRANSFER_PAY_TO,
|
||||
)
|
||||
|
||||
HomeDestinations.BENEFICIARIES -> navController.navigateToBeneficiaryListScreen()
|
||||
@ -245,20 +230,6 @@ fun <T : Activity> startActivity(context: Context, clazz: Class<T>) {
|
||||
context.startActivity(Intent(context, clazz))
|
||||
}
|
||||
|
||||
private fun startPassCodeActivity(context: Context) {
|
||||
val intent = Intent(context, PassCodeActivity::class.java)
|
||||
intent.putExtra(INTIAL_LOGIN, true)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
//
|
||||
//private fun navigateToUpdatePasscodeActivity(passcode: String, context: Context) {
|
||||
// val intent = Intent(context, PassCodeActivity::class.java).apply {
|
||||
// putExtra(CURR_PASSWORD, passcode)
|
||||
// putExtra(IS_TO_UPDATE_PASS_CODE, true)s
|
||||
// }
|
||||
// context.startActivity(intent)ss
|
||||
//}
|
||||
|
||||
private fun callHelpline(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_DIAL)
|
||||
intent.data =
|
||||
@ -271,11 +242,11 @@ private fun mailHelpline(context: Context) {
|
||||
data = Uri.parse("mailto:")
|
||||
putExtra(
|
||||
Intent.EXTRA_EMAIL,
|
||||
arrayOf(context.getString(org.mifos.mobile.feature.home.R.string.contact_email))
|
||||
arrayOf(context.getString(org.mifos.mobile.feature.home.R.string.contact_email)),
|
||||
)
|
||||
putExtra(
|
||||
Intent.EXTRA_SUBJECT,
|
||||
context.getString(org.mifos.mobile.feature.home.R.string.user_query)
|
||||
context.getString(org.mifos.mobile.feature.home.R.string.user_query),
|
||||
)
|
||||
}
|
||||
try {
|
||||
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.navigation
|
||||
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.navigation
|
||||
import org.mifos.library.passcode.PASSCODE_SCREEN
|
||||
import org.mifos.library.passcode.passcodeRoute
|
||||
|
||||
internal fun NavGraphBuilder.passcodeNavGraph(navController: NavHostController) {
|
||||
navigation(
|
||||
route = MifosNavGraph.PASSCODE_GRAPH,
|
||||
startDestination = PASSCODE_SCREEN,
|
||||
) {
|
||||
passcodeRoute(
|
||||
onForgotButton = {
|
||||
navController.popBackStack()
|
||||
navController.navigate(MifosNavGraph.MAIN_GRAPH)
|
||||
},
|
||||
onSkipButton = {
|
||||
navController.popBackStack()
|
||||
navController.navigate(MifosNavGraph.MAIN_GRAPH)
|
||||
},
|
||||
onPasscodeConfirm = {
|
||||
navController.popBackStack()
|
||||
navController.navigate(MifosNavGraph.MAIN_GRAPH)
|
||||
},
|
||||
onPasscodeRejected = {
|
||||
navController.popBackStack()
|
||||
navController.navigate(MifosNavGraph.MAIN_GRAPH)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.navigation
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import org.mifos.library.passcode.navigateToPasscodeScreen
|
||||
import org.mifos.mobile.feature.auth.navigation.authenticationNavGraph
|
||||
import org.mifos.mobile.navigation.MifosNavGraph.AUTH_GRAPH
|
||||
import org.mifos.mobile.ui.MifosApp
|
||||
import org.mifos.mobile.ui.MifosMobileState
|
||||
|
||||
@Composable
|
||||
internal fun RootNavGraph(
|
||||
appState: MifosMobileState,
|
||||
navHostController: NavHostController,
|
||||
startDestination: String,
|
||||
onClickLogout: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
NavHost(
|
||||
navController = navHostController,
|
||||
startDestination = startDestination,
|
||||
route = MifosNavGraph.ROOT_GRAPH,
|
||||
modifier = modifier,
|
||||
) {
|
||||
authenticationNavGraph(
|
||||
navController = navHostController,
|
||||
route = AUTH_GRAPH,
|
||||
navigateToPasscodeScreen = navHostController::navigateToPasscodeScreen,
|
||||
)
|
||||
|
||||
passcodeNavGraph(navHostController)
|
||||
|
||||
composable(MifosNavGraph.MAIN_GRAPH) {
|
||||
MifosApp(
|
||||
appState = appState,
|
||||
onClickLogout = onClickLogout,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
90
androidApp/src/main/kotlin/org/mifos/mobile/ui/MifosApp.kt
Normal file
90
androidApp/src/main/kotlin/org/mifos/mobile/ui/MifosApp.kt
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarDuration.Indefinite
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTagsAsResourceId
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import org.mifos.mobile.R
|
||||
import org.mifos.mobile.core.designsystem.theme.MifosBackground
|
||||
import org.mifos.mobile.navigation.MifosNavHost
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun MifosApp(
|
||||
appState: MifosMobileState,
|
||||
onClickLogout: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
MifosBackground(modifier) {
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val isOffline by appState.isOffline.collectAsStateWithLifecycle()
|
||||
|
||||
// If user is not connected to the internet show a snack bar to inform them.
|
||||
val notConnectedMessage = stringResource(R.string.not_connected)
|
||||
LaunchedEffect(isOffline) {
|
||||
if (isOffline) {
|
||||
snackbarHostState.showSnackbar(
|
||||
message = notConnectedMessage,
|
||||
duration = Indefinite,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.semantics {
|
||||
testTagsAsResourceId = true
|
||||
},
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = MaterialTheme.colorScheme.onBackground,
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
) { padding ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding)
|
||||
.consumeWindowInsets(padding)
|
||||
.windowInsetsPadding(
|
||||
WindowInsets.safeDrawing.only(
|
||||
WindowInsetsSides.Horizontal,
|
||||
),
|
||||
),
|
||||
) {
|
||||
MifosNavHost(
|
||||
onClickLogout = onClickLogout,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.mifos.mobile.core.data.utils.NetworkMonitor
|
||||
|
||||
@Composable
|
||||
fun rememberMifosMobileState(
|
||||
networkMonitor: NetworkMonitor,
|
||||
coroutineScope: CoroutineScope = rememberCoroutineScope(),
|
||||
navController: NavHostController = rememberNavController(),
|
||||
): MifosMobileState {
|
||||
return remember(
|
||||
navController,
|
||||
coroutineScope,
|
||||
networkMonitor,
|
||||
) {
|
||||
MifosMobileState(
|
||||
navController = navController,
|
||||
coroutineScope = coroutineScope,
|
||||
networkMonitor = networkMonitor,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class MifosMobileState(
|
||||
val navController: NavHostController,
|
||||
coroutineScope: CoroutineScope,
|
||||
networkMonitor: NetworkMonitor,
|
||||
) {
|
||||
val currentDestination: NavDestination?
|
||||
@Composable get() = navController
|
||||
.currentBackStackEntryAsState().value?.destination
|
||||
|
||||
val isOffline = networkMonitor.isOnline
|
||||
.map(Boolean::not)
|
||||
.stateIn(
|
||||
scope = coroutineScope,
|
||||
started = SharingStarted.WhileSubscribed(5_000),
|
||||
initialValue = false,
|
||||
)
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:ordering="sequentially"
|
||||
android:shareInterpolator="false">
|
||||
|
||||
<objectAnimator
|
||||
android:duration="@android:integer/config_shortAnimTime"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M6,11 l0,0 l0,0"
|
||||
android:valueTo="M6,11 l3.5,4 l0,0"
|
||||
android:valueType="pathType" />
|
||||
|
||||
<objectAnimator
|
||||
android:duration="@android:integer/config_shortAnimTime"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M6,11 l3.5,4 l0,0"
|
||||
android:valueTo="M6,11 l3.5,4 l8,-7"
|
||||
android:valueType="pathType" />
|
||||
</set>
|
||||
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/gray_dark"
|
||||
android:pathData="M4,4H10V10H4V4M20,4V10H14V4H20M14,15H16V13H14V11H16V13H18V11H20V13H18V15H20V18H18V20H16V18H13V20H11V16H14V15M16,15V18H18V15H16M4,20V14H10V20H4M6,6V8H8V6H6M16,6V8H18V6H16M6,16V18H8V16H6M4,11H6V13H4V11M9,11H13V15H11V13H9V11M11,6H13V10H11V6M2,2V6H0V2A2,2 0,0 1,2 0H6V2H2M22,0A2,2 0,0 1,24 2V6H22V2H18V0H22M2,18V22H6V24H2A2,2 0,0 1,0 22V18H2M22,22V18H24V22A2,2 0,0 1,22 24H18V22H22Z" />
|
||||
</vector>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.4 KiB |
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_check_circle_green_24px">
|
||||
<target
|
||||
android:name="tick"
|
||||
android:animation="@anim/check_animation" />
|
||||
</animated-vector>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB |
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_check_circle_green_24px">
|
||||
<target android:name="tick" />
|
||||
</vector>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#000000"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M4,10v7h3v-7L4,10zM10,10v7h3v-7h-3zM2,22h19v-3L2,19v3zM16,10v7h3v-7h-3zM11.5,1L2,6v2h19L21,6l-9.5,-5z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M21,18v1c0,1.1 -0.9,2 -2,2L5,21c-1.11,0 -2,-0.9 -2,-2L3,5c0,-1.1 0.89,-2 2,-2h14c1.1,0 2,0.9 2,2v1h-9c-1.11,0 -2,0.9 -2,2v8c0,1.1 0.89,2 2,2h9zM12,16h10L22,8L12,8v8zM16,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/gray_dark"
|
||||
android:pathData="M21,18v1c0,1.1 -0.9,2 -2,2L5,21c-1.11,0 -2,-0.9 -2,-2L3,5c0,-1.1 0.89,-2 2,-2h14c1.1,0 2,0.9 2,2v1h-9c-1.11,0 -2,0.9 -2,2v8c0,1.1 0.89,2 2,2h9zM12,16h10L22,8L12,8v8zM16,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M7,10l5,5 5,-5z" />
|
||||
</vector>
|
||||
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_arrow_drop_down"
|
||||
android:fromDegrees="180"
|
||||
android:toDegrees="0" />
|
||||
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,3h-4.18C14.4,1.84 13.3,1 12,1c-1.3,0 -2.4,0.84 -2.82,2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM10,17l-4,-4 1.41,-1.41L10,14.17l6.59,-6.59L18,9l-8,8z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M11.8,10.9c-2.27,-0.59 -3,-1.2 -3,-2.15 0,-1.09 1.01,-1.85 2.7,-1.85 1.78,0 2.44,0.85 2.5,2.1h2.21c-0.07,-1.72 -1.12,-3.3 -3.21,-3.81V3h-3v2.16c-1.94,0.42 -3.5,1.68 -3.5,3.61 0,2.31 1.91,3.46 4.7,4.13 2.5,0.6 3,1.48 3,2.41 0,0.69 -0.49,1.79 -2.7,1.79 -2.06,0 -2.87,-0.92 -2.98,-2.1h-2.2c0.12,2.19 1.76,3.42 3.68,3.83V21h3v-2.15c1.95,-0.37 3.5,-1.5 3.5,-3.55 0,-2.84 -2.43,-3.81 -4.7,-4.4z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48.0"
|
||||
android:viewportHeight="48.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M44,6L14,6c-1.38,0 -2.47,0.7 -3.19,1.76L0,23.99l10.81,16.23C11.53,41.28 12.62,42 14,42h30c2.21,0 4,-1.79 4,-4L48,10c0,-2.21 -1.79,-4 -4,-4zM38,31.17L35.17,34 28,26.83 20.83,34 18,31.17 25.17,24 18,16.83 20.83,14 28,21.17 35.17,14 38,16.83 30.83,24 38,31.17z" />
|
||||
</vector>
|
||||
@ -1,11 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:autoMirrored="true"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" />
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4c-1.48,0 -2.85,0.43 -4.01,1.17l1.46,1.46C10.21,6.23 11.08,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3 0,1.13 -0.64,2.11 -1.56,2.62l1.45,1.45C23.16,18.16 24,16.68 24,15c0,-2.64 -2.05,-4.78 -4.65,-4.96zM3,5.27l2.75,2.74C2.56,8.15 0,10.77 0,14c0,3.31 2.69,6 6,6h11.73l2,2L21,20.73 4.27,4 3,5.27zM7.73,10l8,8H6c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h1.73z" />
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9s9,-4.03 9,-9c0,-0.46 -0.04,-0.92 -0.1,-1.36c-0.98,1.37 -2.58,2.26 -4.4,2.26c-2.98,0 -5.4,-2.42 -5.4,-5.4c0,-1.81 0.89,-3.42 2.26,-4.4C12.92,3.04 12.46,3 12,3L12,3z" />
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48.0"
|
||||
android:viewportHeight="48.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M33,24c2.76,0 4.98,-2.24 4.98,-5s-2.22,-5 -4.98,-5c-2.76,0 -5,2.24 -5,5s2.24,5 5,5zM18,22c3.31,0 5.98,-2.69 5.98,-6s-2.67,-6 -5.98,-6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6zM33,28c-3.67,0 -11,1.84 -11,5.5L22,38h22v-4.5c0,-3.66 -7.33,-5.5 -11,-5.5zM18,26c-4.67,0 -14,2.34 -14,7v5h14v-4.5c0,-1.7 0.67,-4.67 4.74,-6.94C21,26.19 19.31,26 18,26z" />
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48.0"
|
||||
android:viewportHeight="48.0">
|
||||
<path
|
||||
android:fillColor="@color/gray_dark"
|
||||
android:pathData="M28,4L12,4C9.79,4 8.02,5.79 8.02,8L8,40c0,2.21 1.77,4 3.98,4L36,44c2.21,0 4,-1.79 4,-4L40,16L28,4zM32,32h-6v6h-4v-6h-6v-4h6v-6h4v6h6v4zM26,18L26,7l11,11L26,18z" />
|
||||
</vector>
|
||||
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_beneficiaries_48px" />
|
||||
</layer-list>
|
||||
@ -1,13 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M17.75,7L14,3.25l-10,10L4,17h3.75l10,-10zM20.71,4.04c0.39,-0.39 0.39,-1.02 0,-1.41L18.37,0.29c-0.39,-0.39 -1.02,-0.39 -1.41,0L15,2.25 18.75,6l1.96,-1.96z" />
|
||||
<path
|
||||
android:fillAlpha=".36"
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M0,20h24v4H0z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M12,6c1.11,0 2,-0.9 2,-2 0,-0.38 -0.1,-0.73 -0.29,-1.03L12,0l-1.71,2.97c-0.19,0.3 -0.29,0.65 -0.29,1.03 0,1.1 0.9,2 2,2zM16.6,15.99l-1.07,-1.07 -1.08,1.07c-1.3,1.3 -3.58,1.31 -4.89,0l-1.07,-1.07 -1.09,1.07C6.75,16.64 5.88,17 4.96,17c-0.73,0 -1.4,-0.23 -1.96,-0.61L3,21c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-4.61c-0.56,0.38 -1.23,0.61 -1.96,0.61 -0.92,0 -1.79,-0.36 -2.44,-1.01zM18,9h-5L13,7h-2v2L6,9c-1.66,0 -3,1.34 -3,3v1.54c0,1.08 0.88,1.96 1.96,1.96 0.52,0 1.02,-0.2 1.38,-0.57l2.14,-2.13 2.13,2.13c0.74,0.74 2.03,0.74 2.77,0l2.14,-2.13 2.13,2.13c0.37,0.37 0.86,0.57 1.38,0.57 1.08,0 1.96,-0.88 1.96,-1.96L20.99,12C21,10.34 19.66,9 18,9z" />
|
||||
</vector>
|
||||
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_cake_24dp" />
|
||||
</layer-list>
|
||||
@ -1,46 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="147.0"
|
||||
android:viewportHeight="146.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M89.2,96.26C89.66,97.79 89.9,99.37 89.9,100.98C89.9,115.77 69.78,127.75 44.95,127.75C20.12,127.75 0,115.77 0,100.98C0,99.37 0.24,97.79 0.7,96.26C4.44,107.94 22.83,116.8 44.95,116.8C67.07,116.8 85.46,107.94 89.2,96.26Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M89.2,114.51C89.66,116.04 89.9,117.62 89.9,119.23C89.9,134.02 69.78,146 44.95,146C20.12,146 0,134.02 0,119.23C0,117.62 0.24,116.04 0.7,114.51C4.44,126.19 22.83,135.05 44.95,135.05C67.07,135.05 85.46,126.19 89.2,114.51Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M0,86.99a44.95,24.94 0,1 0,89.9 0a44.95,24.94 0,1 0,-89.9 0z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M102.05,49.88C126.88,49.88 147,38.72 147,24.94C147,11.17 126.88,0 102.05,0C77.22,0 57.1,11.17 57.1,24.94C57.1,38.72 77.22,49.88 102.05,49.88Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M85.13,64.96C90.35,66.22 96.06,66.92 102.05,66.92C126.88,66.92 147,54.93 147,40.15C147,38.54 146.76,36.96 146.3,35.43C142.56,47.1 124.17,55.97 102.05,55.97C79.93,55.97 61.54,47.1 57.8,35.43C57.34,36.96 57.1,38.54 57.1,40.15C57.1,46.64 60.98,52.59 67.43,57.23C73.33,58.16 79.62,60.38 85.13,64.96Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M96.05,82.5C98.01,82.65 100.01,82.73 102.05,82.73C126.88,82.73 147,70.75 147,55.97C147,54.35 146.76,52.78 146.3,51.24C142.56,62.92 124.17,71.78 102.05,71.78C98.17,71.78 94.41,71.51 90.82,71C92.77,73.62 94.51,76.7 95.98,80.3L96.05,82.5Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M96.6,99.57C98.38,99.7 100.2,99.77 102.05,99.77C126.88,99.77 147,87.78 147,73C147,71.39 146.76,69.81 146.3,68.28C142.56,79.95 124.17,88.82 102.05,88.82C100.08,88.82 98.14,88.75 96.24,88.61L96.6,99.57Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M97.15,116.64C98.76,116.75 100.39,116.8 102.05,116.8C126.88,116.8 147,104.82 147,90.03C147,88.42 146.76,86.84 146.3,85.31C142.56,96.99 124.17,105.85 102.05,105.85C100.27,105.85 98.52,105.79 96.79,105.68L97.15,116.64Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@ -1,20 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<group android:name="background">
|
||||
<path
|
||||
android:name="circle"
|
||||
android:fillColor="#4CAF50"
|
||||
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0" />
|
||||
</group>
|
||||
<group android:name="check">
|
||||
<path
|
||||
android:name="tick"
|
||||
android:pathData="M6,11 l0,0 l0,0"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="@color/white" />
|
||||
</group>
|
||||
|
||||
</vector>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1001 B |
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M9.01,14L2,14v2h7.01v3L13,15l-3.99,-4v3zM14.99,13v-3L22,10L22,8h-7.01L14.99,5L11,9l3.99,4z" />
|
||||
</vector>
|
||||
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c0.39-0.39 0.39 -1.02 0-1.41l-2.34-2.34c-0.39-0.39-1.02-0.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z" />
|
||||
<path android:pathData="M0 0h24v24H0z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/gray_dark"
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
|
||||
</vector>
|
||||
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_edit_black_24dp" />
|
||||
</selector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-2h2v2zM13,13h-2L11,7h2v6z" />
|
||||
</vector>
|
||||
@ -1,11 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:alpha="0.93"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/gray_dark"
|
||||
android:pathData="M9,16h6v-6h4l-7,-7 -7,7h4zM5,18h14v2L5,20z" />
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z" />
|
||||
</vector>
|
||||
@ -1,11 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:alpha="0.8"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M3.27,3L2,4.27l5,5V13h3v9l3.58,-6.14L17.73,20 19,18.73 3.27,3zM17,10h-4l4,-8H7v2.18l8.46,8.46L17,10z" />
|
||||
</vector>
|
||||
@ -1,11 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:alpha="0.8"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M7,2v11h3v9l7,-12h-4l4,-8z" />
|
||||
</vector>
|
||||
@ -1,45 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m266.859,466.778h-21.719c-3.952,0 -7.155,-3.203 -7.155,-7.155v-407.247c0,-3.952 3.203,-7.155 7.155,-7.155h21.719c3.952,0 7.155,3.203 7.155,7.155v407.247c0,3.952 -3.203,7.155 -7.155,7.155z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m266.859,466.778h-10.859v-421.557h10.859c3.952,0 7.155,3.203 7.155,7.155v407.247c0,3.952 -3.203,7.155 -7.155,7.155z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M423.74,80.381m-60.946,0a60.946,60.946 0,1 1,121.892 0a60.946,60.946 0,1 1,-121.892 0" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m511.914,326.904 l-15.196,-128.529c-1.537,-13 -12.557,-22.794 -25.647,-22.794h-94.663c-13.09,0 -24.11,9.794 -25.647,22.794l-15.196,128.529c-0.857,7.248 4.805,13.618 12.104,13.618l21.612,0.081 -0.567,5.1 -3.536,31.799c-0.401,3.61 2.424,6.767 6.057,6.767h0.674l8.044,97.113c0.523,6.319 5.805,11.182 12.146,11.182h63.283c6.341,0 11.623,-4.862 12.146,-11.182l8.044,-97.113h0.674c3.632,0 6.458,-3.157 6.057,-6.767l-3.536,-31.799 -0.573,-5.181h21.618c7.297,0.001 12.959,-6.37 12.102,-13.618z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m467.197,241.673c-0.686,-6.172 -5.903,-10.841 -12.113,-10.841h-31.344,-31.344c-6.21,0 -11.427,4.669 -12.113,10.841l-15.105,135.829c-0.401,3.61 2.424,6.767 6.057,6.767h52.506,52.506c3.632,0 6.458,-3.157 6.057,-6.767z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m476.25,384.275h-18.605c3.628,0 6.45,-3.163 6.057,-6.77l-15.111,-135.836c-0.682,-6.171 -5.902,-10.832 -12.114,-10.832h18.605c6.212,0 11.432,4.662 12.114,10.832l15.111,135.836c0.393,3.607 -2.429,6.77 -6.057,6.77z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m484.684,80.376c0,33.664 -27.287,60.951 -60.941,60.951 -3.525,0 -6.977,-0.3 -10.336,-0.878 28.734,-4.9 50.605,-29.933 50.605,-60.073 0,-30.129 -21.871,-55.163 -50.605,-60.062 3.359,-0.579 6.811,-0.879 10.336,-0.879 33.654,0 60.941,27.287 60.941,60.941z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m475.568,384.275 l-8.041,97.107c-0.527,6.326 -5.809,11.184 -12.145,11.184h-20.672c6.336,0 11.618,-4.858 12.145,-11.184l8.041,-97.107z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m499.806,340.523h-20.61c7.277,-0.041 12.899,-6.388 12.042,-13.623l-15.194,-128.528c-1.53,-12.992 -12.558,-22.791 -25.644,-22.791h20.672c13.085,0 24.114,9.799 25.644,22.791l15.193,128.528c0.858,7.256 -4.796,13.623 -12.103,13.623z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M89.783,80.381m-60.946,0a60.946,60.946 0,1 1,121.892 0a60.946,60.946 0,1 1,-121.892 0" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m153.745,175.581h-127.924c-14.26,0 -25.821,11.561 -25.821,25.821v126.932c0,6.731 5.457,12.188 12.188,12.188h22.141v3.667,136.187c0,6.731 5.457,12.188 12.188,12.188h17.063c6.731,0 12.188,-5.457 12.188,-12.188v-82.322c0,-7.613 6.171,-13.784 13.784,-13.784h0.463c7.613,0 13.784,6.172 13.784,13.784v82.322c0,6.731 5.457,12.188 12.188,12.188h17.063c6.731,0 12.188,-5.457 12.188,-12.188v-136.186,-3.667h22.141c6.731,0 12.188,-5.456 12.188,-12.188v-126.933c0,-14.26 -11.561,-25.821 -25.822,-25.821z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m150.728,80.376c0,33.664 -27.287,60.951 -60.941,60.951 -3.886,0 -7.69,-0.362 -11.37,-1.065 28.217,-5.323 49.571,-30.109 49.571,-59.887 0,-29.768 -21.354,-54.553 -49.571,-59.876 3.68,-0.703 7.483,-1.065 11.37,-1.065 33.654,0.001 60.941,27.288 60.941,60.942z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="m179.565,201.4v126.936c0,6.729 -5.457,12.186 -12.186,12.186h-22.14s11.587,-5.457 11.587,-12.186v-126.936c0,-14.253 -11.556,-25.819 -25.819,-25.819h22.739c14.264,0 25.819,11.566 25.819,25.819z" />
|
||||
</vector>
|
||||
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_gender_24dp" />
|
||||
</layer-list>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z" />
|
||||
</vector>
|
||||
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M17.63,5.84C17.27,5.33 16.67,5 16,5L5,5.01C3.9,5.01 3,5.9 3,7v10c0,1.1 0.9,1.99 2,1.99L16,19c0.67,0 1.27,-0.33 1.63,-0.84L22,12l-4.37,-6.16z" />
|
||||
</vector>
|
||||
@ -1,11 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="192.0"
|
||||
android:viewportHeight="192.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorPrimary"
|
||||
android:pathData="M133,80.33L133,76L125,76L125,79.69C120.18,80.93 114.15,84.37 118,94C118,94 120,99 132,100C132,100 141,105 131,107C131,107 125,106 124,103L117,103L117,114L124,114L124,111.27C124.62,111.67 125.29,112.06 126,112.42L126,117L133,117L133,113.87C136.05,113.51 139.22,111.64 142,107C142,107 145,97 134,94C123,91 124,92 124,88C124,84 132,87 132,87L135,90L142,90L142,79L135,79L135,81.22L133,80.33ZM169.68,86.67C172.38,91.25 174,97.11 174,103.5C174,107.63 173.32,111.53 172.12,115.01C191.98,117.09 188,139 188,139C188,139 173,160 154,175C135,190 99,192 83,180C67,168 55,171 55,171L54,182L7,182C2,172 6,105 6,105L53,105L54,110C64.11,105.28 76.95,106.47 84.24,107.75C84.08,106.36 84,104.95 84,103.5C84,96.27 86.08,89.71 89.45,84.93C91.73,80.16 102.29,58.75 111.27,52.47C111.27,52.47 131.79,57.53 149,52.47C149,52.47 162.9,71.03 169.68,86.67ZM56.37,115.19C56.37,115.19 100.02,103.28 135.73,135.03C135.73,135.03 141.68,154.86 118.87,148.91C96.05,142.96 101.01,142.96 101.01,142.96L98.03,150.9C98.03,150.9 136.72,171.73 143.66,146.93L168,123C168,123 172.06,117.07 180,126C187.94,134.93 176,142 176,142L155.57,162.8C155.57,162.8 126.8,196.53 81.17,170.74C81.17,170.74 62.32,159.82 53.4,162.8C53.4,162.8 54.39,118.16 52.4,117.17C50.42,116.18 56.37,115.19 56.37,115.19ZM107,27C109.5,35.73 117,48 117,48C117,48 132,53 148,48C148,48 165,24 154,12C154,12 150,9 144,15C138,21 135,22 135,22C135,22 133,23 130,22C130,22 114,10 109,14C106.76,15.79 104.96,19.86 107,27Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11,17h2v-1h1c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1h-3v-1h4L15,8h-2L13,7h-2v1h-1c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1h3v1L9,14v2h2v1zM20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM20,18L4,18L4,6h16v12z" />
|
||||
</vector>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user