Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
595dbd96e9 | ||
|
|
b62bc8dc89 | ||
|
|
a909f1274d | ||
|
|
94a7ad788b | ||
|
|
cfa8bc4971 | ||
|
|
a4ad701aff | ||
|
|
00e94eb1cb | ||
|
|
ff478b3365 | ||
|
|
7bf599ce19 | ||
|
|
a4b9e227bf | ||
|
|
cb9039e927 | ||
|
|
bf65027105 | ||
|
|
28d655efc2 | ||
|
|
e711781eb0 | ||
|
|
8576bad580 | ||
|
|
56e089ffa9 | ||
|
|
6625ebcfc7 | ||
|
|
540ea7ba43 | ||
|
|
dea2d8b468 | ||
|
|
ba292bf709 | ||
|
|
2ce4d1de2e | ||
|
|
9d6712d94b | ||
|
|
4e920328e1 | ||
|
|
1865c62db8 | ||
|
|
d61206a7d2 | ||
|
|
a94c48028d | ||
|
|
909c615ae6 | ||
|
|
5d87bb077f | ||
|
|
72b5b2c795 | ||
|
|
ce91650788 | ||
|
|
1b2534eca6 | ||
|
|
5e3356e1d4 | ||
|
|
ddc7a7598d | ||
|
|
2cfe9d73a2 | ||
|
|
dbed41bdbd | ||
|
|
a0296f5d5a | ||
|
|
39cca12708 | ||
|
|
0c4e3db59c | ||
|
|
8dea17cbf2 | ||
|
|
b428c73602 | ||
|
|
8c9ce29a7a | ||
|
|
f304304bc5 | ||
|
|
f14941cf27 | ||
|
|
c83afb3cd7 | ||
|
|
dfc6d80127 | ||
|
|
3ad1b07ff8 | ||
|
|
d3c2861939 | ||
|
|
8632f8fd7a | ||
|
|
83585b4a8a | ||
|
|
e2e3186bb4 | ||
|
|
29765f0024 | ||
|
|
43edeaff04 | ||
|
|
2b7cf7d3cb | ||
|
|
fdf13fd201 | ||
|
|
92ba77a838 | ||
|
|
d910810dd4 | ||
|
|
5f8853c69d | ||
|
|
0f9b35efb1 | ||
|
|
7096e62948 | ||
|
|
acb7c0e670 | ||
|
|
bb91e6e083 | ||
|
|
67a922362d | ||
|
|
56be44b918 | ||
|
|
15493aec1a | ||
|
|
9aef7582bd | ||
|
|
5378ec6854 | ||
|
|
79dbb64275 | ||
|
|
b8912e747a | ||
|
|
a9dcd0157a | ||
|
|
45e8993d75 | ||
|
|
39bd1fa2eb | ||
|
|
5b33fbc20b | ||
|
|
196195d867 | ||
|
|
20b8076235 | ||
|
|
5f49c8149a | ||
|
|
fb4beb08ee | ||
|
|
6750eff9fa | ||
|
|
692cc8ce67 | ||
|
|
a59b6411b1 | ||
|
|
1345709450 | ||
|
|
8433f38f6e | ||
|
|
91c3d0f9a6 | ||
|
|
579a2ffe2e | ||
|
|
918f28feab | ||
|
|
7b13d40797 | ||
|
|
002588a45a | ||
|
|
1ae0cbb95d | ||
|
|
3e2d32e4c9 | ||
|
|
403f7d47b1 | ||
|
|
d1fcebdf4c | ||
|
|
a983bd729c | ||
|
|
8d311a1193 | ||
|
|
6bbd2c73b5 | ||
|
|
f851e2d626 | ||
|
|
97aafc764f | ||
|
|
183e10dba8 | ||
|
|
f5deaaa8ff | ||
|
|
55537ea191 | ||
|
|
98818023e9 | ||
|
|
e67df253de | ||
|
|
53524c8ef8 | ||
|
|
bc90a8941a | ||
|
|
5c413d1f12 | ||
|
|
8b5ab33730 | ||
|
|
d4d1288900 | ||
|
|
f4f07d0ce3 | ||
|
|
6282f4d6e0 | ||
|
|
19f5f8a0ca | ||
|
|
a296d2b827 | ||
|
|
45872f1653 | ||
|
|
074420056b | ||
|
|
9f7e05d79a | ||
|
|
955299bd89 | ||
|
|
6520758722 | ||
|
|
583137aa25 | ||
|
|
8afce7706c | ||
|
|
7ae0a0bae6 | ||
|
|
f34d6c5222 | ||
|
|
002f4f9309 | ||
|
|
bf77a9aaed | ||
|
|
d17c178eaa | ||
|
|
2c0ba0fae9 | ||
|
|
0396a488cd | ||
|
|
f5ef483cd9 | ||
|
|
78960f6d4e | ||
|
|
2be9408560 | ||
|
|
46dc6fbe91 | ||
|
|
e411cb3d7f | ||
|
|
00535dc859 | ||
|
|
465e6931ad | ||
|
|
7e64100491 | ||
|
|
e199f00ca0 | ||
|
|
8722636b13 | ||
|
|
5db4a1ee8d | ||
|
|
b0bae12e6b | ||
|
|
585d42c6aa | ||
|
|
47448616dd | ||
|
|
ccd64b46e3 | ||
|
|
bce227357f | ||
|
|
2ec1633c51 | ||
|
|
ed8528aea4 | ||
|
|
3cc74f9bcf | ||
|
|
015c9929b3 | ||
|
|
76737b0eed | ||
|
|
28c454261f | ||
|
|
327ec9b6a5 | ||
|
|
fc617a5dfa | ||
|
|
c6289908c4 | ||
|
|
ca0706f94b | ||
|
|
350a64d479 | ||
|
|
058561e4d6 | ||
|
|
a4bc5476a4 | ||
|
|
1fe559ff04 | ||
|
|
78f050f115 | ||
|
|
0d964c4a5d | ||
|
|
c24c433c0e | ||
|
|
fd9010d468 | ||
|
|
90f40075e8 | ||
|
|
f621f785f8 | ||
|
|
76d62906c8 | ||
|
|
dbeafbb569 | ||
|
|
fab5cb45c4 | ||
|
|
7b593806eb | ||
|
|
f6064616b0 | ||
|
|
36d999ebb4 | ||
|
|
79920f6180 | ||
|
|
36ab72226c | ||
|
|
7cc81047d4 | ||
|
|
82252dbe2d | ||
|
|
da1825498a | ||
|
|
947a04d82d | ||
|
|
75ab508dc3 | ||
|
|
1d2da7c2f8 | ||
|
|
dd019279ec | ||
|
|
485282a48d | ||
|
|
eeef2c347d | ||
|
|
b7229c6d15 | ||
|
|
da80605ae1 | ||
|
|
4066a86ad6 | ||
|
|
0f595f7b02 | ||
|
|
42f3068b01 | ||
|
|
0312c3f431 | ||
|
|
7d324ddb8c | ||
|
|
c7b7a786f3 | ||
|
|
26f69c2027 | ||
|
|
450601f26b | ||
|
|
2ab69de686 | ||
|
|
0083aa69b5 | ||
|
|
18d82a5eb3 | ||
|
|
0d668ac3aa | ||
|
|
b1a32496ba | ||
|
|
4db59db7a1 | ||
|
|
0843352514 | ||
|
|
aa50d6449d | ||
|
|
6a41b966c5 | ||
|
|
943b9bd091 | ||
|
|
010f69031a | ||
|
|
168271a8f4 | ||
|
|
ea92d64972 | ||
|
|
766f14cd22 | ||
|
|
33210319bb | ||
|
|
7ef0a8fc51 | ||
|
|
1f850435b1 | ||
|
|
9d8fd77a08 | ||
|
|
e2c760e7f3 | ||
|
|
51a8538d6a | ||
|
|
4b9b148519 | ||
|
|
ced16c3794 | ||
|
|
e824294ea0 | ||
|
|
ffce7c2b3e | ||
|
|
f0d615bd44 | ||
|
|
df546947bb | ||
|
|
3e0544279c | ||
|
|
25bfed3c71 |
@@ -3,3 +3,6 @@
|
||||
e7f4c8a7ebe4e907f65af46e6dddfd3a542415c0
|
||||
ab2713154f846b3db6d44625d1022bf421b275d0
|
||||
cbdfa67d075ec1f8ceec0f3559498cbca01783a0
|
||||
|
||||
# Renamed Renovate config file
|
||||
f304304bc5b64edf189aaa473b05df912067a8bd
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
* text=auto eol=lf
|
||||
**/dependencies/** linguist-generated
|
||||
**/clawicons/** linguist-generated
|
||||
android/src/main/baseline-prof.txt linguist-generated
|
||||
android/src/main/baseline-prof.txt linguist-generated -diff
|
||||
|
||||
@@ -6,14 +6,6 @@
|
||||
"github>msfjarvis/shared-workflows//renovate/automerge"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchPackagePatterns": [
|
||||
"^com.android.tools.build",
|
||||
"^com.android.test",
|
||||
"^gradle"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"matchPackagePatterns": [
|
||||
"^kotlin",
|
||||
@@ -27,21 +19,13 @@
|
||||
"gradle"
|
||||
],
|
||||
"packagePatterns": [
|
||||
"^com.squareup.okhttp3"
|
||||
// We want to stay in sync with Retrofit
|
||||
"^com.squareup.okhttp3",
|
||||
// Renovate refuses to stop resolving this from the snapshots repo
|
||||
"^app.cash.sqldelight",
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"matchDatasources": [
|
||||
"maven"
|
||||
],
|
||||
"matchPackageNames": [
|
||||
"androidx.compose.compiler:compiler"
|
||||
],
|
||||
"registryUrls": [
|
||||
"https://maven.google.com/"
|
||||
]
|
||||
}
|
||||
],
|
||||
"regexManagers": [
|
||||
{
|
||||
@@ -52,7 +36,8 @@
|
||||
"KTFMT_VERSION = \"(?<currentValue>.*)\""
|
||||
],
|
||||
"datasourceTemplate": "maven",
|
||||
"depNameTemplate": "com.facebook:ktfmt"
|
||||
"depNameTemplate": "com.facebook:ktfmt",
|
||||
"registryUrlTemplate": "https://repo1.maven.org/maven2/",
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
@@ -62,7 +47,8 @@
|
||||
"TWITTER_RULES_VERSION = \"(?<currentValue>.*)\""
|
||||
],
|
||||
"datasourceTemplate": "maven",
|
||||
"depNameTemplate": "com.twitter.compose.rules:detekt"
|
||||
"depNameTemplate": "com.twitter.compose.rules:detekt",
|
||||
"registryUrlTemplate": "https://repo1.maven.org/maven2/",
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
@@ -72,7 +58,18 @@
|
||||
"composeCompiler = \"(?<currentValue>.*)\""
|
||||
],
|
||||
"datasourceTemplate": "maven",
|
||||
"depNameTemplate": "androidx.compose.compiler:compiler"
|
||||
"depNameTemplate": "androidx.compose.compiler:compiler",
|
||||
"registryUrlTemplate": "https://maven.google.com",
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"qodana.yaml"
|
||||
],
|
||||
"matchStrings": [
|
||||
"jetbrains/qodana-jvm-android:(?<currentValue>.*)"
|
||||
],
|
||||
"datasourceTemplate": "docker",
|
||||
"depNameTemplate": "jetbrains/qodana-jvm-android",
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
name: Baseline profile generation
|
||||
|
||||
on:
|
||||
# every day at 00:43
|
||||
schedule:
|
||||
- cron: '43 0 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
AVD_API_LEVEL: 31
|
||||
AVD_ARCH: x86_64
|
||||
|
||||
jobs:
|
||||
baseline-profile:
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
TERM: dumb
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
with:
|
||||
token: ${{ secrets.POST_RELEASE_GH_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b # v3.9.0
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 18
|
||||
|
||||
- name: Set up Git author
|
||||
shell: bash
|
||||
run: |
|
||||
git config user.name "GitHub Actions"
|
||||
git config user.email noreply@github.com
|
||||
|
||||
- name: Setup Gradle caching
|
||||
uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef # tag=v2.3.3
|
||||
with:
|
||||
gradle-home-cache-cleanup: true
|
||||
|
||||
# Restore AVD from cache
|
||||
- name: Cache AVD
|
||||
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
|
||||
id: avd-cache
|
||||
with:
|
||||
path: |
|
||||
~/.android/avd/*
|
||||
~/.android/adb*
|
||||
key: ${{ runner.os }}-avd-${{ env.AVD_API_LEVEL }}-${{ env.AVD_ARCH }}
|
||||
|
||||
- name: Decrypt secrets
|
||||
run: |
|
||||
./scripts/setup-age.sh
|
||||
./scripts/signing-setup.sh "$ENCRYPT_KEY"
|
||||
env:
|
||||
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
|
||||
|
||||
# This allows us to build most of what we need without the emulator running
|
||||
# and using resources
|
||||
- name: Build app and benchmark
|
||||
run: ./gradlew :benchmark:assembleBenchmark :android:assembleBenchmark
|
||||
|
||||
# Now use reactivecircus/android-emulator-runner to spin up an emulator. We're gonna use it again
|
||||
# to actually run the test once the emulator has booted.
|
||||
- name: Create AVD snapshot for caching
|
||||
if: steps.avd-cache.outputs.cache-hit != 'true'
|
||||
uses: reactivecircus/android-emulator-runner@50986b1464923454c95e261820bc626f38490ec0 # v2
|
||||
with:
|
||||
api-level: ${{ env.AVD_API_LEVEL }}
|
||||
arch: ${{ env.AVD_ARCH }}
|
||||
channel: canary
|
||||
target: aosp_atd
|
||||
force-avd-creation: false
|
||||
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||
disable-animations: false
|
||||
disk-size: 8G
|
||||
script: echo "Generated AVD snapshot for caching."
|
||||
|
||||
# Run our baseline profile generator. We need to manually pull the baseline profiles off the
|
||||
# emulator when using the GA runner
|
||||
- name: Run benchmark
|
||||
uses: reactivecircus/android-emulator-runner@50986b1464923454c95e261820bc626f38490ec0 # v2
|
||||
with:
|
||||
api-level: ${{ env.AVD_API_LEVEL }}
|
||||
arch: ${{ env.AVD_ARCH }}
|
||||
channel: canary
|
||||
target: aosp_atd
|
||||
disable-animations: true
|
||||
disable-spellchecker: true
|
||||
disk-size: 8G
|
||||
script: |
|
||||
# Run our benchmark, enabling only tests using BaselineProfile
|
||||
./gradlew connectedBenchmarkAndroidTest -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile --stacktrace
|
||||
# Need to manually pull the generated profiles from the emulator
|
||||
adb pull /sdcard/Android/media/dev.msfjarvis.claw.benchmark benchmark/build/outputs/baseline-prof/
|
||||
|
||||
# If we're on main branch, copy over the baseline profile and
|
||||
# commit it to the repository (if changed)
|
||||
- name: Commit baseline profile into main
|
||||
if: github.ref == 'refs/heads/main'
|
||||
run: |
|
||||
# Pull down any changes which may have been committed while this workflow has been running
|
||||
git pull
|
||||
# Sort the baseline profile, saving it to app/
|
||||
sort -o android/src/main/baseline-prof.txt benchmark/build/outputs/baseline-prof/BaselineProfileGenerator_startup-baseline-prof.txt
|
||||
# If the baseline profile has changed, commit it
|
||||
if [[ $(git diff --stat android/src/main/baseline-prof.txt) != '' ]]; then
|
||||
git add android/src/main/baseline-prof.txt
|
||||
git commit -m "chore(android): refresh baseline profile" && git push
|
||||
fi
|
||||
|
||||
# Upload the entire generated folder and attach it to the CI run
|
||||
- name: Attach baseline profile
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: Baseline profile output
|
||||
path: benchmark/build/outputs/baseline-prof
|
||||
|
||||
- name: Clean secrets
|
||||
if: always()
|
||||
run: scripts/signing-cleanup.sh
|
||||
@@ -18,10 +18,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3.1.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@c3ac5dd0ed8db40fedb61c32fbe677e6b355e94c # v3.8.0
|
||||
uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b # v3.9.0
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 18
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
|
||||
- name: (Fail-only) Upload test report
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # tag=v3.1.1
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: Test report
|
||||
path: android/build/reports
|
||||
@@ -53,16 +53,18 @@ jobs:
|
||||
needs: [ "check" ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3.1.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@c3ac5dd0ed8db40fedb61c32fbe677e6b355e94c # v3.8.0
|
||||
uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b # v3.9.0
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 18
|
||||
|
||||
- name: Decrypt secrets
|
||||
run: scripts/signing-setup.sh "$ENCRYPT_KEY"
|
||||
run: |
|
||||
./scripts/setup-age.sh
|
||||
./scripts/signing-setup.sh "$ENCRYPT_KEY"
|
||||
env:
|
||||
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
|
||||
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
schedule:
|
||||
- cron: "20 3 * * 0"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
@@ -17,14 +13,14 @@ jobs:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@a669cc5936cc5e1b6a362ec1ff9e410dc570d190 # v2
|
||||
uses: github/codeql-action/init@3ebbd71c74ef574dbc558c82f70e52732c8b44fe # v2
|
||||
with:
|
||||
languages: java
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@a669cc5936cc5e1b6a362ec1ff9e410dc570d190 # v2
|
||||
uses: github/codeql-action/autobuild@3ebbd71c74ef574dbc558c82f70e52732c8b44fe # v2
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@a669cc5936cc5e1b6a362ec1ff9e410dc570d190 # v2
|
||||
uses: github/codeql-action/analyze@3ebbd71c74ef574dbc558c82f70e52732c8b44fe # v2
|
||||
with:
|
||||
category: "/language:java"
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
name: Qodana
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
qodana:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: 'Qodana Scan'
|
||||
uses: JetBrains/qodana-action@v2022.2.3
|
||||
uses: JetBrains/qodana-action@c25ee7dc4d0697b27ac54877a4ff71cf5b6dde3c # v2022.3.2
|
||||
env:
|
||||
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
|
||||
|
||||
@@ -7,13 +7,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3.1.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
with:
|
||||
token: ${{ secrets.POST_RELEASE_GH_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@c3ac5dd0ed8db40fedb61c32fbe677e6b355e94c # v3.8.0
|
||||
uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b # v3.9.0
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 18
|
||||
@@ -31,7 +31,9 @@ jobs:
|
||||
cache-read-only: true
|
||||
|
||||
- name: Decrypt secrets
|
||||
run: scripts/signing-setup.sh "$ENCRYPT_KEY"
|
||||
run: |
|
||||
./scripts/setup-age.sh
|
||||
./scripts/signing-setup.sh "$ENCRYPT_KEY"
|
||||
env:
|
||||
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
|
||||
|
||||
@@ -45,7 +47,8 @@ jobs:
|
||||
- name: Update changelog
|
||||
uses: thomaseizinger/keep-a-changelog-new-release@5bc232893483441c5d6cd6c9dcb1e48abf9a2bae # 1.3.0
|
||||
with:
|
||||
tag: ${{ env.VERSION }}
|
||||
tag: v${{ env.VERSION }}
|
||||
version: ${{ env.VERSION }}
|
||||
|
||||
- name: Commit changes
|
||||
shell: bash
|
||||
|
||||
+72
-5
@@ -7,6 +7,59 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.19.0] - 2023-02-01
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade dependencies
|
||||
- Optimize packaged baseline profiles
|
||||
|
||||
## [1.18.0] - 2023-01-21
|
||||
|
||||
### Changed
|
||||
|
||||
- Special-case deleted stories in comments API
|
||||
- Fix regression where save button had the incorrect visual state
|
||||
|
||||
## [1.17.0] - 2023-01-12
|
||||
|
||||
### Added
|
||||
|
||||
- The app will now mark new comments as unread when returning to posts
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade to Kotlin 1.8.0
|
||||
- Revert questionable app bar scrolling behaviour change
|
||||
|
||||
## [1.16.0] - 2022-12-24
|
||||
|
||||
### Changed
|
||||
|
||||
- Fix bug where newest posts tab actually showed hottest posts instead
|
||||
|
||||
## [1.15.0] - 2022-12-20
|
||||
|
||||
### Changed
|
||||
|
||||
- Fix a case where collapsing the parent of an already collapsed comment caused it to become expanded
|
||||
- Tweak progress bar UI to use a linear indicator
|
||||
- Allow app bar to hide when scrolling down
|
||||
- Fix bug where refreshing a list of posts caused it to jump around multiple times
|
||||
|
||||
## [1.14.0] - 2022-12-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Rework how often saved posts are updated
|
||||
- Collapsing a comment now collapses all comments under it similar to how it works on the website
|
||||
|
||||
## [1.13.0] - 2022-12-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Fix crash when viewing [jcs](https://lobste.rs/u/jcs)' comments
|
||||
|
||||
## [1.12.0] - 2022-12-09
|
||||
|
||||
### Changed
|
||||
@@ -104,15 +157,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Initial Play Store release
|
||||
|
||||
[Unreleased]: https://github.com/msfjarvis/compose-lobsters/compare/1.12.0...HEAD
|
||||
[Unreleased]: https://github.com/msfjarvis/compose-lobsters/compare/v1.19.0...HEAD
|
||||
|
||||
[1.12.0]: https://github.com/msfjarvis/compose-lobsters/compare/1.11.0...1.12.0
|
||||
[1.19.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.18.0...v1.19.0
|
||||
|
||||
[1.11.0]: https://github.com/msfjarvis/compose-lobsters/compare/1.10.0...1.11.0
|
||||
[1.18.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.17.0...v1.18.0
|
||||
|
||||
[1.10.0]: https://github.com/msfjarvis/compose-lobsters/compare/1.9.0...1.10.0
|
||||
[1.17.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.16.0...v1.17.0
|
||||
|
||||
[1.9.0]: https://github.com/msfjarvis/compose-lobsters/compare/1.8.0...1.9.0
|
||||
[1.16.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.15.0...v1.16.0
|
||||
|
||||
[1.15.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.14.0...v1.15.0
|
||||
|
||||
[1.14.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.13.0...v1.14.0
|
||||
|
||||
[1.13.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.12.0...v1.13.0
|
||||
|
||||
[1.12.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.11.0...v1.12.0
|
||||
|
||||
[1.11.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.10.0...v1.11.0
|
||||
|
||||
[1.10.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.9.0...v1.10.0
|
||||
|
||||
[1.9.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.8.0...v1.9.0
|
||||
|
||||
[1.8.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.7.0...1.8.0
|
||||
|
||||
|
||||
@@ -2,18 +2,16 @@
|
||||
|
||||
Unofficial Android app for read-only access to [lobste.rs](https://lobste.rs), built with [Jetpack Compose](https://developer.android.com/jetpack/compose).
|
||||
|
||||
<img src="https://github.com/msfjarvis/compose-lobsters/blob/main/.github/readme_feature.webp"
|
||||
alt="Get it on Google Play"
|
||||
height="550" />
|
||||
|
||||
## Download
|
||||
|
||||
<a href="https://play.google.com/store/apps/details?id=dev.msfjarvis.claw.android">
|
||||
<img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png"
|
||||
alt="Get it on Google Play"
|
||||
height="80" />
|
||||
</a>
|
||||
|
||||
<img src="https://github.com/msfjarvis/compose-lobsters/blob/main/.github/readme_feature.webp"
|
||||
alt="Side by side screenshots of the app's main page in dark and light UI modes"
|
||||
height="550" />
|
||||
|
||||
Snapshots from the development branch can be obtained [here](https://github.com/msfjarvis/compose-lobsters/releases/tag/nightly).
|
||||
|
||||
## License
|
||||
|
||||
Vendored
-27
@@ -1,29 +1,2 @@
|
||||
# Keep `Companion` object fields of serializable classes.
|
||||
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
|
||||
-if @kotlinx.serialization.Serializable class **
|
||||
-keepclassmembers class <1> {
|
||||
static <1>$Companion Companion;
|
||||
}
|
||||
|
||||
# Keep `serializer()` on companion objects (both default and named) of serializable classes.
|
||||
-if @kotlinx.serialization.Serializable class ** {
|
||||
static **$* *;
|
||||
}
|
||||
-keepclassmembers class <2>$<3> {
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
# Keep `INSTANCE.serializer()` of serializable objects.
|
||||
-if @kotlinx.serialization.Serializable class ** {
|
||||
public static ** INSTANCE;
|
||||
}
|
||||
-keepclassmembers class <1> {
|
||||
public static <1> INSTANCE;
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
|
||||
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
|
||||
|
||||
-dontobfuscate
|
||||
-keepattributes SourceFile, LineNumberTable
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Claw.SplashScreen"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
tools:targetApi="s">
|
||||
tools:targetApi="tiramisu">
|
||||
<profileable
|
||||
android:shell="true"
|
||||
tools:targetApi="29" />
|
||||
@@ -149,6 +149,10 @@
|
||||
android:name="androidx.work.WorkManagerInitializer"
|
||||
android:value="androidx.startup"
|
||||
tools:node="remove" />
|
||||
<meta-data
|
||||
android:name="com.deliveryhero.whetstone.worker.WhetstoneWorkerInitializer"
|
||||
android:value="androidx.startup"
|
||||
tools:node="remove" />
|
||||
</provider>
|
||||
<!-- https://issuetracker.google.com/issues/258619948 -->
|
||||
<receiver
|
||||
|
||||
Generated
+24944
-13383
File diff suppressed because it is too large
Load Diff
@@ -46,7 +46,7 @@ class ClawApplication : Application(), ApplicationComponentOwner {
|
||||
WorkManager.getInstance(this)
|
||||
.enqueueUniquePeriodicWork(
|
||||
"updateSavedPosts",
|
||||
ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
|
||||
ExistingPeriodicWorkPolicy.UPDATE,
|
||||
postUpdateWorkRequest,
|
||||
)
|
||||
}
|
||||
|
||||
+5
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021 Harsh Shandilya.
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -8,22 +8,13 @@ package dev.msfjarvis.claw.android.injection
|
||||
|
||||
import com.deliveryhero.whetstone.app.ApplicationScope
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dev.msfjarvis.claw.android.ui.util.HTMLConverterImpl
|
||||
import dev.msfjarvis.claw.common.comments.HTMLConverter
|
||||
import io.github.furstenheim.CopyDown
|
||||
|
||||
@Module
|
||||
@ContributesTo(ApplicationScope::class)
|
||||
object HTMLConverterModule {
|
||||
|
||||
@Provides
|
||||
fun provideHTMLConverter() =
|
||||
object : HTMLConverter {
|
||||
private val copydown = CopyDown()
|
||||
|
||||
override fun convertHTMLToMarkdown(html: String): String {
|
||||
return copydown.convert(html)
|
||||
}
|
||||
}
|
||||
interface HTMLConverterModule {
|
||||
@Binds fun HTMLConverterImpl.bind(): HTMLConverter
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021 Harsh Shandilya.
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright © 2022 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.android.injection
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import androidx.work.Configuration
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkerFactory
|
||||
import com.deliveryhero.whetstone.app.ApplicationScope
|
||||
import com.squareup.anvil.annotations.ContributesMultibinding
|
||||
import dev.msfjarvis.claw.core.injection.AppPlugin
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesMultibinding(ApplicationScope::class)
|
||||
class WorkManagerPlugin
|
||||
@Inject
|
||||
constructor(
|
||||
private val workerFactory: WorkerFactory,
|
||||
) : AppPlugin {
|
||||
override fun apply(application: Application) {
|
||||
WorkManager.initialize(
|
||||
application,
|
||||
Configuration.Builder()
|
||||
.setWorkerFactory(workerFactory)
|
||||
.setMinimumLoggingLevel(Log.DEBUG)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -27,13 +27,14 @@ constructor(
|
||||
) : PagingSource<Int, LobstersPost>() {
|
||||
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LobstersPost> {
|
||||
val page = params.key ?: 1
|
||||
val page = params.key ?: STARTING_PAGE_INDEX
|
||||
return when (val result = withContext(ioDispatcher) { remoteFetcher.getItemsAtPage(page) }) {
|
||||
is Success ->
|
||||
LoadResult.Page(
|
||||
itemsBefore = (page - 1) * PAGE_SIZE,
|
||||
data = result.value,
|
||||
prevKey = if (page == 1) null else page - 1,
|
||||
nextKey = page.plus(1)
|
||||
prevKey = if (page == STARTING_PAGE_INDEX) null else page - 1,
|
||||
nextKey = page + 1,
|
||||
)
|
||||
is Failure.NetworkFailure -> LoadResult.Error(result.error)
|
||||
is Failure.UnknownFailure -> LoadResult.Error(result.error)
|
||||
@@ -42,12 +43,19 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRefreshKey(state: PagingState<Int, LobstersPost>): Int {
|
||||
return state.pages.size + 1
|
||||
override fun getRefreshKey(state: PagingState<Int, LobstersPost>): Int? {
|
||||
return state.anchorPosition?.let { anchorPosition ->
|
||||
(anchorPosition / PAGE_SIZE).coerceAtLeast(STARTING_PAGE_INDEX)
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(remoteFetcher: RemoteFetcher<LobstersPost>): LobstersPagingSource
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val PAGE_SIZE = 25
|
||||
const val STARTING_PAGE_INDEX = 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -217,6 +217,8 @@ fun LobstersApp(
|
||||
postId = postId,
|
||||
postActions = postActions,
|
||||
htmlConverter = htmlConverter,
|
||||
getSeenComments = viewModel::getSeenComments,
|
||||
markSeenComments = viewModel::markSeenComments,
|
||||
)
|
||||
}
|
||||
composable(
|
||||
|
||||
@@ -32,7 +32,7 @@ fun DatabasePosts(
|
||||
) {
|
||||
items.forEach { (month, posts) ->
|
||||
stickyHeader { MonthHeader(month = month) }
|
||||
items(posts) { item ->
|
||||
items(posts, { it.shortId }) { item ->
|
||||
ListItem(
|
||||
item = item,
|
||||
isSaved = { true },
|
||||
|
||||
@@ -57,7 +57,7 @@ fun NetworkPosts(
|
||||
LazyColumn(
|
||||
state = listState,
|
||||
) {
|
||||
items(lazyPagingItems) { item ->
|
||||
items(items = lazyPagingItems, key = { it.shortId }) { item ->
|
||||
if (item != null) {
|
||||
val dbModel = item.toDbModel()
|
||||
ListItem(
|
||||
@@ -70,12 +70,12 @@ fun NetworkPosts(
|
||||
}
|
||||
}
|
||||
if (lazyPagingItems.loadState.append == LoadState.Loading) {
|
||||
item {
|
||||
item(key = "progressbar") {
|
||||
ProgressBar(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.wrapContentWidth(Alignment.CenterHorizontally)
|
||||
.padding(top = 4.dp),
|
||||
.padding(vertical = 16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright © 2022 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.android.ui.util
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import dev.msfjarvis.claw.common.comments.HTMLConverter
|
||||
import io.github.furstenheim.CopyDown
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
class HTMLConverterImpl @Inject constructor() : HTMLConverter {
|
||||
private val copydown = CopyDown()
|
||||
|
||||
override fun convertHTMLToMarkdown(html: String): String {
|
||||
return copydown.convert(html)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -15,10 +15,14 @@ import com.slack.eithernet.ApiResult.Failure
|
||||
import com.slack.eithernet.ApiResult.Success
|
||||
import dev.msfjarvis.claw.android.injection.IODispatcher
|
||||
import dev.msfjarvis.claw.android.paging.LobstersPagingSource
|
||||
import dev.msfjarvis.claw.android.paging.LobstersPagingSource.Companion.PAGE_SIZE
|
||||
import dev.msfjarvis.claw.android.paging.LobstersPagingSource.Companion.STARTING_PAGE_INDEX
|
||||
import dev.msfjarvis.claw.android.ui.toLocalDateTime
|
||||
import dev.msfjarvis.claw.api.LobstersApi
|
||||
import dev.msfjarvis.claw.database.local.SavedPost
|
||||
import dev.msfjarvis.claw.model.Comment
|
||||
import java.io.IOException
|
||||
import java.net.HttpURLConnection
|
||||
import java.time.Month
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
@@ -38,9 +42,13 @@ constructor(
|
||||
@IODispatcher private val ioDispatcher: CoroutineDispatcher,
|
||||
) : ViewModel() {
|
||||
private val hottestPostsPager =
|
||||
Pager(PagingConfig(pageSize = 20)) { pagingSourceFactory.create(api::getHottestPosts) }
|
||||
Pager(PagingConfig(pageSize = PAGE_SIZE), initialKey = STARTING_PAGE_INDEX) {
|
||||
pagingSourceFactory.create(api::getHottestPosts)
|
||||
}
|
||||
private val newestPostsPager =
|
||||
Pager(PagingConfig(pageSize = 20)) { pagingSourceFactory.create(api::getHottestPosts) }
|
||||
Pager(PagingConfig(pageSize = PAGE_SIZE), initialKey = STARTING_PAGE_INDEX) {
|
||||
pagingSourceFactory.create(api::getNewestPosts)
|
||||
}
|
||||
|
||||
val hottestPosts
|
||||
get() = hottestPostsPager.flow
|
||||
@@ -80,11 +88,23 @@ constructor(
|
||||
is Success -> result.value
|
||||
is Failure.NetworkFailure -> throw result.error
|
||||
is Failure.UnknownFailure -> throw result.error
|
||||
is Failure.HttpFailure,
|
||||
is Failure.HttpFailure -> {
|
||||
if (result.code == HttpURLConnection.HTTP_NOT_FOUND) {
|
||||
throw IOException("Story was removed by moderator")
|
||||
} else {
|
||||
throw IOException("API returned an invalid response")
|
||||
}
|
||||
}
|
||||
is Failure.ApiFailure -> throw IOException("API returned an invalid response")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getSeenComments(postId: String) = savedPostsRepository.getSeenComments(postId)
|
||||
|
||||
fun markSeenComments(postId: String, comments: List<Comment>) {
|
||||
viewModelScope.launch { savedPostsRepository.markSeenComments(postId, comments) }
|
||||
}
|
||||
|
||||
suspend fun getLinkMetadata(url: String) =
|
||||
withContext(ioDispatcher) { linkMetadataRepository.getLinkMetadata(url) }
|
||||
|
||||
|
||||
+22
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -10,7 +10,9 @@ import app.cash.sqldelight.coroutines.asFlow
|
||||
import app.cash.sqldelight.coroutines.mapToList
|
||||
import dev.msfjarvis.claw.android.injection.DatabaseDispatcher
|
||||
import dev.msfjarvis.claw.database.LobstersDatabase
|
||||
import dev.msfjarvis.claw.database.local.PostComments
|
||||
import dev.msfjarvis.claw.database.local.SavedPost
|
||||
import dev.msfjarvis.claw.model.Comment
|
||||
import io.github.aakira.napier.Napier
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
@@ -23,6 +25,7 @@ constructor(
|
||||
@DatabaseDispatcher private val dbDispatcher: CoroutineDispatcher,
|
||||
) {
|
||||
private val savedPostQueries = database.savedPostQueries
|
||||
private val postCommentsQueries = database.postCommentsQueries
|
||||
val savedPosts = savedPostQueries.selectAllPosts().asFlow().mapToList(dbDispatcher)
|
||||
|
||||
suspend fun savePost(post: SavedPost) {
|
||||
@@ -30,11 +33,29 @@ constructor(
|
||||
withContext(dbDispatcher) { savedPostQueries.insertOrReplacePost(post) }
|
||||
}
|
||||
|
||||
suspend fun savePosts(posts: List<SavedPost>) {
|
||||
Napier.d(tag = TAG) { "Saving posts: ${posts.joinToString(",") { it.shortId }}" }
|
||||
withContext(dbDispatcher) {
|
||||
savedPostQueries.transaction {
|
||||
posts.forEach { post -> savedPostQueries.insertOrReplacePost(post) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun removePost(post: SavedPost) {
|
||||
Napier.d(tag = TAG) { "Removing post: ${post.shortId}" }
|
||||
withContext(dbDispatcher) { savedPostQueries.deletePost(post.shortId) }
|
||||
}
|
||||
|
||||
suspend fun getSeenComments(postId: String) =
|
||||
withContext(dbDispatcher) { postCommentsQueries.getCommentIds(postId).executeAsOneOrNull() }
|
||||
|
||||
suspend fun markSeenComments(postId: String, comments: List<Comment>) {
|
||||
withContext(dbDispatcher) {
|
||||
postCommentsQueries.rememberComments(PostComments(postId, comments.map { it.shortId }))
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val TAG = "SavedPostsRepository"
|
||||
}
|
||||
|
||||
@@ -12,15 +12,13 @@ import androidx.work.WorkerParameters
|
||||
import com.deliveryhero.whetstone.ForScope
|
||||
import com.deliveryhero.whetstone.worker.ContributesWorker
|
||||
import com.deliveryhero.whetstone.worker.WorkerScope
|
||||
import com.slack.eithernet.ApiResult
|
||||
import com.slack.eithernet.ApiResult.Success
|
||||
import dev.msfjarvis.claw.android.viewmodel.SavedPostsRepository
|
||||
import dev.msfjarvis.claw.api.LobstersApi
|
||||
import dev.msfjarvis.claw.common.posts.toDbModel
|
||||
import dev.msfjarvis.claw.model.LobstersPostDetails
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
|
||||
/**
|
||||
* WorkManager-backed [CoroutineWorker] that gets all the posts from [SavedPostsRepository], fetches
|
||||
@@ -38,19 +36,13 @@ constructor(
|
||||
private val lobstersApi: LobstersApi,
|
||||
) : CoroutineWorker(appContext, workerParams) {
|
||||
override suspend fun doWork(): Result {
|
||||
val posts = savedPostsRepository.savedPosts.first()
|
||||
supervisorScope {
|
||||
posts
|
||||
.map { post ->
|
||||
async {
|
||||
val details = lobstersApi.getPostDetails(post.shortId)
|
||||
if (details is ApiResult.Success) {
|
||||
savedPostsRepository.savePost(details.value.toDbModel())
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
}
|
||||
savedPostsRepository.savedPosts
|
||||
.first()
|
||||
.map { post -> lobstersApi.getPostDetails(post.shortId) }
|
||||
.filterIsInstance<Success<LobstersPostDetails>>()
|
||||
.map { result -> result.value.toDbModel() }
|
||||
.toList()
|
||||
.let { savedPostsRepository.savePosts(it) }
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# This file was automatically generated by 'versioning-plugin'. DO NOT EDIT MANUALLY.
|
||||
#
|
||||
versioning-plugin.versionCode=11200
|
||||
versioning-plugin.versionName=1.12.0
|
||||
versioning-plugin.versionCode=11900
|
||||
versioning-plugin.versionName=1.19.0
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
@file:Suppress("DSL_SCOPE_VIOLATION", "UnstableApiUsage")
|
||||
|
||||
plugins {
|
||||
kotlin("android")
|
||||
id("dev.msfjarvis.claw.kotlin-common")
|
||||
id("dev.msfjarvis.claw.kotlin-android")
|
||||
id("dev.msfjarvis.claw.android-library")
|
||||
alias(libs.plugins.anvil)
|
||||
alias(libs.plugins.whetstone)
|
||||
|
||||
@@ -13,11 +13,17 @@ import dev.msfjarvis.claw.model.LobstersPost
|
||||
import dev.msfjarvis.claw.model.LobstersPostDetails
|
||||
import dev.msfjarvis.claw.model.User
|
||||
import dev.msfjarvis.claw.util.TestUtils.getJson
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonNamingStrategy
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
class ApiWrapper(controller: EitherNetController<LobstersApi>) {
|
||||
private val json = Json { ignoreUnknownKeys = true }
|
||||
private val json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
namingStrategy = JsonNamingStrategy.SnakeCase
|
||||
}
|
||||
private val hottest: List<LobstersPost> = json.decodeFromString(getJson("hottest.json"))
|
||||
private val postDetails: LobstersPostDetails =
|
||||
json.decodeFromString(getJson("post_details_tdfoqh.json"))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021 Harsh Shandilya.
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
|
||||
@@ -11,14 +11,12 @@ import androidx.benchmark.macro.CompilationMode
|
||||
import androidx.benchmark.macro.StartupMode
|
||||
import androidx.benchmark.macro.StartupTimingMetric
|
||||
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
@LargeTest
|
||||
class BaselineProfileBenchmark {
|
||||
@get:Rule val benchmarkRule = MacrobenchmarkRule()
|
||||
private lateinit var device: UiDevice
|
||||
@@ -52,7 +50,7 @@ class BaselineProfileBenchmark {
|
||||
startupMode = StartupMode.COLD,
|
||||
compilationMode = compilationMode
|
||||
) {
|
||||
exploreUI(device)
|
||||
startActivityAndWait()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,13 @@ package dev.msfjarvis.claw.benchmark
|
||||
|
||||
import androidx.benchmark.macro.ExperimentalStableBaselineProfilesApi
|
||||
import androidx.benchmark.macro.junit4.BaselineProfileRule
|
||||
import androidx.test.filters.MediumTest
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
@ExperimentalStableBaselineProfilesApi
|
||||
@MediumTest
|
||||
@OptIn(ExperimentalStableBaselineProfilesApi::class)
|
||||
class BaselineProfileGenerator {
|
||||
@get:Rule val baselineProfileRule = BaselineProfileRule()
|
||||
private lateinit var device: UiDevice
|
||||
@@ -31,8 +29,8 @@ class BaselineProfileGenerator {
|
||||
fun startup() =
|
||||
baselineProfileRule.collectStableBaselineProfile(
|
||||
packageName = PACKAGE_NAME,
|
||||
maxIterations = 5,
|
||||
maxIterations = 15,
|
||||
) {
|
||||
exploreUI(device)
|
||||
startActivityAndWait()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ private const val NAV_ID_NEWEST = "NEWEST"
|
||||
private const val NAV_ID_SAVED = "SAVED"
|
||||
private const val COMMENT_BUTTON_DESC = "Open comments"
|
||||
|
||||
@Suppress("Unused")
|
||||
fun MacrobenchmarkScope.exploreUI(device: UiDevice) {
|
||||
startActivityAndWait()
|
||||
device.run {
|
||||
|
||||
@@ -47,14 +47,14 @@ gradlePlugin {
|
||||
id = "dev.msfjarvis.claw.kotlin-common"
|
||||
implementationClass = "dev.msfjarvis.claw.gradle.KotlinCommonPlugin"
|
||||
}
|
||||
register("kotlin-jvm") {
|
||||
id = "dev.msfjarvis.claw.kotlin-jvm"
|
||||
implementationClass = "dev.msfjarvis.claw.gradle.KotlinJvmPlugin"
|
||||
}
|
||||
register("kotlin-kapt") {
|
||||
id = "dev.msfjarvis.claw.kotlin-kapt"
|
||||
implementationClass = "dev.msfjarvis.claw.gradle.KotlinKaptPlugin"
|
||||
}
|
||||
register("kotlin-library") {
|
||||
id = "dev.msfjarvis.claw.kotlin-library"
|
||||
implementationClass = "dev.msfjarvis.claw.gradle.KotlinLibraryPlugin"
|
||||
}
|
||||
register("rename-artifacts") {
|
||||
id = "dev.msfjarvis.claw.rename-artifacts"
|
||||
implementationClass = "dev.msfjarvis.claw.gradle.RenameArtifactsPlugin"
|
||||
@@ -79,7 +79,6 @@ dependencies {
|
||||
implementation(libs.build.cachefix)
|
||||
implementation(libs.build.detekt)
|
||||
implementation(libs.build.kotlin.gradle)
|
||||
implementation(libs.build.kotlin.serialization)
|
||||
implementation(libs.build.semver)
|
||||
implementation(libs.build.spotless)
|
||||
implementation(libs.build.vcu)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2022 Harsh Shandilya.
|
||||
* Copyright © 2022-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -23,8 +23,6 @@ class ApplicationPlugin : Plugin<Project> {
|
||||
project.pluginManager.apply(AppPlugin::class)
|
||||
project.pluginManager.apply(AndroidCommonPlugin::class)
|
||||
project.extensions.configure<ApplicationExtension> {
|
||||
installation.installOptions("--user 0")
|
||||
|
||||
dependenciesInfo {
|
||||
includeInBundle = false
|
||||
includeInApk = false
|
||||
|
||||
@@ -26,13 +26,22 @@ class DependencyUpdatesPlugin : Plugin<Project> {
|
||||
when (candidate.group) {
|
||||
"com.squareup.okhttp3",
|
||||
"org.jetbrains.kotlin" -> true
|
||||
else -> false
|
||||
else -> isNonStable(candidate.version) && !isNonStable(currentVersion)
|
||||
}
|
||||
}
|
||||
checkConstraints = true
|
||||
checkBuildEnvironmentConstraints = true
|
||||
checkForGradleUpdate = true
|
||||
}
|
||||
project.extensions.configure<VersionCatalogUpdateExtension> {
|
||||
keep.keepUnusedLibraries.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isNonStable(version: String): Boolean {
|
||||
val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.uppercase().contains(it) }
|
||||
val regex = "^[0-9,.v-]+(-r)?$".toRegex()
|
||||
val isStable = stableKeyword || regex.matches(version)
|
||||
return isStable.not()
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -9,11 +9,12 @@ package dev.msfjarvis.claw.gradle
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
|
||||
|
||||
@Suppress("Unused")
|
||||
class KotlinLibraryPlugin : Plugin<Project> {
|
||||
|
||||
class KotlinJvmPlugin : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
project.pluginManager.apply(KotlinPluginWrapper::class)
|
||||
project.pluginManager.apply(KotlinCommonPlugin::class)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2022 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
|
||||
@@ -11,7 +11,6 @@ import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
||||
import com.android.build.api.variant.VariantOutputConfiguration
|
||||
import dev.msfjarvis.claw.gradle.artifacts.CollectApksTask
|
||||
import dev.msfjarvis.claw.gradle.artifacts.CollectBundleTask
|
||||
import java.util.Locale
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
@@ -24,7 +23,7 @@ class RenameArtifactsPlugin : Plugin<Project> {
|
||||
project.pluginManager.withPlugin("com.android.application") {
|
||||
project.extensions.configure<ApplicationAndroidComponentsExtension> {
|
||||
onVariants { variant ->
|
||||
val taskPrefix = "collect${variant.name.capitalize(Locale.ROOT)}"
|
||||
val taskPrefix = "collect${variant.name.replaceFirstChar { it.uppercase() }}"
|
||||
project.tasks.register<CollectApksTask>("${taskPrefix}Apks") {
|
||||
variantName.set(variant.name)
|
||||
apkFolder.set(variant.artifacts.get(SingleArtifact.APK))
|
||||
|
||||
@@ -27,7 +27,6 @@ dependencies {
|
||||
implementation(libs.androidx.browser)
|
||||
implementation(libs.androidx.compose.animation)
|
||||
implementation(libs.androidx.compose.foundation)
|
||||
implementation(libs.androidx.compose.material)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.runtime)
|
||||
implementation(libs.androidx.compose.ui.text)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
package dev.msfjarvis.claw.common
|
||||
|
||||
sealed class NetworkState {
|
||||
internal sealed class NetworkState {
|
||||
class Success<T>(val data: T) : NetworkState()
|
||||
class Error(val error: Throwable, val description: String) : NetworkState()
|
||||
object Loading : NetworkState()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -26,15 +26,16 @@ import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.msfjarvis.claw.common.posts.PostActions
|
||||
import dev.msfjarvis.claw.common.posts.PostTitle
|
||||
@@ -43,14 +44,13 @@ import dev.msfjarvis.claw.common.posts.TagRow
|
||||
import dev.msfjarvis.claw.common.res.ClawIcons
|
||||
import dev.msfjarvis.claw.common.ui.NetworkImage
|
||||
import dev.msfjarvis.claw.common.ui.ThemedRichText
|
||||
import dev.msfjarvis.claw.model.Comment
|
||||
import dev.msfjarvis.claw.model.LinkMetadata
|
||||
import dev.msfjarvis.claw.model.LobstersPostDetails
|
||||
import java.time.Instant
|
||||
import java.time.temporal.TemporalAccessor
|
||||
|
||||
@Composable
|
||||
fun CommentsHeader(
|
||||
internal fun CommentsHeader(
|
||||
postDetails: LobstersPostDetails,
|
||||
postActions: PostActions,
|
||||
htmlConverter: HTMLConverter,
|
||||
@@ -101,7 +101,7 @@ fun CommentsHeader(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PostLink(
|
||||
private fun PostLink(
|
||||
linkMetadata: LinkMetadata,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -133,18 +133,19 @@ private val CommentEntryPadding = 16f.dp
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
@Composable
|
||||
fun CommentEntry(
|
||||
comment: Comment,
|
||||
internal fun CommentEntry(
|
||||
commentNode: CommentNode,
|
||||
htmlConverter: HTMLConverter,
|
||||
toggleExpanded: (CommentNode) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var expanded by remember(comment) { mutableStateOf(true) }
|
||||
val uriHandler = LocalUriHandler.current
|
||||
val comment = commentNode.comment
|
||||
Box(
|
||||
modifier =
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { expanded = !expanded }
|
||||
.clickable { toggleExpanded(commentNode) }
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.padding(
|
||||
start = CommentEntryPadding * comment.indentLevel,
|
||||
@@ -159,6 +160,7 @@ fun CommentEntry(
|
||||
buildCommenterString(
|
||||
commenterName = comment.user.username,
|
||||
score = comment.score,
|
||||
isUnread = commentNode.isUnread,
|
||||
createdAt = comment.createdAt,
|
||||
updatedAt = comment.updatedAt,
|
||||
),
|
||||
@@ -167,7 +169,7 @@ fun CommentEntry(
|
||||
modifier =
|
||||
Modifier.clickable { uriHandler.openUri("https://lobste.rs/u/${comment.user.username}") },
|
||||
)
|
||||
AnimatedContent(targetState = expanded) { expandedState ->
|
||||
AnimatedContent(targetState = commentNode.isExpanded) { expandedState ->
|
||||
if (expandedState) {
|
||||
ThemedRichText(
|
||||
text = htmlConverter.convertHTMLToMarkdown(comment.comment),
|
||||
@@ -183,6 +185,7 @@ fun CommentEntry(
|
||||
fun buildCommenterString(
|
||||
commenterName: String,
|
||||
score: Int,
|
||||
isUnread: Boolean,
|
||||
createdAt: TemporalAccessor,
|
||||
updatedAt: TemporalAccessor,
|
||||
): AnnotatedString {
|
||||
@@ -221,5 +224,17 @@ fun buildCommenterString(
|
||||
append(updatedRelative.toString())
|
||||
append(')')
|
||||
}
|
||||
if (isUnread) {
|
||||
append(' ')
|
||||
withStyle(
|
||||
style =
|
||||
SpanStyle(
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
)
|
||||
) {
|
||||
append("(unread)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright © 2022-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.common.comments
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.Divider
|
||||
import dev.msfjarvis.claw.database.local.PostComments
|
||||
import dev.msfjarvis.claw.model.Comment
|
||||
|
||||
internal data class CommentNode(
|
||||
val comment: Comment,
|
||||
var parent: CommentNode? = null,
|
||||
val children: MutableList<CommentNode> = mutableListOf(),
|
||||
val isUnread: Boolean = false,
|
||||
var isExpanded: Boolean = true,
|
||||
) {
|
||||
fun addChild(child: CommentNode) {
|
||||
if (comment.indentLevel + 1 == child.comment.indentLevel) {
|
||||
children.add(child)
|
||||
child.parent = this
|
||||
} else {
|
||||
children.last().addChild(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createListNode(
|
||||
comments: List<Comment>,
|
||||
commentState: PostComments?
|
||||
): MutableList<CommentNode> {
|
||||
val commentNodes = mutableListOf<CommentNode>()
|
||||
val isUnread = { id: String -> commentState?.commentIds?.contains(id) == false }
|
||||
|
||||
for (i in comments.indices) {
|
||||
if (comments[i].indentLevel == 1) {
|
||||
commentNodes.add(CommentNode(comment = comments[i], isUnread = isUnread(comments[i].shortId)))
|
||||
} else {
|
||||
commentNodes
|
||||
.last()
|
||||
.addChild(CommentNode(comment = comments[i], isUnread = isUnread(comments[i].shortId)))
|
||||
}
|
||||
}
|
||||
|
||||
return commentNodes
|
||||
}
|
||||
|
||||
internal fun setExpanded(commentNode: CommentNode, expanded: Boolean): CommentNode {
|
||||
commentNode.isExpanded = expanded
|
||||
|
||||
if (commentNode.children.isNotEmpty()) {
|
||||
commentNode.children.forEach { setExpanded(it, expanded) }
|
||||
}
|
||||
return commentNode
|
||||
}
|
||||
|
||||
internal fun findTopMostParent(node: CommentNode): CommentNode {
|
||||
val parent = node.parent
|
||||
return if (parent != null) {
|
||||
findTopMostParent(parent)
|
||||
} else {
|
||||
node
|
||||
}
|
||||
}
|
||||
|
||||
internal fun LazyListScope.nodes(
|
||||
nodes: List<CommentNode>,
|
||||
htmlConverter: HTMLConverter,
|
||||
toggleExpanded: (CommentNode) -> Unit,
|
||||
) {
|
||||
nodes.forEach { node ->
|
||||
node(
|
||||
node = node,
|
||||
htmlConverter = htmlConverter,
|
||||
toggleExpanded = toggleExpanded,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun LazyListScope.node(
|
||||
node: CommentNode,
|
||||
htmlConverter: HTMLConverter,
|
||||
toggleExpanded: (CommentNode) -> Unit,
|
||||
) {
|
||||
// Skip the node if neither the node nor its parent is expanded
|
||||
if (!node.isExpanded && node.parent?.isExpanded == false) {
|
||||
return
|
||||
}
|
||||
item {
|
||||
CommentEntry(
|
||||
commentNode = node,
|
||||
htmlConverter = htmlConverter,
|
||||
toggleExpanded = toggleExpanded,
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
if (node.children.isNotEmpty()) {
|
||||
nodes(
|
||||
node.children,
|
||||
htmlConverter = htmlConverter,
|
||||
toggleExpanded = toggleExpanded,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,26 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.common.comments
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@@ -30,15 +32,23 @@ import dev.msfjarvis.claw.common.NetworkState.Success
|
||||
import dev.msfjarvis.claw.common.posts.PostActions
|
||||
import dev.msfjarvis.claw.common.ui.NetworkError
|
||||
import dev.msfjarvis.claw.common.ui.ProgressBar
|
||||
import dev.msfjarvis.claw.database.local.PostComments
|
||||
import dev.msfjarvis.claw.model.Comment
|
||||
import dev.msfjarvis.claw.model.LobstersPostDetails
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
private fun CommentsPageInternal(
|
||||
details: LobstersPostDetails,
|
||||
postActions: PostActions,
|
||||
htmlConverter: HTMLConverter,
|
||||
commentState: PostComments?,
|
||||
markSeenComments: (String, List<Comment>) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val commentNodes = createListNode(details.comments, commentState).toMutableStateList()
|
||||
LaunchedEffect(key1 = commentNodes) { markSeenComments(details.shortId, details.comments) }
|
||||
|
||||
Surface(color = MaterialTheme.colorScheme.surfaceVariant) {
|
||||
LazyColumn(modifier = modifier, contentPadding = PaddingValues(bottom = 24.dp)) {
|
||||
item {
|
||||
@@ -49,7 +59,7 @@ private fun CommentsPageInternal(
|
||||
)
|
||||
}
|
||||
|
||||
if (details.comments.isNotEmpty()) {
|
||||
if (commentNodes.isNotEmpty()) {
|
||||
item {
|
||||
Text(
|
||||
text = "Comments",
|
||||
@@ -58,12 +68,20 @@ private fun CommentsPageInternal(
|
||||
)
|
||||
}
|
||||
|
||||
itemsIndexed(details.comments) { index, item ->
|
||||
if (index != 0) {
|
||||
Divider()
|
||||
}
|
||||
CommentEntry(comment = item, htmlConverter = htmlConverter)
|
||||
}
|
||||
nodes(
|
||||
nodes = commentNodes,
|
||||
htmlConverter = htmlConverter,
|
||||
toggleExpanded = { node ->
|
||||
val newNode = setExpanded(node, !node.isExpanded)
|
||||
val parent = findTopMostParent(newNode)
|
||||
val index =
|
||||
commentNodes.indexOf(commentNodes.find { it.comment.url == parent.comment.url })
|
||||
if (index != -1) {
|
||||
commentNodes.removeAt(index)
|
||||
commentNodes.add(index, parent)
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
item {
|
||||
Text(
|
||||
@@ -79,12 +97,14 @@ private fun CommentsPageInternal(
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@Suppress("UNCHECKED_CAST", "LongParameterList")
|
||||
@Composable
|
||||
fun CommentsPage(
|
||||
postId: String,
|
||||
postActions: PostActions,
|
||||
htmlConverter: HTMLConverter,
|
||||
getSeenComments: suspend (String) -> PostComments?,
|
||||
markSeenComments: (String, List<Comment>) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val postDetails by
|
||||
@@ -95,6 +115,8 @@ fun CommentsPage(
|
||||
onFailure = { value = Error(error = it, description = "Failed to load comments") }
|
||||
)
|
||||
}
|
||||
val commentState by
|
||||
produceState<PostComments?>(initialValue = null) { value = getSeenComments(postId) }
|
||||
|
||||
when (postDetails) {
|
||||
is Success<*> -> {
|
||||
@@ -102,13 +124,25 @@ fun CommentsPage(
|
||||
details = (postDetails as Success<LobstersPostDetails>).data,
|
||||
postActions = postActions,
|
||||
htmlConverter = htmlConverter,
|
||||
commentState = commentState,
|
||||
markSeenComments = markSeenComments,
|
||||
modifier = modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
is Error -> {
|
||||
val error = postDetails as Error
|
||||
NetworkError(label = error.description, error = error.error)
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
NetworkError(
|
||||
label = error.description,
|
||||
error = error.error,
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading -> {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
ProgressBar(modifier = Modifier.align(Alignment.Center))
|
||||
}
|
||||
}
|
||||
Loading -> ProgressBar()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
*/
|
||||
package dev.msfjarvis.claw.common.comments
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
|
||||
/** Defines a contract to convert strings of HTML to Markdown. */
|
||||
@Stable
|
||||
fun interface HTMLConverter {
|
||||
fun convertHTMLToMarkdown(html: String): String
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ fun PostDetails(post: SavedPost, modifier: Modifier = Modifier) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PostTitle(
|
||||
internal fun PostTitle(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -128,7 +128,7 @@ fun PostTitle(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Submitter(
|
||||
internal fun Submitter(
|
||||
text: AnnotatedString,
|
||||
avatarUrl: String,
|
||||
contentDescription: String,
|
||||
@@ -151,7 +151,7 @@ fun Submitter(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SaveButton(
|
||||
private fun SaveButton(
|
||||
isSaved: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -169,7 +169,7 @@ fun SaveButton(
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
fun CommentsButton(
|
||||
private fun CommentsButton(
|
||||
commentCount: Int?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -200,7 +200,7 @@ fun CommentsButton(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TagRow(
|
||||
internal fun TagRow(
|
||||
tags: List<String>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -214,7 +214,7 @@ fun TagRow(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TagText(
|
||||
private fun TagText(
|
||||
tag: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
*/
|
||||
package dev.msfjarvis.claw.common.posts
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import dev.msfjarvis.claw.database.local.SavedPost
|
||||
import dev.msfjarvis.claw.model.LinkMetadata
|
||||
import dev.msfjarvis.claw.model.LobstersPostDetails
|
||||
|
||||
@Stable
|
||||
interface PostActions {
|
||||
fun viewPost(postUrl: String, commentsUrl: String)
|
||||
fun viewComments(postId: String)
|
||||
|
||||
@@ -21,6 +21,7 @@ fun LobstersPost.toDbModel(): SavedPost {
|
||||
submitterName = submitter.username,
|
||||
submitterAvatarUrl = submitter.avatarUrl,
|
||||
tags = tags,
|
||||
description = description,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -35,5 +36,6 @@ fun LobstersPostDetails.toDbModel(): SavedPost {
|
||||
submitterName = submitter.username,
|
||||
submitterAvatarUrl = submitter.avatarUrl,
|
||||
tags = tags,
|
||||
description = description,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import androidx.compose.runtime.ProvidedValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.halilibo.richtext.ui.material3.SetupMaterial3RichText
|
||||
|
||||
internal val LightThemeColors =
|
||||
private val LightThemeColors =
|
||||
lightColorScheme(
|
||||
primary = md_theme_light_primary,
|
||||
onPrimary = md_theme_light_onPrimary,
|
||||
@@ -48,7 +48,7 @@ internal val LightThemeColors =
|
||||
inverseSurface = md_theme_light_inverseSurface,
|
||||
)
|
||||
|
||||
internal val DarkThemeColors =
|
||||
private val DarkThemeColors =
|
||||
darkColorScheme(
|
||||
primary = md_theme_dark_primary,
|
||||
onPrimary = md_theme_dark_onPrimary,
|
||||
|
||||
@@ -23,7 +23,7 @@ import dev.msfjarvis.claw.common.theme.LobstersTheme
|
||||
import dev.msfjarvis.claw.common.ui.preview.ThemePreviews
|
||||
|
||||
@Composable
|
||||
fun ThemedRichText(
|
||||
internal fun ThemedRichText(
|
||||
text: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -50,7 +50,7 @@ fun ThemedRichText(
|
||||
|
||||
@ThemePreviews
|
||||
@Composable
|
||||
fun ThemedRichTextPreview() {
|
||||
internal fun ThemedRichTextPreview() {
|
||||
val text =
|
||||
"""
|
||||
### Heading
|
||||
|
||||
@@ -72,6 +72,6 @@ fun NetworkError(
|
||||
|
||||
@ThemePreviews
|
||||
@Composable
|
||||
fun NetworkErrorPreview() {
|
||||
internal fun NetworkErrorPreview() {
|
||||
LobstersTheme { NetworkError(label = "Failed to load posts", error = Throwable("Preview")) }
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import androidx.compose.ui.graphics.painter.Painter
|
||||
import coil.compose.AsyncImage
|
||||
|
||||
@Composable
|
||||
fun NetworkImage(
|
||||
internal fun NetworkImage(
|
||||
url: String?,
|
||||
placeholder: Painter,
|
||||
contentDescription: String,
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
package dev.msfjarvis.claw.common.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -16,7 +15,7 @@ import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun ProgressBar(modifier: Modifier = Modifier) {
|
||||
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
CircularProgressIndicator(color = MaterialTheme.colorScheme.secondary)
|
||||
Box(modifier = modifier, contentAlignment = Alignment.Center) {
|
||||
LinearProgressIndicator(color = MaterialTheme.colorScheme.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
|
||||
@@ -11,9 +11,11 @@ import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.platform.UriHandler
|
||||
import io.github.aakira.napier.Napier
|
||||
|
||||
@Stable
|
||||
class UrlLauncher(private val context: Context) : UriHandler {
|
||||
override fun openUri(uri: String) {
|
||||
val customTabsIntent =
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package dev.msfjarvis.claw.common.user
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -60,9 +61,19 @@ fun UserProfile(
|
||||
}
|
||||
is Error -> {
|
||||
val error = user as Error
|
||||
NetworkError(label = error.description, error = error.error)
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
NetworkError(
|
||||
label = error.description,
|
||||
error = error.error,
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading -> {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
ProgressBar(modifier = Modifier.align(Alignment.Center))
|
||||
}
|
||||
}
|
||||
Loading -> ProgressBar()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,9 +101,11 @@ private fun UserProfileInternal(
|
||||
ThemedRichText(
|
||||
text = user.about,
|
||||
)
|
||||
ThemedRichText(
|
||||
text = "Invited by [${user.invitedBy}](https://lobste.rs/u/${user.invitedBy})",
|
||||
)
|
||||
user.invitedBy?.let { invitedBy ->
|
||||
ThemedRichText(
|
||||
text = "Invited by [${invitedBy}](https://lobste.rs/u/${user.invitedBy})",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
@file:Suppress("DSL_SCOPE_VIOLATION", "UnstableApiUsage")
|
||||
|
||||
plugins {
|
||||
kotlin("android")
|
||||
id("dev.msfjarvis.claw.kotlin-common")
|
||||
id("dev.msfjarvis.claw.kotlin-android")
|
||||
id("dev.msfjarvis.claw.android-library")
|
||||
alias(libs.plugins.anvil)
|
||||
alias(libs.plugins.whetstone)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -14,14 +14,15 @@ import dagger.Provides
|
||||
import dagger.multibindings.IntoSet
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonNamingStrategy
|
||||
import okhttp3.MediaType
|
||||
import retrofit2.Converter
|
||||
|
||||
@Module
|
||||
@ContributesTo(ApplicationScope::class)
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
object RetrofitModule {
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@Provides
|
||||
@IntoSet
|
||||
fun provideJsonConverterFactory(json: Json): Converter.Factory {
|
||||
@@ -31,6 +32,9 @@ object RetrofitModule {
|
||||
|
||||
@Provides
|
||||
fun provideJsonSerializer(): Json {
|
||||
return Json { ignoreUnknownKeys = true }
|
||||
return Json {
|
||||
ignoreUnknownKeys = true
|
||||
namingStrategy = JsonNamingStrategy.SnakeCase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("dev.msfjarvis.claw.kotlin-library")
|
||||
}
|
||||
plugins { id("dev.msfjarvis.claw.kotlin-jvm") }
|
||||
|
||||
dependencies {
|
||||
api(libs.kotlinx.coroutines.core)
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
@file:Suppress("DSL_SCOPE_VIOLATION", "UnstableApiUsage")
|
||||
|
||||
plugins {
|
||||
kotlin("android")
|
||||
alias(libs.plugins.sqldelight)
|
||||
id("dev.msfjarvis.claw.kotlin-common")
|
||||
id("dev.msfjarvis.claw.kotlin-android")
|
||||
id("dev.msfjarvis.claw.android-library")
|
||||
alias(libs.plugins.anvil)
|
||||
alias(libs.plugins.sqldelight)
|
||||
alias(libs.plugins.whetstone)
|
||||
}
|
||||
|
||||
@@ -20,11 +19,13 @@ anvil { generateDaggerFactories.set(true) }
|
||||
android { namespace = "dev.msfjarvis.claw.database" }
|
||||
|
||||
sqldelight {
|
||||
database("LobstersDatabase") {
|
||||
packageName = "dev.msfjarvis.claw.database"
|
||||
sourceFolders = listOf("sqldelight")
|
||||
schemaOutputDirectory = file("src/main/sqldelight/databases")
|
||||
verifyMigrations = true
|
||||
databases {
|
||||
create("LobstersDatabase") {
|
||||
packageName.set("dev.msfjarvis.claw.database")
|
||||
sourceFolders.set(listOf("sqldelight"))
|
||||
schemaOutputDirectory.set(file("src/main/sqldelight/databases"))
|
||||
verifyMigrations.set(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -15,8 +15,9 @@ import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dev.msfjarvis.claw.database.LobstersDatabase
|
||||
import dev.msfjarvis.claw.database.local.PostComments
|
||||
import dev.msfjarvis.claw.database.local.SavedPost
|
||||
import dev.msfjarvis.claw.database.model.TagsAdapter
|
||||
import dev.msfjarvis.claw.database.model.CSVAdapter
|
||||
|
||||
@Module
|
||||
@ContributesTo(ApplicationScope::class)
|
||||
@@ -27,6 +28,10 @@ object DatabaseModule {
|
||||
@Provides
|
||||
fun provideDatabase(@ForScope(ApplicationScope::class) context: Context): LobstersDatabase {
|
||||
val driver = AndroidSqliteDriver(LobstersDatabase.Schema, context, LOBSTERS_DATABASE_NAME)
|
||||
return LobstersDatabase(driver, SavedPost.Adapter(IntColumnAdapter, TagsAdapter()))
|
||||
return LobstersDatabase(
|
||||
driver,
|
||||
PostComments.Adapter(CSVAdapter()),
|
||||
SavedPost.Adapter(IntColumnAdapter, CSVAdapter()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.database.local
|
||||
|
||||
import android.content.Context
|
||||
import app.cash.sqldelight.adapter.primitive.IntColumnAdapter
|
||||
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
|
||||
import dev.msfjarvis.claw.database.LobstersDatabase
|
||||
import dev.msfjarvis.claw.database.model.TagsAdapter
|
||||
|
||||
internal const val LobstersDatabaseName = "SavedPosts.db"
|
||||
|
||||
fun createDatabase(context: Context): LobstersDatabase {
|
||||
val driver = AndroidSqliteDriver(LobstersDatabase.Schema, context, LobstersDatabaseName)
|
||||
return LobstersDatabase(driver, SavedPost.Adapter(IntColumnAdapter, TagsAdapter()))
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -8,7 +8,7 @@ package dev.msfjarvis.claw.database.model
|
||||
|
||||
import app.cash.sqldelight.ColumnAdapter
|
||||
|
||||
class TagsAdapter : ColumnAdapter<List<String>, String> {
|
||||
class CSVAdapter : ColumnAdapter<List<String>, String> {
|
||||
override fun decode(databaseValue: String): List<String> {
|
||||
return databaseValue.split(SEPARATOR)
|
||||
}
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE SavedPost
|
||||
ADD COLUMN description TEXT NOT NULL DEFAULT "";
|
||||
@@ -0,0 +1,7 @@
|
||||
import kotlin.String;
|
||||
import kotlin.collections.List;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS PostComments(
|
||||
postId TEXT NOT NULL PRIMARY KEY,
|
||||
commentIds TEXT AS List<String> NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
import kotlin.String;
|
||||
import kotlin.collections.List;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS PostComments(
|
||||
postId TEXT NOT NULL PRIMARY KEY,
|
||||
commentIds TEXT AS List<String> NOT NULL
|
||||
);
|
||||
|
||||
rememberComments:
|
||||
INSERT OR REPLACE
|
||||
INTO PostComments
|
||||
VALUES ?;
|
||||
|
||||
getCommentIds:
|
||||
SELECT *
|
||||
FROM PostComments
|
||||
WHERE postId = ?;
|
||||
@@ -11,7 +11,8 @@ CREATE TABLE IF NOT EXISTS SavedPost(
|
||||
commentsUrl TEXT NOT NULL,
|
||||
submitterName TEXT NOT NULL,
|
||||
submitterAvatarUrl TEXT NOT NULL,
|
||||
tags TEXT AS List<String> NOT NULL
|
||||
tags TEXT AS List<String> NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT ""
|
||||
);
|
||||
|
||||
insertOrReplacePost:
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright © 2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.database.local
|
||||
|
||||
import app.cash.sqldelight.adapter.primitive.IntColumnAdapter
|
||||
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
|
||||
import dev.msfjarvis.claw.database.LobstersDatabase
|
||||
import dev.msfjarvis.claw.database.model.CSVAdapter
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.collections.shouldHaveSize
|
||||
import io.kotest.matchers.shouldBe
|
||||
import java.util.UUID
|
||||
|
||||
class PostCommentsQueriesTest : FunSpec() {
|
||||
private lateinit var postQueries: PostCommentsQueries
|
||||
init {
|
||||
beforeEach {
|
||||
val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
|
||||
LobstersDatabase.Schema.create(driver)
|
||||
val database =
|
||||
LobstersDatabase(
|
||||
driver,
|
||||
PostComments.Adapter(CSVAdapter()),
|
||||
SavedPost.Adapter(IntColumnAdapter, CSVAdapter()),
|
||||
)
|
||||
postQueries = database.postCommentsQueries
|
||||
}
|
||||
|
||||
test("get non-existent post") {
|
||||
val ids = postQueries.getCommentIds(UUID.randomUUID().toString()).executeAsOneOrNull()
|
||||
ids shouldBe null
|
||||
}
|
||||
|
||||
test("put and get post comments") {
|
||||
val postId = UUID.randomUUID().toString()
|
||||
val comments = PostComments(postId, List(10) { UUID.randomUUID().toString() })
|
||||
postQueries.rememberComments(comments)
|
||||
|
||||
val ids = postQueries.getCommentIds(postId).executeAsOne().commentIds
|
||||
ids shouldHaveSize 10
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -9,13 +9,13 @@ package dev.msfjarvis.claw.database.local
|
||||
import app.cash.sqldelight.adapter.primitive.IntColumnAdapter
|
||||
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
|
||||
import dev.msfjarvis.claw.database.LobstersDatabase
|
||||
import dev.msfjarvis.claw.database.model.TagsAdapter
|
||||
import dev.msfjarvis.claw.database.model.CSVAdapter
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.collections.shouldBeEmpty
|
||||
import io.kotest.matchers.collections.shouldHaveSize
|
||||
import io.kotest.matchers.shouldBe
|
||||
|
||||
class SqlDelightQueriesTest : FunSpec() {
|
||||
class SavedPostQueriesTest : FunSpec() {
|
||||
|
||||
private lateinit var postQueries: SavedPostQueries
|
||||
|
||||
@@ -26,7 +26,8 @@ class SqlDelightQueriesTest : FunSpec() {
|
||||
val database =
|
||||
LobstersDatabase(
|
||||
driver,
|
||||
SavedPost.Adapter(IntColumnAdapter, TagsAdapter()),
|
||||
PostComments.Adapter(CSVAdapter()),
|
||||
SavedPost.Adapter(IntColumnAdapter, CSVAdapter()),
|
||||
)
|
||||
postQueries = database.savedPostQueries
|
||||
}
|
||||
@@ -131,6 +132,7 @@ class SqlDelightQueriesTest : FunSpec() {
|
||||
submitterName = "test_user_$i",
|
||||
submitterAvatarUrl = "test_avatar_url",
|
||||
tags = listOf(),
|
||||
description = "",
|
||||
)
|
||||
|
||||
posts.add(post)
|
||||
+2
-18
@@ -31,19 +31,12 @@ android.injected.testOnly=false
|
||||
kotlin.incremental.useClasspathSnapshot=true
|
||||
kotlin.build.report.output=file
|
||||
|
||||
# Disable Gradle task that breaks configuration caching
|
||||
kotlin.mpp.enableKotlinToolingMetadataArtifact=false
|
||||
|
||||
# Use R8 instead of ProGuard for code shrinking.
|
||||
android.enableR8.fullMode=false
|
||||
|
||||
# Enable AndroidX
|
||||
android.useAndroidX=true
|
||||
|
||||
# Kotlin Multiplatform
|
||||
kotlin.mpp.stability.nowarn=true
|
||||
import_orphan_source_sets=false
|
||||
|
||||
# Enable non-transitive R class namespacing where each library only contains
|
||||
# references to the resources it declares instead of declarations plus all
|
||||
# transitive dependency references.
|
||||
@@ -63,21 +56,12 @@ android.defaults.buildfeatures.shaders=false
|
||||
# Experimental features
|
||||
android.disableEarlyManifestParsing=true
|
||||
android.enablePartialRIncrementalBuilds=true
|
||||
# TODO: enable once we're back on AGP 8.x
|
||||
# android.experimental.testOptions.uninstallIncompatibleApks=true
|
||||
android.experimental.testOptions.uninstallIncompatibleApks=true
|
||||
android.enableBuildConfigAsBytecode=true
|
||||
android.experimental.enableNewResourceShrinker.preciseShrinking=true
|
||||
|
||||
# Disable warnings about unsupported features, we know what we're doing
|
||||
android.suppressUnsupportedOptionWarnings=android.disableEarlyManifestParsing,android.enablePartialRIncrementalBuilds,android.enableBuildConfigAsBytecode,android.experimental.enableNewResourceShrinker.preciseShrinking,android.suppressUnsupportedOptionWarnings
|
||||
|
||||
# Maven publishing
|
||||
GROUP=com.github.android-password-store
|
||||
|
||||
# OSSRH sometimes struggles with slow deployments, so this makes Gradle
|
||||
# more tolerant to those delays.
|
||||
systemProp.org.gradle.internal.http.connectionTimeout=500000
|
||||
systemProp.org.gradle.internal.http.socketTimeout=500000
|
||||
android.suppressUnsupportedOptionWarnings=android.disableEarlyManifestParsing,android.enablePartialRIncrementalBuilds,android.experimental.testOptions.uninstallIncompatibleApks,android.enableBuildConfigAsBytecode,android.experimental.enableNewResourceShrinker.preciseShrinking,android.suppressUnsupportedOptionWarnings
|
||||
|
||||
# Add opens for KAPT
|
||||
# https://youtrack.jetbrains.com/issue/KT-45545#focus=Comments-27-4862682.0-0
|
||||
|
||||
+23
-23
@@ -1,32 +1,32 @@
|
||||
[versions]
|
||||
accompanist = "0.28.0"
|
||||
# @pin https://issuetracker.google.com/issues/259556213
|
||||
agp = "7.3.1"
|
||||
agp = "7.4.0"
|
||||
androidx-compose-ui = "1.4.0-alpha04"
|
||||
androidx-test = "1.5.0"
|
||||
coil = "2.2.2"
|
||||
# @keep used for kotlinCompilerExtensionVersion
|
||||
composeCompiler = "1.4.0-alpha02"
|
||||
composeCompiler = "1.4.0"
|
||||
coroutines = "1.6.4"
|
||||
dagger = "2.44.2"
|
||||
kotest = "5.5.4"
|
||||
kotlin = "1.7.21"
|
||||
kotlin = "1.8.0"
|
||||
# @pin Needs to be aligned with Retrofit
|
||||
okhttp = "3.14.9"
|
||||
retrofit = "2.9.0"
|
||||
richtext = "0.16.0"
|
||||
serialization = "1.4.1"
|
||||
sqldelight = "2.0.0-alpha04"
|
||||
whetstone = "0.5.0-SNAPSHOT"
|
||||
serialization = "1.5.0-RC"
|
||||
sqldelight = "2.0.0-alpha05"
|
||||
whetstone = "0.6.0-SNAPSHOT"
|
||||
workmanager = "2.8.0-rc01"
|
||||
|
||||
[libraries]
|
||||
accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", version.ref = "accompanist" }
|
||||
accompanist-sysuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" }
|
||||
androidx-activity-compose = "androidx.activity:activity-compose:1.7.0-alpha02"
|
||||
androidx-benchmark-macro-junit4 = "androidx.benchmark:benchmark-macro-junit4:1.2.0-alpha08"
|
||||
androidx-browser = "androidx.browser:browser:1.5.0-alpha02"
|
||||
androidx-activity-compose = "androidx.activity:activity-compose:1.7.0-alpha04"
|
||||
androidx-benchmark-macro-junit4 = "androidx.benchmark:benchmark-macro-junit4:1.2.0-alpha09"
|
||||
androidx-browser = "androidx.browser:browser:1.5.0-rc01"
|
||||
androidx-compose-animation = { module = "androidx.compose.animation:animation" }
|
||||
androidx-compose-bom = "androidx.compose:compose-bom:2022.12.00"
|
||||
androidx-compose-bom = "androidx.compose:compose-bom:2023.01.00"
|
||||
androidx-compose-foundation = { module = "androidx.compose.foundation:foundation" }
|
||||
androidx-compose-material = { module = "androidx.compose.material:material" }
|
||||
androidx-compose-material3 = { module = "androidx.compose.material3:material3" }
|
||||
@@ -36,24 +36,23 @@ androidx-compose-ui-text = { module = "androidx.compose.ui:ui-text" }
|
||||
androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
|
||||
androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
|
||||
androidx-core-splashscreen = "androidx.core:core-splashscreen:1.0.0"
|
||||
androidx-lifecycle-compose = "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.0-alpha03"
|
||||
androidx-lifecycle-compose = "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.0-alpha05"
|
||||
androidx-navigation-compose = "androidx.navigation:navigation-compose:2.6.0-alpha04"
|
||||
androidx-paging-compose = "androidx.paging:paging-compose:1.0.0-alpha17"
|
||||
androidx-profileinstaller = "androidx.profileinstaller:profileinstaller:1.3.0-alpha02"
|
||||
androidx-profileinstaller = "androidx.profileinstaller:profileinstaller:1.3.0-alpha03"
|
||||
androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test" }
|
||||
androidx-test-espresso-core = "androidx.test.espresso:espresso-core:3.5.0"
|
||||
androidx-test-ext-junit = "androidx.test.ext:junit:1.1.4"
|
||||
androidx-test-espresso-core = "androidx.test.espresso:espresso-core:3.5.1"
|
||||
androidx-test-ext-junit = "androidx.test.ext:junit:1.1.5"
|
||||
androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidx-test" }
|
||||
androidx-test-runner = "androidx.test:runner:1.5.1"
|
||||
androidx-test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha01"
|
||||
androidx-test-runner = "androidx.test:runner:1.5.2"
|
||||
androidx-test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha02"
|
||||
androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workmanager" }
|
||||
build-agp = { module = "com.android.tools.build:gradle", version.ref = "agp" }
|
||||
build-cachefix = "org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin:2.6.0"
|
||||
build-cachefix = "org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin:2.6.1"
|
||||
build-detekt = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.22.0"
|
||||
build-kotlin-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
build-kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" }
|
||||
build-semver = "com.vdurmont:semver4j:3.1.0"
|
||||
build-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.12.0"
|
||||
build-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.14.0"
|
||||
build-vcu = "nl.littlerobots.version-catalog-update:nl.littlerobots.version-catalog-update.gradle.plugin:0.7.0"
|
||||
build-versions = "com.github.ben-manes:gradle-versions-plugin:0.44.0"
|
||||
coil = { module = "io.coil-kt:coil", version.ref = "coil" }
|
||||
@@ -65,12 +64,12 @@ copydown = "io.github.furstenheim:copy_down:1.1"
|
||||
crux = "com.chimbori.crux:crux:3.11.0"
|
||||
dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" }
|
||||
dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" }
|
||||
eithernet = "com.slack.eithernet:eithernet:1.2.1"
|
||||
eithernet = "com.slack.eithernet:eithernet:1.3.1"
|
||||
javapoet = "com.squareup:javapoet:1.13.0"
|
||||
javax-inject = "javax.inject:javax.inject:1"
|
||||
jsoup = "org.jsoup:jsoup:1.15.3"
|
||||
kotest-runner-junit5 = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" }
|
||||
kotest-assertions-core = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" }
|
||||
kotest-runner-junit5 = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
|
||||
kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "serialization" }
|
||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" }
|
||||
@@ -88,6 +87,7 @@ whetstone = { module = "com.deliveryhero.whetstone:whetstone", version.ref = "wh
|
||||
|
||||
[plugins]
|
||||
android-test = { id = "com.android.test", version.ref = "agp" }
|
||||
anvil = "com.squareup.anvil:2.4.2"
|
||||
anvil = "com.squareup.anvil:2.4.4"
|
||||
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }
|
||||
whetstone = { id = "dev.msfjarvis.whetstone", version.ref = "whetstone" }
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=7ba68c54029790ab444b39d7e293d3236b2632631fb5f2e012bb28b4ff669e4b
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
distributionSha256Sum=28ebe9afc20564bcdc39bfe36f6b60a373e40be2c3c307a0028b545b8ccf6ba0
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-rc-2-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
@file:Suppress("DSL_SCOPE_VIOLATION", "UnstableApiUsage")
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("dev.msfjarvis.claw.kotlin-library")
|
||||
}
|
||||
plugins { id("dev.msfjarvis.claw.kotlin-jvm") }
|
||||
|
||||
dependencies {
|
||||
api(libs.crux)
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
@file:Suppress("DSL_SCOPE_VIOLATION", "UnstableApiUsage")
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
kotlin("plugin.serialization")
|
||||
id("dev.msfjarvis.claw.kotlin-common")
|
||||
id("dev.msfjarvis.claw.kotlin-jvm")
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
}
|
||||
|
||||
dependencies { implementation(libs.kotlinx.serialization.core) }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -15,15 +15,12 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class Comment(
|
||||
val shortId: String,
|
||||
val comment: String,
|
||||
val url: String,
|
||||
val score: Int,
|
||||
@Serializable(with = JavaInstantSerializer::class)
|
||||
@SerialName("created_at")
|
||||
val createdAt: TemporalAccessor,
|
||||
@Serializable(with = JavaInstantSerializer::class)
|
||||
@SerialName("updated_at")
|
||||
val updatedAt: TemporalAccessor,
|
||||
@SerialName("indent_level") val indentLevel: Int,
|
||||
@Serializable(with = JavaInstantSerializer::class) val createdAt: TemporalAccessor,
|
||||
@Serializable(with = JavaInstantSerializer::class) val updatedAt: TemporalAccessor,
|
||||
val indentLevel: Int,
|
||||
@SerialName("commenting_user") val user: User,
|
||||
)
|
||||
|
||||
@@ -13,13 +13,13 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class LobstersPost(
|
||||
@SerialName("short_id") val shortId: String,
|
||||
@SerialName("created_at") val createdAt: String,
|
||||
val shortId: String,
|
||||
val createdAt: String,
|
||||
val title: String,
|
||||
val url: String,
|
||||
val description: String,
|
||||
@SerialName("comment_count") val commentCount: Int,
|
||||
@SerialName("comments_url") val commentsUrl: String,
|
||||
val commentCount: Int,
|
||||
val commentsUrl: String,
|
||||
@SerialName("submitter_user") val submitter: User,
|
||||
val tags: List<String>,
|
||||
)
|
||||
|
||||
@@ -13,13 +13,13 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class LobstersPostDetails(
|
||||
@SerialName("short_id") val shortId: String,
|
||||
@SerialName("created_at") val createdAt: String,
|
||||
val shortId: String,
|
||||
val createdAt: String,
|
||||
val title: String,
|
||||
val url: String,
|
||||
val description: String,
|
||||
@SerialName("comment_count") val commentCount: Int,
|
||||
@SerialName("comments_url") val commentsUrl: String,
|
||||
val commentCount: Int,
|
||||
val commentsUrl: String,
|
||||
@SerialName("submitter_user") val submitter: User,
|
||||
val tags: List<String>,
|
||||
val comments: List<Comment>,
|
||||
|
||||
@@ -15,7 +15,7 @@ import kotlinx.serialization.Serializable
|
||||
class User(
|
||||
val username: String,
|
||||
val about: String,
|
||||
@SerialName("invited_by_user") val invitedBy: String,
|
||||
@SerialName("avatar_url") val avatarUrl: String,
|
||||
@SerialName("created_at") val createdAt: String,
|
||||
@SerialName("invited_by_user") val invitedBy: String?,
|
||||
val avatarUrl: String,
|
||||
val createdAt: String,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version: "1.0"
|
||||
# Also update renovate.json when the linter is changed
|
||||
linter: jetbrains/qodana-jvm-android:2022.3-eap
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
TEMP_DIR="$(mktemp -d)"
|
||||
BIN_DIR=""
|
||||
AGE_VERSION="v1.0.0"
|
||||
AGE_FILE=""
|
||||
|
||||
case "$(uname)" in
|
||||
Linux)
|
||||
AGE_FILE="age-${AGE_VERSION}-linux-amd64.tar.gz"
|
||||
BIN_DIR="${HOME}/.local/bin"
|
||||
;;
|
||||
Darwin)
|
||||
AGE_FILE="age-${AGE_VERSION}-darwin-amd64.tar.gz"
|
||||
BIN_DIR="${HOME}/bin"
|
||||
;;
|
||||
*) echo "Unsupported system: $(uname)"; exit 1 ;;
|
||||
esac
|
||||
|
||||
pushd "${TEMP_DIR}"
|
||||
|
||||
curl -L --silent --show-error --retry 3 --fail -o age.tar.gz "https://github.com/FiloSottile/age/releases/download/v1.0.0/${AGE_FILE:?}"
|
||||
tar xvf age.tar.gz
|
||||
rm age/LICENSE
|
||||
mkdir -p "${BIN_DIR}"
|
||||
mv -v age/age "${BIN_DIR}" && chmod +x "${BIN_DIR}/age"
|
||||
mv -v age/age-keygen "${BIN_DIR}" && chmod +x "${BIN_DIR}/age-keygen"
|
||||
|
||||
popd
|
||||
+17
-11
@@ -2,16 +2,22 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ENCRYPT_KEY="${1:-}"
|
||||
ENCRYPT_KEY="${1}"
|
||||
TEMP_KEY="$(mktemp)"
|
||||
|
||||
declare -A SECRETS
|
||||
SECRETS[secrets/keystore.cipher]=keystore.jks
|
||||
SECRETS[secrets/props.cipher]=keystore.properties
|
||||
trap "rm -rf ${TEMP_KEY} 2>/dev/null" INT TERM EXIT
|
||||
|
||||
if [[ -n "$ENCRYPT_KEY" ]]; then
|
||||
for src in "${!SECRETS[@]}"; do
|
||||
openssl enc -aes-256-cbc -md sha256 -pbkdf2 -d -in "${src}" -out "${SECRETS[${src}]}" -k "${ENCRYPT_KEY}"
|
||||
done
|
||||
else
|
||||
echo "Usage: ./signing-setup.sh <encryption key>"
|
||||
fi
|
||||
echo "${ENCRYPT_KEY:?}" > "${TEMP_KEY}"
|
||||
|
||||
function decrypt() {
|
||||
if ! command -v age 1>/dev/null; then
|
||||
echo "age not installed"
|
||||
exit 1
|
||||
fi
|
||||
SRC="${1}"
|
||||
DST="${2}"
|
||||
age --decrypt -i "${TEMP_KEY}" -o "${DST:?}" "${SRC:?}"
|
||||
}
|
||||
|
||||
decrypt secrets/keystore.cipher keystore.jks
|
||||
decrypt secrets/props.cipher keystore.properties
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+3
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2021-2022 Harsh Shandilya.
|
||||
* Copyright © 2021-2023 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
@@ -26,21 +26,12 @@ pluginManagement {
|
||||
includeModule("com.android.test", "com.android.test.gradle.plugin")
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository { maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") }
|
||||
filter {
|
||||
includeGroupByRegex("org\\.jetbrains\\.compose.*")
|
||||
includeGroup("org.jetbrains.skiko")
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository { gradlePluginPortal() }
|
||||
filter {
|
||||
includeModule("com.github.ben-manes", "gradle-versions-plugin")
|
||||
includeModule("org.gradle.android.cache-fix", "org.gradle.android.cache-fix.gradle.plugin")
|
||||
includeModule("gradle.plugin.org.gradle.android", "android-cache-fix-gradle-plugin")
|
||||
includeModule("com.sergei-lapin.napt", "com.sergei-lapin.napt.gradle.plugin")
|
||||
includeModule("com.sergei-lapin.napt", "gradle")
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
@@ -80,6 +71,7 @@ dependencyResolutionManagement {
|
||||
includeGroup("androidx.customview")
|
||||
includeGroup("androidx.databinding")
|
||||
includeGroup("androidx.drawerlayout")
|
||||
includeGroup("androidx.emoji2")
|
||||
includeGroup("androidx.exifinterface")
|
||||
includeGroup("androidx.fragment")
|
||||
includeGroup("androidx.interpolator")
|
||||
@@ -88,6 +80,7 @@ dependencyResolutionManagement {
|
||||
includeGroup("androidx.navigation")
|
||||
includeGroup("androidx.paging")
|
||||
includeGroup("androidx.profileinstaller")
|
||||
includeGroup("androidx.resourceinspection")
|
||||
includeGroup("androidx.room")
|
||||
includeGroup("androidx.savedstate")
|
||||
includeGroup("androidx.startup")
|
||||
@@ -118,13 +111,6 @@ dependencyResolutionManagement {
|
||||
includeModule("com.google.android.material", "material")
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository { maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") }
|
||||
filter {
|
||||
includeGroupByRegex("org\\.jetbrains\\.compose.*")
|
||||
includeGroup("org.jetbrains.skiko")
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository { maven("https://oss.sonatype.org/content/repositories/snapshots/") }
|
||||
filter { includeGroup("dev.msfjarvis.whetstone") }
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
{ pkgs ? import <nixpkgs> { config.android_sdk.accept_license = true; } }:
|
||||
|
||||
let
|
||||
androidComposition = pkgs.androidenv.composeAndroidPackages {
|
||||
toolsVersion = "26.1.1";
|
||||
platformToolsVersion = "31.0.3";
|
||||
buildToolsVersions = [ "31.0.0" ];
|
||||
includeEmulator = false;
|
||||
emulatorVersion = "30.9.0";
|
||||
platformVersions = [ "31" ];
|
||||
includeSources = false;
|
||||
includeSystemImages = false;
|
||||
systemImageTypes = [ ];
|
||||
abiVersions = [ ];
|
||||
cmakeVersions = [ ];
|
||||
includeNDK = false;
|
||||
ndkVersions = [ ];
|
||||
useGoogleAPIs = false;
|
||||
useGoogleTVAddOns = false;
|
||||
includeExtras = [ ];
|
||||
};
|
||||
in pkgs.mkShell rec {
|
||||
ANDROID_SDK_ROOT = "${androidComposition.androidsdk}/libexec/android-sdk";
|
||||
buildInputs = with pkgs; [ gradle glibc zlib ];
|
||||
}
|
||||
Reference in New Issue
Block a user