mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2024-11-25 04:44:36 -06:00
Add F-Droid flavor (#349)
This commit is contained in:
parent
0b2ef367da
commit
b1e3bab5e7
@ -35,7 +35,7 @@ jobs:
|
|||||||
command: ./gradlew dependencies --no-daemon --stacktrace --console=plain -PdisablePreDex || true
|
command: ./gradlew dependencies --no-daemon --stacktrace --console=plain -PdisablePreDex || true
|
||||||
- run:
|
- run:
|
||||||
name: Initial build
|
name: Initial build
|
||||||
command: ./gradlew build -x test -x lint -x fabricGenerateResourcesRelease -x packageRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
|
command: ./gradlew build -x test -x lint -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease -x packageRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
|
||||||
- run:
|
- run:
|
||||||
name: Run FOSSA
|
name: Run FOSSA
|
||||||
command: fossa --no-ansi || true
|
command: fossa --no-ansi || true
|
||||||
@ -56,7 +56,7 @@ jobs:
|
|||||||
<<: *general_cache_key
|
<<: *general_cache_key
|
||||||
- run:
|
- run:
|
||||||
name: Run lint
|
name: Run lint
|
||||||
command: ./gradlew lint -x fabricGenerateResourcesRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
|
command: ./gradlew lint -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: ./app/build/reports/
|
path: ./app/build/reports/
|
||||||
destination: lint_reports/app/
|
destination: lint_reports/app/
|
||||||
@ -75,7 +75,7 @@ jobs:
|
|||||||
<<: *general_cache_key
|
<<: *general_cache_key
|
||||||
- run:
|
- run:
|
||||||
name: Run app tests
|
name: Run app tests
|
||||||
command: ./gradlew :app:test :app:jacocoTestReport -x fabricGenerateResourcesRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
|
command: ./gradlew :app:test :app:jacocoTestReport -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
|
||||||
- run:
|
- run:
|
||||||
name: Upload unit code coverage to codecov
|
name: Upload unit code coverage to codecov
|
||||||
command: bash <(curl -s https://codecov.io/bash) -F app
|
command: bash <(curl -s https://codecov.io/bash) -F app
|
||||||
@ -116,7 +116,7 @@ jobs:
|
|||||||
adb shell input keyevent 82
|
adb shell input keyevent 82
|
||||||
- run:
|
- run:
|
||||||
name: Run instrumented tests
|
name: Run instrumented tests
|
||||||
command: ./gradlew clean createDebugCoverageReport jacocoTestReport --no-daemon --stacktrace --console=plain -PdisablePreDex
|
command: ./gradlew clean createPlayDebugCoverageReport jacocoTestReport --no-daemon --stacktrace --console=plain -PdisablePreDex
|
||||||
- run:
|
- run:
|
||||||
name: Collect logs from emulator
|
name: Collect logs from emulator
|
||||||
command: adb logcat -d > ./app/build/reports/logcat_emulator.txt
|
command: adb logcat -d > ./app/build/reports/logcat_emulator.txt
|
||||||
@ -162,7 +162,7 @@ jobs:
|
|||||||
openssl aes-256-cbc -d -in ./app/upload-key-encrypted.jks -k $ENCRYPT_KEY >> ./app/upload-key.jks
|
openssl aes-256-cbc -d -in ./app/upload-key-encrypted.jks -k $ENCRYPT_KEY >> ./app/upload-key.jks
|
||||||
- run:
|
- run:
|
||||||
name: Publish release
|
name: Publish release
|
||||||
command: ./gradlew publish --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex
|
command: ./gradlew publishPlayRelease --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
version: 2
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -48,3 +48,4 @@ app/key.p12
|
|||||||
app/upload-key.jks
|
app/upload-key.jks
|
||||||
*.log
|
*.log
|
||||||
.idea/assetWizardSettings.xml
|
.idea/assetWizardSettings.xml
|
||||||
|
.idea/uiDesigner.xml
|
||||||
|
@ -12,7 +12,7 @@ build:
|
|||||||
script:
|
script:
|
||||||
- ./gradlew --no-daemon --stacktrace dependencies || true
|
- ./gradlew --no-daemon --stacktrace dependencies || true
|
||||||
- ./gradlew --no-daemon --stacktrace assembleDebug
|
- ./gradlew --no-daemon --stacktrace assembleDebug
|
||||||
- mv app/build/outputs/apk/debug/app-debug.apk .
|
- mv app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk .
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "${CI_PROJECT_NAME}_${CI_BUILD_REF_NAME}-${CI_BUILD_ID}"
|
name: "${CI_PROJECT_NAME}_${CI_BUILD_REF_NAME}-${CI_BUILD_ID}"
|
||||||
paths:
|
paths:
|
||||||
@ -26,7 +26,7 @@ tests:
|
|||||||
- .gradle
|
- .gradle
|
||||||
policy: pull
|
policy: pull
|
||||||
script:
|
script:
|
||||||
- ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesRelease test
|
- ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease test
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- app/build/reports/tests
|
- app/build/reports/tests
|
||||||
@ -39,7 +39,7 @@ lint:
|
|||||||
- .gradle
|
- .gradle
|
||||||
policy: pull
|
policy: pull
|
||||||
script:
|
script:
|
||||||
- ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesRelease lint
|
- ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease lint
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- app/build/reports
|
- app/build/reports
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="RunConfigurationProducerService">
|
|
||||||
<option name="ignoredProducers">
|
|
||||||
<set>
|
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
10
.travis.yml
10
.travis.yml
@ -47,20 +47,20 @@ before_script:
|
|||||||
script:
|
script:
|
||||||
- ./gradlew dependencies --stacktrace --daemon
|
- ./gradlew dependencies --stacktrace --daemon
|
||||||
- fossa --no-ansi || true
|
- fossa --no-ansi || true
|
||||||
#- ./gradlew lint -x fabricGenerateResourcesRelease --stacktrace --daemon
|
#- ./gradlew lintPlayRelease -x fabricGenerateResourcesPlayRelease --stacktrace --daemon
|
||||||
- ./gradlew test -x fabricGenerateResourcesRelease --stacktrace --daemon
|
- ./gradlew testPlayDebugUnitTest -x fabricGenerateResourcesPlay --stacktrace --daemon
|
||||||
- ./gradlew createDebugCoverageReport --stacktrace --daemon
|
- ./gradlew createPlayDebugCoverageReport --stacktrace --daemon
|
||||||
- ./gradlew jacocoTestReport --stacktrace --daemon
|
- ./gradlew jacocoTestReport --stacktrace --daemon
|
||||||
- if [ -z ${SONAR_HOST+x} ]; then echo "sonar scan skipped"; else
|
- if [ -z ${SONAR_HOST+x} ]; then echo "sonar scan skipped"; else
|
||||||
git fetch --unshallow;
|
git fetch --unshallow;
|
||||||
./gradlew sonarqube -x test -x lint -x fabricGenerateResourcesRelease -Dsonar.host.url=$SONAR_HOST -Dsonar.organization=$SONAR_ORG -Dsonar.login=$SONAR_KEY -Dsonar.branch.name=${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} --stacktrace --daemon;
|
./gradlew sonarqube -x test -x lint -x fabricGenerateResourcesPlayRelease -x fabricGenerateResourcesFdroidRelease -Dsonar.host.url=$SONAR_HOST -Dsonar.organization=$SONAR_ORG -Dsonar.login=$SONAR_KEY -Dsonar.branch.name=${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} --stacktrace --daemon;
|
||||||
fi
|
fi
|
||||||
- |
|
- |
|
||||||
if [ $TRAVIS_TAG ]; then
|
if [ $TRAVIS_TAG ]; then
|
||||||
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg;
|
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg;
|
||||||
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg;
|
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg;
|
||||||
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg;
|
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg;
|
||||||
./gradlew publish -PenableCrashlytics --stacktrace;
|
./gradlew publishPlayRelease -PenableCrashlytics --stacktrace;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
# Wulkanowy
|
# Wulkanowy
|
||||||
|
|
||||||
[![CircleCI](https://img.shields.io/circleci/project/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://circleci.com/gh/wulkanowy/wulkanowy)
|
|
||||||
[![Travis](https://img.shields.io/travis/com/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://travis-ci.com/wulkanowy/wulkanowy)
|
[![Travis](https://img.shields.io/travis/com/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://travis-ci.com/wulkanowy/wulkanowy)
|
||||||
[![Bitrise](https://img.shields.io/bitrise/daeff1893f3c8128/master.svg?token=Hjm1ACamk86JDeVVJHOeqQ&style=flat-square)](https://www.bitrise.io/app/daeff1893f3c8128)
|
[![Bitrise](https://img.shields.io/bitrise/daeff1893f3c8128/master.svg?token=Hjm1ACamk86JDeVVJHOeqQ&style=flat-square)](https://www.bitrise.io/app/daeff1893f3c8128)
|
||||||
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
|
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||||
@ -8,6 +7,8 @@
|
|||||||
[![Sonarcloud](https://sonarcloud.io/api/project_badges/measure?project=io.github.wulkanowy%3Aapp&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=io.github.wulkanowy%3Aapp)
|
[![Sonarcloud](https://sonarcloud.io/api/project_badges/measure?project=io.github.wulkanowy%3Aapp&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=io.github.wulkanowy%3Aapp)
|
||||||
[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy.svg?type=shield)](https://app.fossa.com/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy?ref=badge_shield)
|
[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy.svg?type=shield)](https://app.fossa.com/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy?ref=badge_shield)
|
||||||
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
|
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
|
||||||
|
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg)](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
|
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github)](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
|
||||||
[Pobierz wersję beta z Google Play](https://play.google.com/store/apps/details?id=io.github.wulkanowy&utm_source=vcs)
|
[Pobierz wersję beta z Google Play](https://play.google.com/store/apps/details?id=io.github.wulkanowy&utm_source=vcs)
|
||||||
|
|
||||||
|
@ -63,6 +63,18 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flavorDimensions "platform"
|
||||||
|
productFlavors {
|
||||||
|
play {
|
||||||
|
dimension "platform"
|
||||||
|
}
|
||||||
|
|
||||||
|
fdroid {
|
||||||
|
buildConfigField "boolean", "CRASHLYTICS_ENABLED", "false"
|
||||||
|
dimension "platform"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
disable 'HardwareIds'
|
disable 'HardwareIds'
|
||||||
}
|
}
|
||||||
@ -129,8 +141,8 @@ dependencies {
|
|||||||
implementation "com.mikepenz:aboutlibraries:6.2.3"
|
implementation "com.mikepenz:aboutlibraries:6.2.3"
|
||||||
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
||||||
|
|
||||||
implementation 'com.google.firebase:firebase-core:16.0.9'
|
playImplementation 'com.google.firebase:firebase-core:16.0.9'
|
||||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
|
playImplementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
|
||||||
|
|
||||||
releaseImplementation 'fr.o80.chucker:library-no-op:2.0.4'
|
releaseImplementation 'fr.o80.chucker:library-no-op:2.0.4'
|
||||||
|
|
||||||
|
@ -35,11 +35,14 @@ task jacocoTestReport(type: JacocoReport) {
|
|||||||
dir: "$buildDir/intermediates/classes/debug",
|
dir: "$buildDir/intermediates/classes/debug",
|
||||||
excludes: excludes
|
excludes: excludes
|
||||||
) + fileTree(
|
) + fileTree(
|
||||||
dir: "$buildDir/tmp/kotlin-classes/debug",
|
dir: "$buildDir/tmp/kotlin-classes/playDebug",
|
||||||
excludes: excludes
|
excludes: excludes
|
||||||
))
|
))
|
||||||
|
|
||||||
sourceDirectories.setFrom(files("$project.projectDir/src/main/java"))
|
sourceDirectories.setFrom(files([
|
||||||
|
"src/main/java",
|
||||||
|
"src/play/java"
|
||||||
|
]))
|
||||||
executionData.setFrom(fileTree(
|
executionData.setFrom(fileTree(
|
||||||
dir: project.projectDir,
|
dir: project.projectDir,
|
||||||
includes: ["**/*.exec", "**/*.ec"]
|
includes: ["**/*.exec", "**/*.ec"]
|
||||||
|
@ -29,5 +29,6 @@ sonarqube {
|
|||||||
property "sonar.java.coveragePlugin", "jacoco"
|
property "sonar.java.coveragePlugin", "jacoco"
|
||||||
property "sonar.android.lint.report", "build/reports/lint-results.xml"
|
property "sonar.android.lint.report", "build/reports/lint-results.xml"
|
||||||
property "sonar.jacoco.reportPaths", fileTree(dir: project.projectDir, includes: ['**/*.exec', '**/*.ec'])
|
property "sonar.jacoco.reportPaths", fileTree(dir: project.projectDir, includes: ['**/*.exec', '**/*.ec'])
|
||||||
|
property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacocoTestReport/jacocoTestReport.xml"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
@file:Suppress("UNUSED_PARAMETER")
|
||||||
|
|
||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class CrashlyticsTree : Timber.Tree() {
|
||||||
|
|
||||||
|
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initCrashlytics(context: Context) {
|
||||||
|
// do nothing
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class FirebaseAnalyticsHelper @Inject constructor() {
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
@ -4,21 +4,18 @@ import android.content.Context
|
|||||||
import androidx.multidex.MultiDex
|
import androidx.multidex.MultiDex
|
||||||
import androidx.work.Configuration
|
import androidx.work.Configuration
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.crashlytics.android.Crashlytics
|
|
||||||
import com.crashlytics.android.core.CrashlyticsCore
|
|
||||||
import com.jakewharton.threetenabp.AndroidThreeTen
|
import com.jakewharton.threetenabp.AndroidThreeTen
|
||||||
import dagger.android.AndroidInjector
|
import dagger.android.AndroidInjector
|
||||||
import dagger.android.support.DaggerApplication
|
import dagger.android.support.DaggerApplication
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.utils.Log
|
import eu.davidea.flexibleadapter.utils.Log
|
||||||
import io.fabric.sdk.android.Fabric
|
|
||||||
import io.github.wulkanowy.BuildConfig.CRASHLYTICS_ENABLED
|
|
||||||
import io.github.wulkanowy.BuildConfig.DEBUG
|
import io.github.wulkanowy.BuildConfig.DEBUG
|
||||||
import io.github.wulkanowy.di.DaggerAppComponent
|
import io.github.wulkanowy.di.DaggerAppComponent
|
||||||
import io.github.wulkanowy.services.sync.SyncWorkerFactory
|
import io.github.wulkanowy.services.sync.SyncWorkerFactory
|
||||||
import io.github.wulkanowy.utils.ActivityLifecycleLogger
|
import io.github.wulkanowy.utils.ActivityLifecycleLogger
|
||||||
import io.github.wulkanowy.utils.CrashlyticsTree
|
import io.github.wulkanowy.utils.CrashlyticsTree
|
||||||
import io.github.wulkanowy.utils.DebugLogTree
|
import io.github.wulkanowy.utils.DebugLogTree
|
||||||
|
import io.github.wulkanowy.utils.initCrashlytics
|
||||||
import io.reactivex.exceptions.UndeliverableException
|
import io.reactivex.exceptions.UndeliverableException
|
||||||
import io.reactivex.plugins.RxJavaPlugins
|
import io.reactivex.plugins.RxJavaPlugins
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -41,7 +38,7 @@ class WulkanowyApp : DaggerApplication() {
|
|||||||
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
|
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
|
||||||
RxJavaPlugins.setErrorHandler(::onError)
|
RxJavaPlugins.setErrorHandler(::onError)
|
||||||
|
|
||||||
initCrashlytics()
|
initCrashlytics(applicationContext)
|
||||||
initLogging()
|
initLogging()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,12 +52,6 @@ class WulkanowyApp : DaggerApplication() {
|
|||||||
registerActivityLifecycleCallbacks(ActivityLifecycleLogger())
|
registerActivityLifecycleCallbacks(ActivityLifecycleLogger())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initCrashlytics() {
|
|
||||||
Fabric.with(Fabric.Builder(this).kits(
|
|
||||||
Crashlytics.Builder().core(CrashlyticsCore.Builder().disabled(!CRASHLYTICS_ENABLED).build()).build()
|
|
||||||
).debuggable(DEBUG).build())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onError(error: Throwable) {
|
private fun onError(error: Throwable) {
|
||||||
if (error is UndeliverableException && error.cause is IOException || error.cause is InterruptedException) {
|
if (error is UndeliverableException && error.cause is IOException || error.cause is InterruptedException) {
|
||||||
Timber.e(error.cause, "An undeliverable error occurred")
|
Timber.e(error.cause, "An undeliverable error occurred")
|
||||||
|
@ -2,7 +2,6 @@ package io.github.wulkanowy.di
|
|||||||
|
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
@ -27,10 +26,6 @@ internal class AppModule {
|
|||||||
@Provides
|
@Provides
|
||||||
fun provideFlexibleAdapter() = FlexibleAdapter<AbstractFlexibleItem<*>>(null, null, true)
|
fun provideFlexibleAdapter() = FlexibleAdapter<AbstractFlexibleItem<*>>(null, null, true)
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideFirebaseAnalytics(context: Context) = FirebaseAnalytics.getInstance(context)
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideAppWidgetManager(context: Context): AppWidgetManager = AppWidgetManager.getInstance(context)
|
fun provideAppWidgetManager(context: Context): AppWidgetManager = AppWidgetManager.getInstance(context)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.attendance
|
package io.github.wulkanowy.ui.modules.attendance
|
||||||
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.data.repositories.attendance.AttendanceRepository
|
import io.github.wulkanowy.data.repositories.attendance.AttendanceRepository
|
||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
@ -9,12 +8,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
|||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.*
|
||||||
import io.github.wulkanowy.utils.isHolidays
|
|
||||||
import io.github.wulkanowy.utils.nextSchoolDay
|
|
||||||
import io.github.wulkanowy.utils.previousOrSameSchoolDay
|
|
||||||
import io.github.wulkanowy.utils.previousSchoolDay
|
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import org.threeten.bp.LocalDate.now
|
import org.threeten.bp.LocalDate.now
|
||||||
import org.threeten.bp.LocalDate.ofEpochDay
|
import org.threeten.bp.LocalDate.ofEpochDay
|
||||||
@ -115,7 +109,7 @@ class AttendancePresenter @Inject constructor(
|
|||||||
showEmpty(it.isEmpty())
|
showEmpty(it.isEmpty())
|
||||||
showContent(it.isNotEmpty())
|
showContent(it.isNotEmpty())
|
||||||
}
|
}
|
||||||
analytics.logEvent("load_attendance", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))
|
analytics.logEvent("load_attendance", "items" to it.size, "force_refresh" to forceRefresh)
|
||||||
}) {
|
}) {
|
||||||
Timber.i("Loading attendance result: An exception occurred")
|
Timber.i("Loading attendance result: An exception occurred")
|
||||||
view?.run { showEmpty(isViewEmpty) }
|
view?.run { showEmpty(isViewEmpty) }
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.exam
|
package io.github.wulkanowy.ui.modules.exam
|
||||||
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.data.db.entities.Exam
|
import io.github.wulkanowy.data.db.entities.Exam
|
||||||
import io.github.wulkanowy.data.repositories.exam.ExamRepository
|
import io.github.wulkanowy.data.repositories.exam.ExamRepository
|
||||||
@ -102,7 +101,7 @@ class ExamPresenter @Inject constructor(
|
|||||||
showEmpty(it.isEmpty())
|
showEmpty(it.isEmpty())
|
||||||
showContent(it.isNotEmpty())
|
showContent(it.isNotEmpty())
|
||||||
}
|
}
|
||||||
analytics.logEvent("load_exam", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))
|
analytics.logEvent("load_exam", "items" to it.size, "force_refresh" to forceRefresh)
|
||||||
}) {
|
}) {
|
||||||
Timber.i("Loading exam result: An exception occurred")
|
Timber.i("Loading exam result: An exception occurred")
|
||||||
view?.run { showEmpty(isViewEmpty) }
|
view?.run { showEmpty(isViewEmpty) }
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.homework
|
package io.github.wulkanowy.ui.modules.homework
|
||||||
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.data.db.entities.Homework
|
import io.github.wulkanowy.data.db.entities.Homework
|
||||||
import io.github.wulkanowy.data.repositories.homework.HomeworkRepository
|
import io.github.wulkanowy.data.repositories.homework.HomeworkRepository
|
||||||
@ -89,7 +88,7 @@ class HomeworkPresenter @Inject constructor(
|
|||||||
showEmpty(it.isEmpty())
|
showEmpty(it.isEmpty())
|
||||||
showContent(it.isNotEmpty())
|
showContent(it.isNotEmpty())
|
||||||
}
|
}
|
||||||
analytics.logEvent("load_homework", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))
|
analytics.logEvent("load_homework", "items" to it.size, "force_refresh" to forceRefresh)
|
||||||
}) {
|
}) {
|
||||||
Timber.i("Loading homework result: An exception occurred")
|
Timber.i("Loading homework result: An exception occurred")
|
||||||
view?.run { showEmpty(isViewEmpty()) }
|
view?.run { showEmpty(isViewEmpty()) }
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login.form
|
package io.github.wulkanowy.ui.modules.login.form
|
||||||
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Param.SUCCESS
|
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||||
@ -78,11 +77,11 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
.subscribe({
|
.subscribe({
|
||||||
Timber.i("Login result: Success")
|
Timber.i("Login result: Success")
|
||||||
analytics.logEvent("registration_form", SUCCESS to true, "students" to it.size, "endpoint" to endpoint, "error" to "No error")
|
analytics.logEvent("registration_form", "success" to true, "students" to it.size, "endpoint" to endpoint, "error" to "No error")
|
||||||
view?.notifyParentAccountLogged(it)
|
view?.notifyParentAccountLogged(it)
|
||||||
}, {
|
}, {
|
||||||
Timber.i("Login result: An exception occurred")
|
Timber.i("Login result: An exception occurred")
|
||||||
analytics.logEvent("registration_form", SUCCESS to false, "students" to -1, "endpoint" to endpoint, "error" to it.localizedMessage)
|
analytics.logEvent("registration_form", "success" to false, "students" to -1, "endpoint" to endpoint, "error" to it.localizedMessage.ifEmpty { "No message" })
|
||||||
loginErrorHandler.dispatch(it)
|
loginErrorHandler.dispatch(it)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login.studentselect
|
package io.github.wulkanowy.ui.modules.login.studentselect
|
||||||
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Param.SUCCESS
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
@ -21,7 +20,7 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
|
|
||||||
var students = emptyList<Student>()
|
var students = emptyList<Student>()
|
||||||
|
|
||||||
var selectedStudents = mutableListOf<Student>()
|
private var selectedStudents = mutableListOf<Student>()
|
||||||
|
|
||||||
fun onAttachView(view: LoginStudentSelectView, students: Serializable?) {
|
fun onAttachView(view: LoginStudentSelectView, students: Serializable?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
@ -78,11 +77,11 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
Timber.i("Registration started")
|
Timber.i("Registration started")
|
||||||
}
|
}
|
||||||
.subscribe({
|
.subscribe({
|
||||||
students.forEach { analytics.logEvent("registration_student_select", SUCCESS to true, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to "No error") }
|
students.forEach { analytics.logEvent("registration_student_select", "success" to true, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to "No error") }
|
||||||
Timber.i("Registration result: Success")
|
Timber.i("Registration result: Success")
|
||||||
view?.openMainView()
|
view?.openMainView()
|
||||||
}, { error ->
|
}, { error ->
|
||||||
students.forEach { analytics.logEvent("registration_student_select", SUCCESS to false, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to error.localizedMessage) }
|
students.forEach { analytics.logEvent("registration_student_select", "success" to false, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to error.localizedMessage.ifEmpty { "No message" }) }
|
||||||
Timber.i("Registration result: An exception occurred ")
|
Timber.i("Registration result: An exception occurred ")
|
||||||
loginErrorHandler.dispatch(error)
|
loginErrorHandler.dispatch(error)
|
||||||
view?.apply {
|
view?.apply {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login.symbol
|
package io.github.wulkanowy.ui.modules.login.symbol
|
||||||
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Param.SUCCESS
|
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||||
@ -59,7 +58,7 @@ class LoginSymbolPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.subscribe({
|
.subscribe({
|
||||||
analytics.logEvent("registration_symbol", SUCCESS to true, "students" to it.size, "endpoint" to loginData?.third, "symbol" to symbol, "error" to "No error")
|
analytics.logEvent("registration_symbol", "success" to true, "students" to it.size, "endpoint" to loginData?.third, "symbol" to symbol, "error" to "No error")
|
||||||
view?.apply {
|
view?.apply {
|
||||||
if (it.isEmpty()) {
|
if (it.isEmpty()) {
|
||||||
Timber.i("Login with symbol result: Empty student list")
|
Timber.i("Login with symbol result: Empty student list")
|
||||||
@ -71,7 +70,7 @@ class LoginSymbolPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
Timber.i("Login with symbol result: An exception occurred")
|
Timber.i("Login with symbol result: An exception occurred")
|
||||||
analytics.logEvent("registration_symbol", SUCCESS to false, "students" to -1, "endpoint" to loginData?.third, "symbol" to symbol, "error" to it.localizedMessage)
|
analytics.logEvent("registration_symbol", "success" to false, "students" to -1, "endpoint" to loginData?.third, "symbol" to symbol, "error" to it.localizedMessage.ifEmpty { "No message" })
|
||||||
loginErrorHandler.dispatch(it)
|
loginErrorHandler.dispatch(it)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.main
|
package io.github.wulkanowy.ui.modules.main
|
||||||
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Event.APP_OPEN
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Param.DESTINATION
|
|
||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.services.sync.SyncManager
|
import io.github.wulkanowy.services.sync.SyncManager
|
||||||
@ -33,7 +31,7 @@ class MainPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
syncManager.startSyncWorker()
|
syncManager.startSyncWorker()
|
||||||
analytics.logEvent(APP_OPEN, DESTINATION to initMenu?.name)
|
analytics.logEvent("app_open", "destination" to initMenu?.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onViewChange() {
|
fun onViewChange() {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.preview
|
package io.github.wulkanowy.ui.modules.message.preview
|
||||||
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE
|
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageRepository
|
import io.github.wulkanowy.data.repositories.message.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
@ -53,7 +52,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
else setSender(it.sender)
|
else setSender(it.sender)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
analytics.logEvent("load_message_preview", START_DATE to message.date.toFormattedString("yyyy.MM.dd"), "length" to message.content?.length)
|
analytics.logEvent("load_message_preview", "length" to message.content?.length)
|
||||||
}) {
|
}) {
|
||||||
Timber.i("Loading message $id preview result: An exception occurred ")
|
Timber.i("Loading message $id preview result: An exception occurred ")
|
||||||
view?.showMessageError()
|
view?.showMessageError()
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.timetable
|
package io.github.wulkanowy.ui.modules.timetable
|
||||||
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
@ -109,7 +108,7 @@ class TimetablePresenter @Inject constructor(
|
|||||||
showEmpty(it.isEmpty())
|
showEmpty(it.isEmpty())
|
||||||
showContent(it.isNotEmpty())
|
showContent(it.isNotEmpty())
|
||||||
}
|
}
|
||||||
analytics.logEvent("load_timetable", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))
|
analytics.logEvent("load_timetable", "items" to it.size, "force_refresh" to forceRefresh)
|
||||||
}) {
|
}) {
|
||||||
Timber.i("Loading timetable result: An exception occurred")
|
Timber.i("Loading timetable result: An exception occurred")
|
||||||
view?.run { showEmpty(isViewEmpty) }
|
view?.run { showEmpty(isViewEmpty) }
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.timetable.completed
|
package io.github.wulkanowy.ui.modules.timetable.completed
|
||||||
|
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.data.repositories.completedlessons.CompletedLessonsRepository
|
import io.github.wulkanowy.data.repositories.completedlessons.CompletedLessonsRepository
|
||||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||||
@ -93,7 +92,7 @@ class CompletedLessonsPresenter @Inject constructor(
|
|||||||
showEmpty(it.isEmpty())
|
showEmpty(it.isEmpty())
|
||||||
showContent(it.isNotEmpty())
|
showContent(it.isNotEmpty())
|
||||||
}
|
}
|
||||||
analytics.logEvent("load_completed_lessons", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))
|
analytics.logEvent("load_completed_lessons", "items" to it.size, "force_refresh" to forceRefresh)
|
||||||
}) {
|
}) {
|
||||||
Timber.i("Loading completed lessons result: An exception occurred")
|
Timber.i("Loading completed lessons result: An exception occurred")
|
||||||
view?.run { showEmpty(isViewEmpty) }
|
view?.run { showEmpty(isViewEmpty) }
|
||||||
|
@ -7,7 +7,6 @@ import android.os.Bundle
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import com.crashlytics.android.Crashlytics
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -19,17 +18,6 @@ class DebugLogTree : Timber.DebugTree() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CrashlyticsTree : Timber.Tree() {
|
|
||||||
|
|
||||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
|
||||||
Crashlytics.setInt("priority", priority)
|
|
||||||
Crashlytics.setString("tag", tag)
|
|
||||||
|
|
||||||
if (t == null) Crashlytics.log(message)
|
|
||||||
else Crashlytics.logException(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ActivityLifecycleLogger : Application.ActivityLifecycleCallbacks {
|
class ActivityLifecycleLogger : Application.ActivityLifecycleCallbacks {
|
||||||
|
|
||||||
override fun onActivityPaused(activity: Activity?) {
|
override fun onActivityPaused(activity: Activity?) {
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.crashlytics.android.Crashlytics
|
||||||
|
import com.crashlytics.android.core.CrashlyticsCore
|
||||||
|
import io.fabric.sdk.android.Fabric
|
||||||
|
import io.github.wulkanowy.BuildConfig
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class CrashlyticsTree : Timber.Tree() {
|
||||||
|
|
||||||
|
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||||
|
Crashlytics.setInt("priority", priority)
|
||||||
|
Crashlytics.setString("tag", tag)
|
||||||
|
|
||||||
|
if (t == null) Crashlytics.log(message)
|
||||||
|
else Crashlytics.logException(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initCrashlytics(context: Context) {
|
||||||
|
Fabric.with(Fabric.Builder(context).kits(
|
||||||
|
Crashlytics.Builder().core(CrashlyticsCore.Builder().disabled(!BuildConfig.CRASHLYTICS_ENABLED).build()).build()
|
||||||
|
).debuggable(BuildConfig.DEBUG).build())
|
||||||
|
}
|
@ -1,12 +1,15 @@
|
|||||||
package io.github.wulkanowy.utils
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class FirebaseAnalyticsHelper @Inject constructor(private val analytics: FirebaseAnalytics) {
|
class FirebaseAnalyticsHelper @Inject constructor(private val context: Context) {
|
||||||
|
|
||||||
|
private val analytics by lazy { FirebaseAnalytics.getInstance(context) }
|
||||||
|
|
||||||
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
|
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
|
||||||
Bundle().apply {
|
Bundle().apply {
|
Loading…
Reference in New Issue
Block a user