diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..f519c570 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,31 @@ +## Issue + +- close #TBD + +## Overview + +TBD + +## Details (Optional) + +TBD + +## Screenshots (Optional) + +|Before|After| +|:--:|:--:| +|TBD|TBD| + +## Checklist + +- [ ] Format code (⌥⌘L in Android Studio) +- [ ] Optimize imports (^⌥O in Android Studio) +- [ ] Resolve Android Studio warning + +## What to check (Optional) + +- [ ] TBD + +## Reference(s) (Optional) + +- https://example.com diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fba712b1..9f13a4d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,49 +18,39 @@ on: - LICENSE jobs: - test: + build: runs-on: ubuntu-latest steps: - # チェックアウト - uses: actions/checkout@v2 - # JDKのセットアップ - - name: set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - # Gradleのキャッシュ復元 - - uses: actions/cache@v2 + - uses: ./.github/workflows/templates/setup-android with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} - restore-keys: | - ${{ runner.os }}-gradle- - - # 依存関係の出力 - - name: Displays the Android dependencies of the project - run: ./gradlew androidDependencies + use-cache: true - # コンパイル - name: Run Compile run: ./gradlew assembleDebug - # テスト + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - uses: ./.github/workflows/templates/setup-android + with: + use-cache: true + - name: Test with Gradle run: ./gradlew test --stacktrace - # コードカバレッジをJaCoCo形式で取得 - name: Get code coverage for JaCoCo run: ./gradlew jacocoDevelopDebugTestReport - # コードカバレッジをCodecovへアップロード - name: Upload code coverage to Codecov - run: bash <(curl -s https://codecov.io/bash) - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + uses: codecov/codecov-action@v2 + with: + fail_ci_if_error: true + verbose: true - # テスト結果とコードカバレッジのアップロード - name: Upload test results and code coverage Artifact uses: actions/upload-artifact@v2 if: success() || failure() @@ -76,36 +66,35 @@ jobs: lint: runs-on: ubuntu-latest steps: - # チェックアウト - uses: actions/checkout@v2 - # 静的解析 - name: Run Inspection run: ./gradlew lint - # アーティファクトへアップロード + - name: Show results on GitHub + uses: yutailang0119/action-android-lint@v2 + with: + report-path: '**/build/reports/lint-results-*.xml' + - name: Upload results Artifact uses: actions/upload-artifact@v2 if: success() || failure() with: name: results path: | - **/build/reports/lint-results.html - **/build/reports/lint-results.xml + **/build/reports/lint-results-*.html + **/build/reports/lint-results-*.xml if-no-files-found: error retention-days: 14 detekt: runs-on: ubuntu-latest steps: - # チェックアウト - uses: actions/checkout@v2 - # 静的解析 - name: Lint with detekt run: ./gradlew detekt - # アーティファクトへアップロード - name: Upload results Artifact uses: actions/upload-artifact@v2 if: failure() @@ -116,3 +105,33 @@ jobs: if-no-files-found: error retention-days: 14 + ktlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install ktlint + run: | + curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.42.1/ktlint + chmod a+x ktlint + sudo mv ktlint /usr/local/bin/ + + - name: Lint with ktlint + run: ktlint --reporter=checkstyle,output=build/ktlint-report.xml + continue-on-error: true + + - name: Show results on GitHub + uses: yutailang0119/action-ktlint@v2 + with: + report-path: build/ktlint-report.xml + continue-on-error: true + + - name: Upload results Artifact + uses: actions/upload-artifact@v2 + if: failure() + with: + name: results + path: | + **/build/ktlint-report.xml + if-no-files-found: error + retention-days: 14 diff --git a/.github/workflows/generate-aab.yml b/.github/workflows/generate-aab.yml index 26312427..e8d208d4 100644 --- a/.github/workflows/generate-aab.yml +++ b/.github/workflows/generate-aab.yml @@ -13,31 +13,21 @@ jobs: generate-aab: runs-on: ubuntu-latest steps: - # チェックアウト - uses: actions/checkout@v2 - # JDKのセットアップ - - name: set up JDK 1.8 - uses: actions/setup-java@v1 + - uses: ./.github/workflows/templates/setup-android with: - java-version: 1.8 + use-cache: false - # 依存関係の出力 - - name: Displays the Android dependencies of the project - run: ./gradlew androidDependencies - - # キーストアのデコード - name: Decode Keystore run: echo ${{ secrets.ENCODED_RELEASE_KEYSTORE }} | base64 --decode > ./app/release.keystore - # AABの生成 - name: Generate AAB run: ./gradlew :app:bundleProductionRelease env: RELEASE_KEYSTORE_STORE_PASSWORD: ${{ secrets.RELEASE_KEYSTORE_STORE_PASSWORD }} RELEASE_KEYSTORE_KEY_PASSWORD: ${{ secrets.RELEASE_KEYSTORE_KEY_PASSWORD }} - # AABのアップロード - name: Upload AAB Artifact uses: actions/upload-artifact@v2 with: diff --git a/.github/workflows/templates/setup-android/action.yml b/.github/workflows/templates/setup-android/action.yml new file mode 100644 index 00000000..26477fce --- /dev/null +++ b/.github/workflows/templates/setup-android/action.yml @@ -0,0 +1,29 @@ +name: "Setup for Android" +description: "Install dependencies for Android" + +inputs: + use-cache: + description: "Whether to use cache" + required: true + +runs: + using: "composite" + steps: + - name: Setup JDK 11 + uses: actions/setup-java@v2 + with: + distribution: 'zulu' + java-version: '11' + + - uses: actions/cache@v2 + if: ${{ inputs.use-cache }} + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Displays the Android dependencies of the project + run: ./gradlew androidDependencies + shell: bash + diff --git a/.gitignore b/.gitignore index d035872a..a14bd606 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ .idea/scopes/scope_settings.xml .idea/assetWizardSettings.xml .idea/compiler.xml +.idea/deploymentTargetDropDown.xml .idea/gradle.xml .idea/jarRepositories.xml .idea/misc.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 9c7dcd69..88ea3aa1 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,24 +1,6 @@ - - - diff --git a/.idea/dictionaries/Project.xml b/.idea/dictionaries/Project.xml index c7112900..3b5f6f69 100644 --- a/.idea/dictionaries/Project.xml +++ b/.idea/dictionaries/Project.xml @@ -1,10 +1,14 @@ + appname cardview codecov crashlytics dancingmonster + dorg + endlocal + errorlevel fileprovider firestore imageview @@ -14,13 +18,15 @@ monsterlist mvvm noninfringement + setlocal textview theuhooi uhooi + uhooi's uhooipicbook viewmodel viewmodels webview - + \ No newline at end of file diff --git a/README.md b/README.md index c104f822..8da7e880 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ You can develop this project. ### Environment -- Android Studio: 4.1.3 +- Android Studio: Arctic Fox | 2020.3.1 Patch 4 ### Configuration @@ -55,10 +55,10 @@ You can develop this project. 1. Clone the project. -```shell -$ git clone https://github.com/uhooi/UhooiPicBook-Android.git -$ cd UhooiPicBook-Android -``` + ```shell + $ git clone https://github.com/uhooi/UhooiPicBook-Android.git + $ cd UhooiPicBook-Android + ``` 2. Open the project in Android Studio. @@ -68,3 +68,7 @@ I would be happy if you contribute :) - [New issue](https://github.com/uhooi/UhooiPicBook-Android/issues/new) - [New pull request](https://github.com/uhooi/UhooiPicBook-Android/compare) + +## Stats + +[![Stats](https://repobeats.axiom.co/api/embed/854645b4486364c77380b9cce747b91feb127715.svg "Repobeats analytics image")](https://github.com/uhooi/UhooiPicBook-Android) diff --git a/app/build.gradle b/app/build.gradle index 8fe6ecf1..7aa0ffd8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,28 +1,28 @@ plugins { id 'com.android.application' id 'kotlin-android' - id 'kotlin-android-extensions' + id 'kotlin-parcelize' + id 'kotlin-kapt' id 'androidx.navigation.safeargs.kotlin' + id 'dagger.hilt.android.plugin' id 'com.google.gms.google-services' id 'com.google.firebase.crashlytics' id 'com.google.firebase.firebase-perf' - id 'io.gitlab.arturbosch.detekt' - id 'kotlin-kapt' id 'com.google.android.gms.oss-licenses-plugin' - id 'dagger.hilt.android.plugin' + id 'io.gitlab.arturbosch.detekt' version '1.17.0' id 'jacoco' } android { - compileSdkVersion 29 - buildToolsVersion "29.0.3" + compileSdk 31 + buildToolsVersion "30.0.3" defaultConfig { applicationId "com.theuhooi.uhooipicbook" - minSdkVersion 26 - targetSdkVersion 29 - versionCode 6 - versionName "1.5.0" + minSdk 26 + targetSdk 31 + versionCode 7 + versionName "1.6.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -48,8 +48,13 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '11' } testOptions { @@ -59,12 +64,7 @@ android { } buildFeatures { - dataBinding = true - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + dataBinding true } flavorDimensions 'environment' @@ -81,49 +81,55 @@ android { } dependencies { - def coil_version = '1.1.1' - implementation "io.coil-kt:coil:$coil_version" - implementation "io.coil-kt:coil-base:$coil_version" - implementation "io.coil-kt:coil-gif:$coil_version" + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.4.0' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.2' + + // Lifecycle + implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0' + + // Navigation + implementation "androidx.navigation:navigation-fragment-ktx:$rootProject.nav_version" + implementation "androidx.navigation:navigation-ui-ktx:$rootProject.nav_version" + + implementation 'androidx.recyclerview:recyclerview:1.2.1' + + def coroutines_version = '1.6.0' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutines_version" + + // Hilt + implementation "com.google.dagger:hilt-android:$rootProject.hilt_version" + kapt "com.google.dagger:hilt-android-compiler:$rootProject.hilt_version" + implementation 'androidx.hilt:hilt-navigation-fragment:1.0.0' // Firebase - implementation platform('com.google.firebase:firebase-bom:27.0.0') + implementation platform('com.google.firebase:firebase-bom:29.0.3') implementation 'com.google.firebase:firebase-analytics-ktx' implementation 'com.google.firebase:firebase-crashlytics-ktx' implementation 'com.google.firebase:firebase-firestore-ktx' implementation 'com.google.firebase:firebase-messaging' implementation 'com.google.firebase:firebase-perf' - implementation 'androidx.recyclerview:recyclerview:1.2.0' - - implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" - implementation "androidx.navigation:navigation-ui-ktx:$nav_version" - - def lifecycle_version = '2.2.0' - implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" - - implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.core:core-ktx:1.3.2' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - - implementation 'com.google.android.material:material:1.3.0' - - implementation "com.google.dagger:hilt-android:$rootProject.hilt_version" - kapt "com.google.dagger:hilt-android-compiler:$rootProject.hilt_version" + implementation 'com.google.android.gms:play-services-oss-licenses:17.0.0' - implementation "com.google.android.gms:play-services-oss-licenses:17.0.0" + implementation 'com.jakewharton.timber:timber:5.0.1' - implementation 'com.jakewharton.timber:timber:4.7.1' + def coil_version = '1.4.0' + implementation "io.coil-kt:coil:$coil_version" + implementation "io.coil-kt:coil-base:$coil_version" + implementation "io.coil-kt:coil-gif:$coil_version" - testImplementation 'org.robolectric:robolectric:4.3.1' - testImplementation 'androidx.test:runner:1.3.0' + testImplementation 'org.robolectric:robolectric:4.6.1' + testImplementation 'androidx.test:runner:1.4.0' + testImplementation "androidx.test.ext:junit:1.1.3" // LeakCanary - def leakcanary_version = '2.6' + def leakcanary_version = '2.7' debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakcanary_version" androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:$leakcanary_version" } @@ -133,8 +139,8 @@ kapt { } detekt { - failFast = true buildUponDefaultConfig = true + allRules = false config = files("$projectDir/config/detekt/detekt.yml") baseline = file("$projectDir/config/detekt/baseline.xml") reports { @@ -150,11 +156,15 @@ detekt { enabled = true destination = file("$buildDir/reports/detekt/detekt.txt") } + sarif { + enabled = true + destination = file("$buildDir/reports/detekt/detekt.sarif") + } } } jacoco { - toolVersion = "0.8.6" + toolVersion = "0.8.7" } task jacocoDevelopDebugTestReport(type: JacocoReport, dependsOn: 'testDevelopDebugUnitTest', group: 'verification') { @@ -183,3 +193,15 @@ jacocoDevelopDebugTestReport { } } } + +// Workaround for using the enableAggregatingTask flag. +// ref: https://github.com/google/dagger/issues/2744#issuecomment-901277926 +tasks.named("getDependencies").configure { task -> + def configured = false + project.android.applicationVariants.all { + if (!configured) { + task.inputs.files(project.files(project.configurations.getByName("productionDebugAndroidTestRuntimeClasspath"))) + configured = true + } + } +} diff --git a/app/src/developDebug/ic_launcher-playstore.png b/app/src/developDebug/ic_launcher-playstore.png new file mode 100644 index 00000000..22ccc4de Binary files /dev/null and b/app/src/developDebug/ic_launcher-playstore.png differ diff --git a/app/src/developDebug/res/mipmap-anydpi/ic_launcher.xml b/app/src/developDebug/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 00000000..036d09bc --- /dev/null +++ b/app/src/developDebug/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/developDebug/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/developDebug/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 00000000..036d09bc --- /dev/null +++ b/app/src/developDebug/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/developDebug/res/mipmap-hdpi/ic_launcher.png b/app/src/developDebug/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..4d2a666b Binary files /dev/null and b/app/src/developDebug/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/developDebug/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/developDebug/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..f25b3f25 Binary files /dev/null and b/app/src/developDebug/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/developDebug/res/mipmap-hdpi/ic_launcher_round.png b/app/src/developDebug/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..c803c288 Binary files /dev/null and b/app/src/developDebug/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/developDebug/res/mipmap-mdpi/ic_launcher.png b/app/src/developDebug/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..63216158 Binary files /dev/null and b/app/src/developDebug/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/developDebug/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/developDebug/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..8790beac Binary files /dev/null and b/app/src/developDebug/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/developDebug/res/mipmap-mdpi/ic_launcher_round.png b/app/src/developDebug/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..9d812998 Binary files /dev/null and b/app/src/developDebug/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/developDebug/res/mipmap-xhdpi/ic_launcher.png b/app/src/developDebug/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..3596bad9 Binary files /dev/null and b/app/src/developDebug/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/developDebug/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/developDebug/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..8fd21789 Binary files /dev/null and b/app/src/developDebug/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/developDebug/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/developDebug/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..d15a1573 Binary files /dev/null and b/app/src/developDebug/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/developDebug/res/mipmap-xxhdpi/ic_launcher.png b/app/src/developDebug/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..69f54d70 Binary files /dev/null and b/app/src/developDebug/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/developDebug/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/developDebug/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..2da9b6c8 Binary files /dev/null and b/app/src/developDebug/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/developDebug/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/developDebug/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..ea243539 Binary files /dev/null and b/app/src/developDebug/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/developDebug/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/developDebug/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..b34671fe Binary files /dev/null and b/app/src/developDebug/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/developDebug/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/developDebug/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..c6783692 Binary files /dev/null and b/app/src/developDebug/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/developDebug/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/developDebug/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..b64eb78f Binary files /dev/null and b/app/src/developDebug/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/develop/res/values-en/strings.xml b/app/src/developDebug/res/values-en/strings.xml similarity index 52% rename from app/src/develop/res/values-en/strings.xml rename to app/src/developDebug/res/values-en/strings.xml index 4cff0e73..a13c1216 100644 --- a/app/src/develop/res/values-en/strings.xml +++ b/app/src/developDebug/res/values-en/strings.xml @@ -1,4 +1,4 @@ - dev-UhooiPicBook + devDbg-UhooiPicBook diff --git a/app/src/developDebug/res/values/ic_launcher_background.xml b/app/src/developDebug/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..c5d5899f --- /dev/null +++ b/app/src/developDebug/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/app/src/developDebug/res/values/strings.xml b/app/src/developDebug/res/values/strings.xml new file mode 100644 index 00000000..e9ddc5f4 --- /dev/null +++ b/app/src/developDebug/res/values/strings.xml @@ -0,0 +1,4 @@ + + + devDbg-ウホーイ図鑑 + diff --git a/app/src/developRelease/ic_launcher-playstore.png b/app/src/developRelease/ic_launcher-playstore.png new file mode 100644 index 00000000..85d6e065 Binary files /dev/null and b/app/src/developRelease/ic_launcher-playstore.png differ diff --git a/app/src/developRelease/res/mipmap-anydpi/ic_launcher.xml b/app/src/developRelease/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 00000000..036d09bc --- /dev/null +++ b/app/src/developRelease/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/developRelease/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/developRelease/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 00000000..036d09bc --- /dev/null +++ b/app/src/developRelease/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/developRelease/res/mipmap-hdpi/ic_launcher.png b/app/src/developRelease/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..97af1f70 Binary files /dev/null and b/app/src/developRelease/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/developRelease/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/developRelease/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..dde65549 Binary files /dev/null and b/app/src/developRelease/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/developRelease/res/mipmap-hdpi/ic_launcher_round.png b/app/src/developRelease/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..7d053ea8 Binary files /dev/null and b/app/src/developRelease/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/developRelease/res/mipmap-mdpi/ic_launcher.png b/app/src/developRelease/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..b42dbed0 Binary files /dev/null and b/app/src/developRelease/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/developRelease/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/developRelease/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..d8610153 Binary files /dev/null and b/app/src/developRelease/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/developRelease/res/mipmap-mdpi/ic_launcher_round.png b/app/src/developRelease/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..c13f54ac Binary files /dev/null and b/app/src/developRelease/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/developRelease/res/mipmap-xhdpi/ic_launcher.png b/app/src/developRelease/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..fd95fdcd Binary files /dev/null and b/app/src/developRelease/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/developRelease/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/developRelease/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..d12a6f1f Binary files /dev/null and b/app/src/developRelease/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/developRelease/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/developRelease/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..e3203126 Binary files /dev/null and b/app/src/developRelease/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/developRelease/res/mipmap-xxhdpi/ic_launcher.png b/app/src/developRelease/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..698f13b4 Binary files /dev/null and b/app/src/developRelease/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/developRelease/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/developRelease/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..ea020564 Binary files /dev/null and b/app/src/developRelease/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/developRelease/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/developRelease/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..94608432 Binary files /dev/null and b/app/src/developRelease/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/developRelease/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/developRelease/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..37183aab Binary files /dev/null and b/app/src/developRelease/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/developRelease/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/developRelease/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..2bf128fa Binary files /dev/null and b/app/src/developRelease/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/developRelease/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/developRelease/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..4e659c77 Binary files /dev/null and b/app/src/developRelease/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/develop/res/values/strings.xml b/app/src/developRelease/res/values-en/strings.xml similarity index 51% rename from app/src/develop/res/values/strings.xml rename to app/src/developRelease/res/values-en/strings.xml index 168214b3..49640ef9 100644 --- a/app/src/develop/res/values/strings.xml +++ b/app/src/developRelease/res/values-en/strings.xml @@ -1,4 +1,4 @@ - dev-ウホーイ図鑑 + devRls-UhooiPicBook diff --git a/app/src/developRelease/res/values/ic_launcher_background.xml b/app/src/developRelease/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..c5d5899f --- /dev/null +++ b/app/src/developRelease/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/app/src/developRelease/res/values/strings.xml b/app/src/developRelease/res/values/strings.xml new file mode 100644 index 00000000..41184a50 --- /dev/null +++ b/app/src/developRelease/res/values/strings.xml @@ -0,0 +1,4 @@ + + + devRls-ウホーイ図鑑 + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7760895f..92a00be7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ @@ -15,9 +16,11 @@ android:supportsRtl="true" android:theme="@style/Theme.UhooiPicBook"> + android:theme="@style/Theme.UhooiPicBook.NoActionBar" + tools:ignore="LockedOrientationActivity" + android:exported="true"> diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png index 94480464..36536712 100644 Binary files a/app/src/main/ic_launcher-playstore.png and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/UhooiPicBookApp.kt b/app/src/main/java/com/theuhooi/uhooipicbook/UhooiPicBookApp.kt index 28971f0c..6a4cf4d6 100644 --- a/app/src/main/java/com/theuhooi/uhooipicbook/UhooiPicBookApp.kt +++ b/app/src/main/java/com/theuhooi/uhooipicbook/UhooiPicBookApp.kt @@ -76,7 +76,7 @@ class UhooiPicBookApp : Application() { } .componentRegistry { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - add(ImageDecoderDecoder()) + add(ImageDecoderDecoder(applicationContext)) } else { add(GifDecoder()) } diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/data/Result.kt b/app/src/main/java/com/theuhooi/uhooipicbook/data/Result.kt new file mode 100644 index 00000000..0f295a70 --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/data/Result.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * 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 + * + * https://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 com.theuhooi.uhooipicbook.data + +/** + * A generic class that holds a value or an exception + */ +sealed class Result { + data class Success(val data: T) : Result() + data class Error(val exception: Exception) : Result() +} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/data/monsters/MonstersRepository.kt b/app/src/main/java/com/theuhooi/uhooipicbook/data/monsters/MonstersRepository.kt new file mode 100644 index 00000000..be813cc6 --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/data/monsters/MonstersRepository.kt @@ -0,0 +1,8 @@ +package com.theuhooi.uhooipicbook.data.monsters + +import com.theuhooi.uhooipicbook.data.Result +import com.theuhooi.uhooipicbook.data.monsters.impl.MonsterDto + +interface MonstersRepository { + suspend fun fetchMonsters(): Result> +} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/entities/MonsterItem.kt b/app/src/main/java/com/theuhooi/uhooipicbook/data/monsters/impl/MonsterDto.kt similarity index 71% rename from app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/entities/MonsterItem.kt rename to app/src/main/java/com/theuhooi/uhooipicbook/data/monsters/impl/MonsterDto.kt index 7ae4fe8b..855953b8 100644 --- a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/entities/MonsterItem.kt +++ b/app/src/main/java/com/theuhooi/uhooipicbook/data/monsters/impl/MonsterDto.kt @@ -1,11 +1,8 @@ -package com.theuhooi.uhooipicbook.modules.monsterlist.entities +package com.theuhooi.uhooipicbook.data.monsters.impl -import android.os.Parcelable import com.google.firebase.firestore.PropertyName -import kotlinx.android.parcel.Parcelize -@Parcelize -data class MonsterItem( +data class MonsterDto( val name: String = "", val description: String = "", @get:PropertyName("base_color") @@ -18,4 +15,4 @@ data class MonsterItem( @set:PropertyName("dancing_url") var dancingUrlString: String = "", val order: Int = 0 -) : Parcelable +) diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/data/monsters/impl/MonstersFirestoreClient.kt b/app/src/main/java/com/theuhooi/uhooipicbook/data/monsters/impl/MonstersFirestoreClient.kt new file mode 100644 index 00000000..1abe5931 --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/data/monsters/impl/MonstersFirestoreClient.kt @@ -0,0 +1,42 @@ +package com.theuhooi.uhooipicbook.data.monsters.impl + +import com.google.firebase.firestore.FirebaseFirestoreException +import com.google.firebase.firestore.ktx.firestore +import com.google.firebase.ktx.Firebase +import com.theuhooi.uhooipicbook.data.Result +import com.theuhooi.uhooipicbook.data.monsters.MonstersRepository +import com.theuhooi.uhooipicbook.di.IoDispatcher +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.tasks.await +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class MonstersFirestoreClient @Inject constructor( + @IoDispatcher private val ioDispatcher: CoroutineDispatcher +) : MonstersRepository { + + // region Stored Instance Properties + + private val firestore = Firebase.firestore + + // endregion + + // region MonstersRepository + + override suspend fun fetchMonsters(): Result> { + return withContext(ioDispatcher) { + val querySnapshot = try { + firestore.collection("monsters") + .orderBy(MonsterDto::order.name) + .get() + .await() + } catch (e: FirebaseFirestoreException) { + return@withContext Result.Error(e) + } + Result.Success(querySnapshot.toObjects(MonsterDto::class.java)) + } + } + + // endregion + +} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/di/AppModule.kt b/app/src/main/java/com/theuhooi/uhooipicbook/di/AppModule.kt index c6770b21..187fec76 100644 --- a/app/src/main/java/com/theuhooi/uhooipicbook/di/AppModule.kt +++ b/app/src/main/java/com/theuhooi/uhooipicbook/di/AppModule.kt @@ -1,7 +1,7 @@ package com.theuhooi.uhooipicbook.di -import com.theuhooi.uhooipicbook.modules.monsterlist.MonstersRepository -import com.theuhooi.uhooipicbook.repository.monsters.firebase.MonstersFirestoreClient +import com.theuhooi.uhooipicbook.data.monsters.MonstersRepository +import com.theuhooi.uhooipicbook.data.monsters.impl.MonstersFirestoreClient import dagger.Binds import dagger.Module import dagger.hilt.InstallIn diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/di/CoroutinesModule.kt b/app/src/main/java/com/theuhooi/uhooipicbook/di/CoroutinesModule.kt new file mode 100644 index 00000000..0c305487 --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/di/CoroutinesModule.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2019 Google LLC + * + * 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 + * + * https://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 com.theuhooi.uhooipicbook.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + +@InstallIn(SingletonComponent::class) +@Module +object CoroutinesModule { + + @IoDispatcher + @Provides + fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO +} \ No newline at end of file diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/di/CoroutinesQualifiers.kt b/app/src/main/java/com/theuhooi/uhooipicbook/di/CoroutinesQualifiers.kt new file mode 100644 index 00000000..9f3e97a1 --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/di/CoroutinesQualifiers.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2019 Google LLC + * + * 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 + * + * https://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 com.theuhooi.uhooipicbook.di + +import javax.inject.Qualifier + +@Retention(AnnotationRetention.BINARY) +@Qualifier +annotation class IoDispatcher diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/domain/models/MonsterItem.kt b/app/src/main/java/com/theuhooi/uhooipicbook/domain/models/MonsterItem.kt new file mode 100644 index 00000000..695514b1 --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/domain/models/MonsterItem.kt @@ -0,0 +1,39 @@ +package com.theuhooi.uhooipicbook.domain.models + +import android.os.Parcelable +import androidx.recyclerview.widget.DiffUtil +import com.theuhooi.uhooipicbook.data.monsters.impl.MonsterDto +import kotlinx.parcelize.Parcelize + +@Parcelize +data class MonsterItem( + val name: String, + val description: String, + val baseColorCode: String, + val iconUrlString: String, + val dancingUrlString: String, + val order: Int +) : Parcelable { + companion object { + val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: MonsterItem, newItem: MonsterItem): Boolean { + return oldItem.order == newItem.order + } + + override fun areContentsTheSame(oldItem: MonsterItem, newItem: MonsterItem): Boolean { + return oldItem == newItem + } + } + + internal fun create(dto: MonsterDto): MonsterItem { + return MonsterItem( + dto.name, + dto.description, + dto.baseColorCode, + dto.iconUrlString, + dto.dancingUrlString, + dto.order + ) + } + } +} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/MonsterListRecyclerViewAdapter.kt b/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/MonsterListRecyclerViewAdapter.kt deleted file mode 100644 index ea454a13..00000000 --- a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/MonsterListRecyclerViewAdapter.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.theuhooi.uhooipicbook.modules.monsterlist - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LiveData -import androidx.recyclerview.widget.RecyclerView -import com.theuhooi.uhooipicbook.databinding.ItemMonsterListBinding -import com.theuhooi.uhooipicbook.modules.monsterlist.MonsterListFragment.OnListFragmentInteractionListener -import com.theuhooi.uhooipicbook.modules.monsterlist.entities.MonsterItem - -class MonsterListRecyclerViewAdapter( - private val listener: OnListFragmentInteractionListener?, - private val monsters: LiveData>, - private val viewLifecycleOwner: LifecycleOwner -) : RecyclerView.Adapter() { - - // region Stored Instance Properties - - private val onClickListener = View.OnClickListener { v -> - val item = v.tag as MonsterItem - this.listener?.onListFragmentInteraction(item) - } - - // endregion - - // region View Life-Cycle Methods - - override fun onCreateViewHolder( - parent: ViewGroup, - viewType: Int - ): MonsterListRecyclerViewHolder { - val binding = ItemMonsterListBinding.inflate( - LayoutInflater.from(parent.context), parent, false - ) - return MonsterListRecyclerViewHolder(binding) - } - - override fun onBindViewHolder(holder: MonsterListRecyclerViewHolder, position: Int) { - holder.binding.lifecycleOwner = this.viewLifecycleOwner - val monster = this.monsters.value?.get(position) - holder.binding.monsterItem = monster - holder.binding.cardView.tag = monster - holder.binding.cardView.setOnClickListener(this.onClickListener) - } - - override fun getItemCount(): Int = this.monsters.value?.size ?: 0 - - // endregion - - // region ViewHolder - - class MonsterListRecyclerViewHolder(val binding: ItemMonsterListBinding) : RecyclerView.ViewHolder(binding.root) - - // endregion - -} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/MonstersRepository.kt b/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/MonstersRepository.kt deleted file mode 100644 index cf90912e..00000000 --- a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/MonstersRepository.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.theuhooi.uhooipicbook.modules.monsterlist - -import com.theuhooi.uhooipicbook.modules.monsterlist.entities.MonsterItem - -interface MonstersRepository { - fun loadMonsters( - onSuccess: (monsters: List) -> Unit, - onFailure: (error: Throwable) -> Unit - ) -} - diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/viewmodels/MonsterListViewModel.kt b/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/viewmodels/MonsterListViewModel.kt deleted file mode 100644 index 980352ef..00000000 --- a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/viewmodels/MonsterListViewModel.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.theuhooi.uhooipicbook.modules.monsterlist.viewmodels - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.theuhooi.uhooipicbook.modules.monsterlist.MonstersRepository -import com.theuhooi.uhooipicbook.modules.monsterlist.entities.MonsterItem -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject - -@HiltViewModel -class MonsterListViewModel @Inject constructor( - private val repository: MonstersRepository -) : ViewModel() { - - // region Stored Instance Properties - - private val _monsters = MutableLiveData>() - val monsters: LiveData> - get() = _monsters - - private val _isLoading = MutableLiveData(false) - val isLoading: LiveData - get() = _isLoading - - // endregion - - // region Initializers - - init { - loadMonsters() - } - - // endregion - - // region Other Private Methods - - private fun loadMonsters() { - _isLoading.value = true - this.repository.loadMonsters( - onSuccess = { monsters -> - _monsters.value = monsters - _isLoading.value = false - }, - onFailure = { - // TODO: エラーハンドリング - } - ) - } - - // endregion - -} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/notification/services/MessagingService.kt b/app/src/main/java/com/theuhooi/uhooipicbook/notification/services/MessagingService.kt index 3592c2ae..eb43c2b8 100644 --- a/app/src/main/java/com/theuhooi/uhooipicbook/notification/services/MessagingService.kt +++ b/app/src/main/java/com/theuhooi/uhooipicbook/notification/services/MessagingService.kt @@ -9,7 +9,7 @@ import android.media.RingtoneManager import androidx.core.app.NotificationCompat import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage -import com.theuhooi.uhooipicbook.MainActivity +import com.theuhooi.uhooipicbook.ui.MainActivity import com.theuhooi.uhooipicbook.R class MessagingService : FirebaseMessagingService() { diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/repository/monsters/firebase/MonstersFirestoreClient.kt b/app/src/main/java/com/theuhooi/uhooipicbook/repository/monsters/firebase/MonstersFirestoreClient.kt deleted file mode 100644 index a57d7dc3..00000000 --- a/app/src/main/java/com/theuhooi/uhooipicbook/repository/monsters/firebase/MonstersFirestoreClient.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.theuhooi.uhooipicbook.repository.monsters.firebase - -import com.google.firebase.firestore.ktx.firestore -import com.google.firebase.firestore.ktx.toObjects -import com.google.firebase.ktx.Firebase -import com.theuhooi.uhooipicbook.modules.monsterlist.MonstersRepository -import com.theuhooi.uhooipicbook.modules.monsterlist.entities.MonsterItem -import javax.inject.Inject - -class MonstersFirestoreClient @Inject constructor() : MonstersRepository { - - // region Stored Instance Properties - - private val firestore = Firebase.firestore - - // endregion - - // region MonstersRepository - - override fun loadMonsters( - onSuccess: (monsters: List) -> Unit, - onFailure: (error: Throwable) -> Unit - ) { - this.firestore.collection("monsters") - .orderBy(MonsterItem::order.name) - .get() - .addOnSuccessListener { result -> - onSuccess(result.toObjects()) - } - .addOnFailureListener { exception -> - onFailure(exception) - } - } - - // endregion - -} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/MainActivity.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/MainActivity.kt similarity index 59% rename from app/src/main/java/com/theuhooi/uhooipicbook/MainActivity.kt rename to app/src/main/java/com/theuhooi/uhooipicbook/ui/MainActivity.kt index d037ca12..70e61902 100644 --- a/app/src/main/java/com/theuhooi/uhooipicbook/MainActivity.kt +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/MainActivity.kt @@ -1,7 +1,6 @@ -package com.theuhooi.uhooipicbook +package com.theuhooi.uhooipicbook.ui import android.content.Intent -import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.net.Uri import android.os.Bundle @@ -10,22 +9,18 @@ import androidx.navigation.findNavController import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.setupActionBarWithNavController import com.google.android.material.color.MaterialColors -import com.theuhooi.uhooipicbook.extensions.IntColorInterface -import com.theuhooi.uhooipicbook.modules.monsterlist.MonsterListFragment -import com.theuhooi.uhooipicbook.modules.monsterlist.MonsterListFragmentDirections -import com.theuhooi.uhooipicbook.modules.monsterlist.entities.MonsterItem +import com.theuhooi.uhooipicbook.R import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class MainActivity : AppCompatActivity(), MonsterListFragment.OnListFragmentInteractionListener, - IntColorInterface { +class MainActivity : AppCompatActivity() { // region View Life-Cycle Methods override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + setContentView(R.layout.main_activity) configureToolBar() openNotificationUrlIfNeeded() @@ -43,7 +38,7 @@ class MainActivity : AppCompatActivity(), MonsterListFragment.OnListFragmentInte val navController = findNavController(R.id.nav_host_fragment) navController.addOnDestinationChangedListener { _, destination, _ -> if (destination.id == R.id.monster_list_fragment) { - this.supportActionBar?.setBackgroundDrawable( + supportActionBar?.setBackgroundDrawable( ColorDrawable( MaterialColors.getColor( this, @@ -52,7 +47,7 @@ class MainActivity : AppCompatActivity(), MonsterListFragment.OnListFragmentInte ) ) ) - this.window.statusBarColor = MaterialColors.getColor( + window.statusBarColor = MaterialColors.getColor( this, R.attr.colorPrimaryVariant, "colorPrimaryVariant is not set in the current theme" @@ -64,7 +59,7 @@ class MainActivity : AppCompatActivity(), MonsterListFragment.OnListFragmentInte } private fun openNotificationUrlIfNeeded() { - val urlString = this.intent.getStringExtra(getString(R.string.notification_url_extra_name)) + val urlString = intent.getStringExtra(getString(R.string.notification_url_extra_name)) if (urlString != null) { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(urlString)) startActivity(intent) @@ -73,19 +68,4 @@ class MainActivity : AppCompatActivity(), MonsterListFragment.OnListFragmentInte // endregion - // region MonsterListFragment.OnListFragmentInteractionListener - - override fun onListFragmentInteraction(item: MonsterItem) { - val action = MonsterListFragmentDirections.actionListToDetail(item) - findNavController(R.id.nav_host_fragment).navigate(action) - - if (item.baseColorCode.isNotEmpty()) { - val actionBarColor = Color.parseColor(item.baseColorCode) - this.supportActionBar?.setBackgroundDrawable(ColorDrawable(actionBarColor)) - this.window.statusBarColor = actionBarColor.actionBarColorToStatusBarColor - } - } - - // endregion - } diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterdetail/dancingmonster/DancingMonsterFragment.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/dancingmonster/DancingMonsterFragment.kt similarity index 55% rename from app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterdetail/dancingmonster/DancingMonsterFragment.kt rename to app/src/main/java/com/theuhooi/uhooipicbook/ui/dancingmonster/DancingMonsterFragment.kt index 60841e52..eacc619a 100644 --- a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterdetail/dancingmonster/DancingMonsterFragment.kt +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/dancingmonster/DancingMonsterFragment.kt @@ -1,23 +1,24 @@ -package com.theuhooi.uhooipicbook.modules.monsterdetail.dancingmonster +package com.theuhooi.uhooipicbook.ui.dancingmonster import android.graphics.Color import android.graphics.drawable.ColorDrawable +import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.WindowInsets import android.view.WindowManager import androidx.appcompat.app.AppCompatDialogFragment import androidx.navigation.fragment.navArgs -import coil.load -import com.theuhooi.uhooipicbook.R -import kotlinx.android.synthetic.main.fragment_dancing_monster.view.* +import com.theuhooi.uhooipicbook.databinding.DancingMonsterFragmentBinding class DancingMonsterFragment : AppCompatDialogFragment() { // region Stored Instance Properties - private val args: DancingMonsterFragmentArgs by navArgs() + private var _binding: DancingMonsterFragmentBinding? = null + private val binding get() = _binding!! // endregion @@ -28,23 +29,38 @@ class DancingMonsterFragment : AppCompatDialogFragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View { - return inflater.inflate(R.layout.fragment_dancing_monster, container, false) + _binding = DancingMonsterFragmentBinding.inflate(inflater, container, false) + + val args: DancingMonsterFragmentArgs by navArgs() + binding.args = args + + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - view.dancing_imageview.load(this.args.dancingUrlString) - view.close_button.setOnClickListener { dismiss() } + binding.closeButton.setOnClickListener { dismiss() } + } + + override fun onDestroyView() { + super.onDestroyView() + + _binding = null } override fun onStart() { super.onStart() + dialog?.window?.apply { - setFlags( - WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + insetsController?.hide(WindowInsets.Type.statusBars()) + } else { + setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + ) + } setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) val layoutParams = attributes.apply { width = WindowManager.LayoutParams.MATCH_PARENT diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterdetail/MonsterDetailFragment.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterdetail/MonsterDetailFragment.kt similarity index 63% rename from app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterdetail/MonsterDetailFragment.kt rename to app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterdetail/MonsterDetailFragment.kt index 88cfccd7..12780ef9 100644 --- a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterdetail/MonsterDetailFragment.kt +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterdetail/MonsterDetailFragment.kt @@ -1,69 +1,83 @@ -package com.theuhooi.uhooipicbook.modules.monsterdetail +package com.theuhooi.uhooipicbook.ui.monsterdetail import android.content.Context import android.graphics.Bitmap +import android.graphics.Color import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.net.Uri import android.os.Bundle -import android.view.LayoutInflater import android.view.Menu import android.view.MenuInflater import android.view.View -import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ShareCompat import androidx.core.content.FileProvider import androidx.fragment.app.Fragment +import androidx.hilt.navigation.fragment.hiltNavGraphViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import coil.ImageLoader -import coil.load import coil.request.Disposable import coil.request.ImageRequest import com.theuhooi.uhooipicbook.R -import kotlinx.android.synthetic.main.fragment_monster_detail.view.* +import com.theuhooi.uhooipicbook.databinding.MonsterDetailFragmentBinding +import com.theuhooi.uhooipicbook.domain.models.MonsterItem +import com.theuhooi.uhooipicbook.extensions.IntColorInterface +import com.theuhooi.uhooipicbook.ui.monsterlist.MonsterViewModel import java.io.File import java.io.FileOutputStream -class MonsterDetailFragment : Fragment() { +class MonsterDetailFragment : Fragment(R.layout.monster_detail_fragment), IntColorInterface { // region Stored Instance Properties private val args: MonsterDetailFragmentArgs by navArgs() + private val viewModel: MonsterViewModel by hiltNavGraphViewModels(R.id.monster_nav_graph) + private var disposable: Disposable? = null // endregion - // region View Life-Cycle Methods + // region Computed Instance Properties - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - setHasOptionsMenu(true) - return inflater.inflate(R.layout.fragment_monster_detail, container, false) - } + private val monster: MonsterItem by lazy { viewModel.findMonster(args.monsterOrder) } + + // endregion + + // region View Life-Cycle Methods override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - view.icon_imageview.load(this.args.monster.iconUrlString) - view.dancing_imageview.load(this.args.monster.dancingUrlString) - view.dancing_imageview.setOnClickListener { + setHasOptionsMenu(true) + + val binding = MonsterDetailFragmentBinding.bind(view) + binding.monster = monster + + binding.dancingImageview.setOnClickListener { val action = - MonsterDetailFragmentDirections.actionDetailToDancing(this.args.monster.dancingUrlString) + MonsterDetailFragmentDirections.actionDetailToDancing(monster.dancingUrlString) findNavController().navigate(action) } - view.name_textview.text = this.args.monster.name - view.description_textview.text = unescapeNewline(this.args.monster.description) + + val baseColorCode = monster.baseColorCode + if (baseColorCode.isNotEmpty()) { + val activity = requireActivity() + val actionBarColor = Color.parseColor(baseColorCode) + (activity as AppCompatActivity).supportActionBar?.setBackgroundDrawable( + ColorDrawable(actionBarColor) + ) + activity.window.statusBarColor = actionBarColor.actionBarColorToStatusBarColor + } } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) - inflater.inflate(R.menu.menu_monster_detail, menu) + inflater.inflate(R.menu.monster_detail_menu, menu) val shareMenuItem = menu.findItem(R.id.share_menu_item) shareMenuItem.setOnMenuItemClickListener { shareMonster() @@ -74,7 +88,7 @@ class MonsterDetailFragment : Fragment() { override fun onDestroyOptionsMenu() { super.onDestroyOptionsMenu() - this.disposable?.dispose() + disposable?.dispose() } // endregion @@ -82,13 +96,11 @@ class MonsterDetailFragment : Fragment() { // region Other Private Methods private fun shareMonster() { - val monster = this.args.monster val context = requireContext() val request = ImageRequest.Builder(context) .data(monster.iconUrlString) .target { drawable -> - ShareCompat.IntentBuilder - .from(requireActivity()) + ShareCompat.IntentBuilder(context) .setText(monster.name + "\n" + unescapeNewline(monster.description) + "\n#UhooiPicBook") .setStream(createTempPngFileUri(context, drawable)) .setType("image/png") @@ -96,7 +108,7 @@ class MonsterDetailFragment : Fragment() { .startChooser() } .build() - this.disposable = ImageLoader(context).enqueue(request) + disposable = ImageLoader(context).enqueue(request) } private fun createTempPngFileUri(context: Context, drawable: Drawable): Uri? { diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterlist/MonsterListAdapter.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterlist/MonsterListAdapter.kt new file mode 100644 index 00000000..d9954e06 --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterlist/MonsterListAdapter.kt @@ -0,0 +1,52 @@ +package com.theuhooi.uhooipicbook.ui.monsterlist + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.navigation.findNavController +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.theuhooi.uhooipicbook.databinding.MonsterListItemBinding +import com.theuhooi.uhooipicbook.domain.models.MonsterItem + +class MonsterListAdapter : + ListAdapter(MonsterItem.DIFF_CALLBACK) { + + // region View Life-Cycle Methods + + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): MonsterViewHolder { + val binding = MonsterListItemBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + return MonsterViewHolder(binding) + } + + override fun onBindViewHolder(holder: MonsterViewHolder, position: Int) { + holder.bind(getItem(position)) + } + + // endregion + + // region ViewHolder + + class MonsterViewHolder(val binding: MonsterListItemBinding) : + RecyclerView.ViewHolder(binding.root) { + private val onClickListener = View.OnClickListener { view -> + val item = view.tag as MonsterItem + val action = MonsterListFragmentDirections.actionListToDetail(item.order) + view.findNavController().navigate(action) + } + + fun bind(monster: MonsterItem) { + binding.monsterItem = monster + binding.cardView.tag = monster + binding.cardView.setOnClickListener(onClickListener) + } + } + + // endregion + +} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/MonsterListFragment.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterlist/MonsterListFragment.kt similarity index 51% rename from app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/MonsterListFragment.kt rename to app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterlist/MonsterListFragment.kt index 6ace9f94..fac1b1fc 100644 --- a/app/src/main/java/com/theuhooi/uhooipicbook/modules/monsterlist/MonsterListFragment.kt +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterlist/MonsterListFragment.kt @@ -1,89 +1,78 @@ -package com.theuhooi.uhooipicbook.modules.monsterlist +package com.theuhooi.uhooipicbook.ui.monsterlist -import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle -import android.view.LayoutInflater import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View -import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels +import androidx.hilt.navigation.fragment.hiltNavGraphViewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager +import androidx.transition.TransitionManager import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.theuhooi.uhooipicbook.BuildConfig import com.theuhooi.uhooipicbook.R -import com.theuhooi.uhooipicbook.databinding.FragmentMonsterListBinding -import com.theuhooi.uhooipicbook.modules.monsterlist.entities.MonsterItem -import com.theuhooi.uhooipicbook.modules.monsterlist.viewmodels.MonsterListViewModel +import com.theuhooi.uhooipicbook.databinding.MonsterListFragmentBinding +import com.theuhooi.uhooipicbook.ui.motion.Stagger import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch @AndroidEntryPoint -class MonsterListFragment : Fragment() { +class MonsterListFragment : Fragment(R.layout.monster_list_fragment) { // region Stored Instance Properties - private var listener: OnListFragmentInteractionListener? = null - - private val viewModel: MonsterListViewModel by viewModels() + private val viewModel: MonsterViewModel by hiltNavGraphViewModels(R.id.monster_nav_graph) // endregion // region View Life-Cycle Methods - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - setHasOptionsMenu(true) - val binding = FragmentMonsterListBinding.inflate(inflater, container, false) - binding.monsterListRecyclerview.adapter = - MonsterListRecyclerViewAdapter( - this.listener, - this.viewModel.monsters, - this.viewLifecycleOwner - ) - binding.monsterListRecyclerview.layoutManager = LinearLayoutManager(this.context) - binding.viewModel = this.viewModel - binding.lifecycleOwner = this.viewLifecycleOwner - return binding.root - } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) - override fun onAttach(context: Context) { - super.onAttach(context) + setHasOptionsMenu(true) - if (context is OnListFragmentInteractionListener) { - this.listener = context - } else { - throw RuntimeException("$context must implement OnListFragmentInteractionListener") + val binding = MonsterListFragmentBinding.bind(view) + val list = binding.monsterListRecyclerview + val adapter = MonsterListAdapter() + list.adapter = adapter + list.layoutManager = LinearLayoutManager(context) + binding.viewModel = viewModel + binding.lifecycleOwner = viewLifecycleOwner + + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.uiState.collect { + TransitionManager.beginDelayedTransition(list, Stagger()) + adapter.submitList(it.monsterItems) + } + } } } - override fun onDetach() { - super.onDetach() - - this.listener = null - } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) - inflater.inflate(R.menu.menu_monster_list, menu) + inflater.inflate(R.menu.monster_list_menu, menu) } override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.contact_us_menu_item -> { - val action = MonsterListFragmentDirections.actionListToWebView(getString(R.string.contact_us_url)) + val action = + MonsterListFragmentDirections.actionListToWebView(getString(R.string.contact_us_url)) findNavController().navigate(action) true } R.id.privacy_policy_menu_item -> { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.privacy_policy_url))) + val intent = + Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.privacy_policy_url))) startActivity(intent) true } @@ -113,12 +102,4 @@ class MonsterListFragment : Fragment() { // endregion - // region Interfaces - - interface OnListFragmentInteractionListener { - fun onListFragmentInteraction(item: MonsterItem) - } - - // endregion - } diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterlist/MonsterViewModel.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterlist/MonsterViewModel.kt new file mode 100644 index 00000000..04e9f2c7 --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/monsterlist/MonsterViewModel.kt @@ -0,0 +1,68 @@ +package com.theuhooi.uhooipicbook.ui.monsterlist + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.theuhooi.uhooipicbook.data.Result +import com.theuhooi.uhooipicbook.data.monsters.MonstersRepository +import com.theuhooi.uhooipicbook.domain.models.MonsterItem +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + +data class MonsterUiState( + val isLoading: Boolean = false, + val monsterItems: List = listOf() +) + +@HiltViewModel +class MonsterViewModel @Inject constructor( + private val repository: MonstersRepository +) : ViewModel() { + + // region Stored Instance Properties + + private val _uiState = MutableStateFlow(MonsterUiState(isLoading = true)) + val uiState: StateFlow = _uiState.asStateFlow() + + // endregion + + // region Initializers + + init { + refreshMonsters() + } + + // endregion + + // region Other Public Methods + + fun findMonster(order: Int): MonsterItem = + requireNotNull(uiState.value.monsterItems.find { it.order == order }) + + // endregion + + // region Other Private Methods + + private fun refreshMonsters() { + _uiState.update { it.copy(isLoading = true) } + viewModelScope.launch { + val result = repository.fetchMonsters() + _uiState.update { + when (result) { + is Result.Success -> it.copy( + monsterItems = result.data.map { dto -> MonsterItem.create(dto) }, + isLoading = false + ) + is Result.Error -> it.copy(isLoading = false) // TODO: エラーハンドリング + } + } + } + } + + // endregion + +} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/ui/motion/Durations.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/motion/Durations.kt new file mode 100644 index 00000000..5d7af5fe --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/motion/Durations.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * 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 com.theuhooi.uhooipicbook.ui.motion + +// Animation durations. +// See https://material.io/design/motion/speed.html#duration for the detail. + +const val LARGE_EXPAND_DURATION = 300L diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/ui/motion/Interpolators.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/motion/Interpolators.kt new file mode 100644 index 00000000..228c1644 --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/motion/Interpolators.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * 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 com.theuhooi.uhooipicbook.ui.motion + +import android.animation.TimeInterpolator +import androidx.core.view.animation.PathInterpolatorCompat + +/** + * Decelerate easing. + * + * Incoming elements are animated using deceleration easing, which starts a transition at peak + * velocity (the fastest point of an element’s movement) and ends at rest. + */ +val LINEAR_OUT_SLOW_IN: TimeInterpolator by lazy(LazyThreadSafetyMode.NONE) { + PathInterpolatorCompat.create(0f, 0f, 0.2f, 1f) +} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/ui/motion/Stagger.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/motion/Stagger.kt new file mode 100644 index 00000000..4d04c50f --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/motion/Stagger.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * 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 com.theuhooi.uhooipicbook.ui.motion + +import android.animation.Animator +import android.animation.AnimatorSet +import android.animation.ObjectAnimator +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import androidx.transition.Fade +import androidx.transition.SidePropagation +import androidx.transition.TransitionValues + +/** + * Transition for stagger effect. + */ +// We extend Fade, so fade-in effect is handled by the parent. We customize and add a slight +// slide-up effect to it. +class Stagger : Fade(IN) { + + init { + // This duration is for a single item. See the comment below about propagation. + duration = LARGE_EXPAND_DURATION / 2 + interpolator = LINEAR_OUT_SLOW_IN + propagation = SidePropagation().apply { + setSide(Gravity.BOTTOM) + // We want the stagger effect to take as long as the duration of a single item. + // In other words, the last item starts to fade in around the time when the first item + // finishes animating. The overall animation will take about twice the duration of one + // item fading in. + setPropagationSpeed(1f) + } + } + + override fun createAnimator( + sceneRoot: ViewGroup, + startValues: TransitionValues?, + endValues: TransitionValues? + ): Animator? { + val view = startValues?.view ?: endValues?.view ?: return null + // The parent can create an Animator for the fade-in. + val fadeAnimator = super.createAnimator(sceneRoot, startValues, endValues) ?: return null + return AnimatorSet().apply { + playTogether( + fadeAnimator, + // We make the view to slide up a little as it fades in. + ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, view.height * 0.5f, 0f) + ) + } + } +} diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/util/ViewBindingAdapters.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/utils/ViewBindingAdapters.kt similarity index 89% rename from app/src/main/java/com/theuhooi/uhooipicbook/util/ViewBindingAdapters.kt rename to app/src/main/java/com/theuhooi/uhooipicbook/ui/utils/ViewBindingAdapters.kt index 5d75939a..2600be8e 100644 --- a/app/src/main/java/com/theuhooi/uhooipicbook/util/ViewBindingAdapters.kt +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/utils/ViewBindingAdapters.kt @@ -1,4 +1,4 @@ -package com.theuhooi.uhooipicbook.util +package com.theuhooi.uhooipicbook.ui.utils import android.view.View import android.view.View.GONE @@ -18,6 +18,7 @@ fun load(imageView: ImageView, imageUrl: String?) { imageView.load(imageUrl) } +@Suppress("UnusedPrivateMember") @BindingAdapter("observedList") fun observeList(recyclerView: RecyclerView, observedList: List?) { recyclerView.adapter?.notifyDataSetChanged() diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/modules/webview/WebViewFragment.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/webview/WebViewFragment.kt similarity index 72% rename from app/src/main/java/com/theuhooi/uhooipicbook/modules/webview/WebViewFragment.kt rename to app/src/main/java/com/theuhooi/uhooipicbook/ui/webview/WebViewFragment.kt index f44618f2..bc5f001c 100644 --- a/app/src/main/java/com/theuhooi/uhooipicbook/modules/webview/WebViewFragment.kt +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/webview/WebViewFragment.kt @@ -1,45 +1,37 @@ -package com.theuhooi.uhooipicbook.modules.webview +package com.theuhooi.uhooipicbook.ui.webview import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.navigation.fragment.navArgs import com.theuhooi.uhooipicbook.R +import com.theuhooi.uhooipicbook.databinding.WebViewFragmentBinding +import timber.log.Timber -class WebViewFragment : Fragment() { +class WebViewFragment : Fragment(R.layout.web_view_fragment) { // region Stored Instance Properties - private val args: WebViewFragmentArgs by navArgs() - - private var webView: WebView? = null + @Suppress("UnusedPrivateMember") + private val viewModel: WebViewViewModel by viewModels() // TODO: Use // endregion // region View Life-Cycle Methods - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - val view = inflater.inflate(R.layout.fragment_web_view, container, false) - this.webView = view.findViewById(R.id.webview) - return view - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - this.webView?.webViewClient = object : WebViewClient() { + val binding = WebViewFragmentBinding.bind(view) + binding.webview.settings.javaScriptEnabled = true + binding.webview.webViewClient = object : WebViewClient() { override fun shouldOverrideUrlLoading( view: WebView?, request: WebResourceRequest? @@ -56,12 +48,12 @@ class WebViewFragment : Fragment() { if (intent.scheme == "http" || intent.scheme == "https") { val fallbackUrlString = intent.getStringExtra( BROWSER_FALLBACK_URL_EXTRA_NAME - ) - webView?.loadUrl(fallbackUrlString) + ) ?: return false + binding.webview.loadUrl(fallbackUrlString) return true } - val context = webView?.context + val context = binding.webview.context val info = context?.packageManager?.resolveActivity( intent, PackageManager.MATCH_DEFAULT_ONLY @@ -78,20 +70,21 @@ class WebViewFragment : Fragment() { } true } catch (e: Exception) { + Timber.e(e) false } } else -> { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(urlString)) - webView?.context?.startActivity(intent) + binding.webview.context?.startActivity(intent) true } } } } - this.webView?.settings?.javaScriptEnabled = true - this.webView?.loadUrl(this.args.urlString) + val args: WebViewFragmentArgs by navArgs() + binding.webview.loadUrl(args.urlString) } // endregion @@ -99,7 +92,7 @@ class WebViewFragment : Fragment() { // region Companion Object companion object { - const val BROWSER_FALLBACK_URL_EXTRA_NAME = "browser_fallback_url" + private const val BROWSER_FALLBACK_URL_EXTRA_NAME = "browser_fallback_url" } // endregion diff --git a/app/src/main/java/com/theuhooi/uhooipicbook/ui/webview/WebViewViewModel.kt b/app/src/main/java/com/theuhooi/uhooipicbook/ui/webview/WebViewViewModel.kt new file mode 100644 index 00000000..b7729677 --- /dev/null +++ b/app/src/main/java/com/theuhooi/uhooipicbook/ui/webview/WebViewViewModel.kt @@ -0,0 +1,5 @@ +package com.theuhooi.uhooipicbook.ui.webview + +import androidx.lifecycle.ViewModel + +class WebViewViewModel : ViewModel() diff --git a/app/src/main/res/layout/dancing_monster_fragment.xml b/app/src/main/res/layout/dancing_monster_fragment.xml new file mode 100644 index 00000000..63568854 --- /dev/null +++ b/app/src/main/res/layout/dancing_monster_fragment.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_dancing_monster.xml b/app/src/main/res/layout/fragment_dancing_monster.xml deleted file mode 100644 index 15670ddb..00000000 --- a/app/src/main/res/layout/fragment_dancing_monster.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_monster_detail.xml b/app/src/main/res/layout/fragment_monster_detail.xml deleted file mode 100644 index eb9e606e..00000000 --- a/app/src/main/res/layout/fragment_monster_detail.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_web_view.xml b/app/src/main/res/layout/fragment_web_view.xml deleted file mode 100644 index 1cad6e79..00000000 --- a/app/src/main/res/layout/fragment_web_view.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/main_activity.xml similarity index 100% rename from app/src/main/res/layout/activity_main.xml rename to app/src/main/res/layout/main_activity.xml diff --git a/app/src/main/res/layout/monster_detail_fragment.xml b/app/src/main/res/layout/monster_detail_fragment.xml new file mode 100644 index 00000000..4085e9d2 --- /dev/null +++ b/app/src/main/res/layout/monster_detail_fragment.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_monster_list.xml b/app/src/main/res/layout/monster_list_fragment.xml similarity index 77% rename from app/src/main/res/layout/fragment_monster_list.xml rename to app/src/main/res/layout/monster_list_fragment.xml index f634f3b3..b93cbaa0 100644 --- a/app/src/main/res/layout/fragment_monster_list.xml +++ b/app/src/main/res/layout/monster_list_fragment.xml @@ -4,14 +4,16 @@ xmlns:tools="http://schemas.android.com/tools"> + + type="com.theuhooi.uhooipicbook.ui.monsterlist.MonsterViewModel" /> + android:layout_height="match_parent" + tools:context=".ui.monsterlist.MonsterListFragment"> + app:observedList="@{viewModel.uiState.monsterItems}" + tools:listitem="@layout/monster_list_item" /> + + type="com.theuhooi.uhooipicbook.domain.models.MonsterItem" /> + app:imageUrl="@{monsterItem.iconUrlString}" + tools:src="@tools:sample/avatars" /> + android:textStyle="bold" + tools:text="@string/name_dummy" /> diff --git a/app/src/main/res/layout/web_view_fragment.xml b/app/src/main/res/layout/web_view_fragment.xml new file mode 100644 index 00000000..535c78bf --- /dev/null +++ b/app/src/main/res/layout/web_view_fragment.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/menu_monster_detail.xml b/app/src/main/res/menu/monster_detail_menu.xml similarity index 100% rename from app/src/main/res/menu/menu_monster_detail.xml rename to app/src/main/res/menu/monster_detail_menu.xml diff --git a/app/src/main/res/menu/menu_monster_list.xml b/app/src/main/res/menu/monster_list_menu.xml similarity index 100% rename from app/src/main/res/menu/menu_monster_list.xml rename to app/src/main/res/menu/monster_list_menu.xml diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index 15b4e0d2..83404c2f 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png index 4320a459..a721356f 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png index e88175e2..eeae753e 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index 339204b4..e93af4d6 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png index 90764b27..77994d89 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png index 01d6dbb3..5c414ceb 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 830679a8..fd271d41 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png index aa2fc924..417f63e1 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index 6c76d564..efc89556 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index c8a2ab40..63c12dfb 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png index e5660973..9b1945fc 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png index 70eef091..ddeff9d6 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 7f0c26ef..ec5955a6 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png index 384304fa..c1dafb4f 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png index 9d12ca0c..33e9d7af 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 7394aed1..fbd10044 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -3,43 +3,48 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_graph" - app:startDestination="@id/monster_list_fragment"> + app:startDestination="@id/monster_nav_graph"> - - - - - + - - + + + + + - - + + + + + + + tools:layout="@layout/dancing_monster_fragment"> @@ -47,9 +52,9 @@ + tools:layout="@layout/web_view_fragment"> diff --git a/app/src/productionDebug/ic_launcher-playstore.png b/app/src/productionDebug/ic_launcher-playstore.png new file mode 100644 index 00000000..8b5f675f Binary files /dev/null and b/app/src/productionDebug/ic_launcher-playstore.png differ diff --git a/app/src/productionDebug/res/mipmap-anydpi/ic_launcher.xml b/app/src/productionDebug/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 00000000..036d09bc --- /dev/null +++ b/app/src/productionDebug/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/productionDebug/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/productionDebug/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 00000000..036d09bc --- /dev/null +++ b/app/src/productionDebug/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/productionDebug/res/mipmap-hdpi/ic_launcher.png b/app/src/productionDebug/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..d8be80e4 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/productionDebug/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/productionDebug/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..48f3a3f5 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/productionDebug/res/mipmap-hdpi/ic_launcher_round.png b/app/src/productionDebug/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..638b7961 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/productionDebug/res/mipmap-mdpi/ic_launcher.png b/app/src/productionDebug/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..f1b1531a Binary files /dev/null and b/app/src/productionDebug/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/productionDebug/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/productionDebug/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..09f4f111 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/productionDebug/res/mipmap-mdpi/ic_launcher_round.png b/app/src/productionDebug/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..e0384088 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/productionDebug/res/mipmap-xhdpi/ic_launcher.png b/app/src/productionDebug/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..cf0a3a9f Binary files /dev/null and b/app/src/productionDebug/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/productionDebug/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/productionDebug/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..78c8dab1 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/productionDebug/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/productionDebug/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..5c63e9d8 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/productionDebug/res/mipmap-xxhdpi/ic_launcher.png b/app/src/productionDebug/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..7c7d5f5a Binary files /dev/null and b/app/src/productionDebug/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/productionDebug/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/productionDebug/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..fece4d56 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/productionDebug/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/productionDebug/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..65b62830 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/productionDebug/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/productionDebug/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..aa109eb2 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/productionDebug/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/productionDebug/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..04f85956 Binary files /dev/null and b/app/src/productionDebug/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/productionDebug/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/productionDebug/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..2f1a9cbb Binary files /dev/null and b/app/src/productionDebug/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/productionDebug/res/values-en/strings.xml b/app/src/productionDebug/res/values-en/strings.xml new file mode 100644 index 00000000..bb7be875 --- /dev/null +++ b/app/src/productionDebug/res/values-en/strings.xml @@ -0,0 +1,4 @@ + + + prodDbg-UhooiPicBook + diff --git a/app/src/productionDebug/res/values/ic_launcher_background.xml b/app/src/productionDebug/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..c5d5899f --- /dev/null +++ b/app/src/productionDebug/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/app/src/productionDebug/res/values/strings.xml b/app/src/productionDebug/res/values/strings.xml new file mode 100644 index 00000000..7c29d0ae --- /dev/null +++ b/app/src/productionDebug/res/values/strings.xml @@ -0,0 +1,4 @@ + + + prodDbg-ウホーイ図鑑 + diff --git a/app/src/test/java/com/theuhooi/uhooipicbook/extensions/IntColorTest.kt b/app/src/test/java/com/theuhooi/uhooipicbook/extensions/IntColorTest.kt index 7ebfb9b6..143cea1e 100644 --- a/app/src/test/java/com/theuhooi/uhooipicbook/extensions/IntColorTest.kt +++ b/app/src/test/java/com/theuhooi/uhooipicbook/extensions/IntColorTest.kt @@ -2,10 +2,8 @@ package com.theuhooi.uhooipicbook.extensions import android.os.Build import androidx.core.graphics.ColorUtils -import androidx.test.runner.AndroidJUnit4 -import org.junit.After +import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Assert.assertEquals -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.Config @@ -14,18 +12,6 @@ import org.robolectric.annotation.Config @Config(sdk = [Build.VERSION_CODES.P]) class IntColorTest : IntColorInterface { - // region TestCase Life-Cycle Methods - - @Before - fun setUp() { - } - - @After - fun tearDown() { - } - - // endregion - // region Test Methods // region actionBarColorToStatusBarColor() diff --git a/build.gradle b/build.gradle index 45db34b3..1b6a25c9 100644 --- a/build.gradle +++ b/build.gradle @@ -2,49 +2,33 @@ buildscript { ext { - kotlin_version = '1.4.32' + kotlin_version = '1.6.10' nav_version = '2.3.5' - hilt_version = '2.31-alpha' - detekt_version = '1.7.4' + hilt_version = '2.40.5' } repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.3' + classpath 'com.android.tools.build:gradle:7.0.4' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" // Firebase - classpath 'com.google.gms:google-services:4.3.5' - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.2' - classpath 'com.google.firebase:perf-plugin:1.3.5' + classpath 'com.google.gms:google-services:4.3.10' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' + classpath 'com.google.firebase:perf-plugin:1.4.0' classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" - classpath 'com.google.android.gms:oss-licenses-plugin:0.10.3' - - classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:$detekt_version" + classpath 'com.google.android.gms:oss-licenses-plugin:0.10.4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } -plugins { - id "io.gitlab.arturbosch.detekt" version "$detekt_version" -} - -allprojects { - repositories { - google() - jcenter() - } -} - task clean(type: Delete) { delete rootProject.buildDir } - -tasks.detekt.jvmTarget = "1.8" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 21c251d5..f213eb6d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip diff --git a/settings.gradle b/settings.gradle index e5587f53..efaad1f8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,9 @@ +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} rootProject.name='UhooiPicBook' include ':app'