Compare commits

..
751 Commits
Author SHA1 Message Date
GitHub Actions deb900f8f8 feat(release): bump version 2023-10-06 08:47:17 +00:00
Harsh Shandilya e6f6ed75f1 chore: update changelog 2023-10-06 14:03:59 +05:30
Harsh Shandilya 6226c3b0c8 fix(common): prevent crashing when parsing comment trees
Fixes COMPOSE-LOBSTERS-1Z
2023-10-06 13:51:18 +05:30
Harsh Shandilya 1a525d6e5d fix(android): avoid violating sorting contract
Fixes COMPOSE-LOBSTERS-1J
2023-10-06 13:47:58 +05:30
Harsh Shandilya bc213fe3c9 chore: make rgignore common 2023-10-06 12:21:10 +05:30
Harsh Shandilya 731666936c fix(android): prevent crashes when <50 saved posts exist
Fixes COMPOSE-LOBSTERS-25
2023-10-06 12:21:10 +05:30
renovate[bot]andGitHub 67ec7e92b5 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-collections-immutable to v0.3.6 2023-10-06 01:24:19 +00:00
renovate[bot]andGitHub 40bfcb07b6 chore(deps): update agp to v8.3.0-alpha07 2023-10-05 22:19:05 +00:00
renovate[bot]andGitHub e5f09a7aef chore(deps): update dependency gradle to v8.4 2023-10-04 23:27:29 +00:00
renovate[bot]andGitHub 341bdb0eda fix(deps): update androidx 2023-10-04 17:56:34 +00:00
Harsh ShandilyaandGitHub 27d68f2774 fix(deps): update compose-bom to v2023.11.00-alpha01
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-10-04 23:26:16 +05:30
GitHub Actions d259cd8eb5 feat(release): start next development iteration 2023-10-04 13:34:35 +00:00
GitHub Actions c9e5ded43a feat(release): bump version 2023-10-04 13:30:30 +00:00
renovate[bot]andGitHub a8e03e22bf fix(deps): update dagger to v2.48.1 2023-10-03 22:31:04 +00:00
Harsh Shandilya 7094016e7e chore: update changelog 2023-10-03 23:37:32 +05:30
Harsh Shandilya 1bfa1f3981 Revert "Revert "fix(deps): use Swipe snapshots""
Maybe fixed by new Compose BOM?

This reverts commit 3cf6b22d95.
2023-10-03 22:43:34 +05:30
Harsh Shandilya 655745e049 fix(deps): upgrade to Compose Compiler 1.5.3 2023-10-03 22:43:34 +05:30
Harsh Shandilya f83a22b310 fix(deps): update compose-bom to 2023.10.00-alpha02 2023-10-03 22:43:34 +05:30
Harsh Shandilya 025c24a9d9 feat(android): switch to M3-compatible pull to refresh 2023-10-03 22:43:34 +05:30
renovate[bot]andGitHub c8c3e83e7b chore(deps): update gradle/gradle-build-action digest to 842c587 2023-10-01 01:43:33 +00:00
renovate[bot]andGitHub 7d8327af18 chore(deps): update gradle/gradle-build-action action to v2.9.0 2023-09-29 22:36:21 +00:00
Harsh Shandilya 58bab2f538 refactor(android): DRY 2023-09-30 02:45:43 +05:30
Harsh Shandilya cf93eda6c1 chore: update changelog 2023-09-30 02:43:56 +05:30
Harsh Shandilya a3b7af0f79 feat(android): add separate touch actions for widget title and comment count 2023-09-30 02:43:56 +05:30
Harsh Shandilya 91bf5e5555 fix(android): sort saved posts in view model 2023-09-30 02:03:20 +05:30
Harsh Shandilya 61a72b330d fix(android): rollback widget size to 5x2 2023-09-30 02:03:20 +05:30
Harsh Shandilya 6a1164363c feat(android): fix saved posts widget layout 2023-09-30 02:03:20 +05:30
Harsh Shandilya df9a82482c fix(android): dispatch widget update when toggling save state 2023-09-30 01:51:57 +05:30
Harsh Shandilya 778d98c7f2 fix(android): limit widget to 50 posts 2023-09-30 01:51:57 +05:30
Harsh Shandilya cae759a09e Merge remote-tracking branches 'origin/renovate/sentry' and 'origin/renovate/org.gradle.android.cache-fix-org.gradle.android.cache-fix.gradle.plugin-2.x'
* origin/renovate/sentry:
  fix(deps): update dependency io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin to v3.13.0

* origin/renovate/org.gradle.android.cache-fix-org.gradle.android.cache-fix.gradle.plugin-2.x:
  fix(deps): update dependency org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin to v2.8.1
2023-09-29 23:19:35 +05:30
renovate[bot]andGitHub 52126b2248 fix(deps): update dependency io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin to v3.13.0 2023-09-29 17:13:29 +00:00
renovate[bot]andGitHub 5782521824 fix(deps): update dependency org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin to v2.8.1 2023-09-29 17:13:26 +00:00
Harsh Shandilya 3522dc529d fix(build): prevent invalid lints failing build 2023-09-29 12:06:52 +05:30
Harsh Shandilya 8602e68b60 Merge remote-tracking branches 'origin/renovate/agp' and 'origin/renovate/com.diffplug.spotless-spotless-plugin-gradle-6.x'
* origin/renovate/agp:
  chore(deps): update dependency com.android.test to v8.3.0-alpha06

* origin/renovate/com.diffplug.spotless-spotless-plugin-gradle-6.x:
  fix(deps): update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.22.0
2023-09-29 11:54:16 +05:30
renovate[bot]andGitHub fb4514d70e fix(deps): update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.22.0 2023-09-29 00:41:48 +00:00
renovate[bot]andGitHub 35d86bff11 chore(deps): update dependency com.android.test to v8.3.0-alpha06 2023-09-28 21:25:13 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
193730e16c fix(deps): update sentry to v6.30.0 (#400)
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[io.sentry:sentry-android-okhttp](https://togithub.com/getsentry/sentry-java)
| `6.29.0` -> `6.30.0` |
[![age](https://developer.mend.io/api/mc/badges/age/maven/io.sentry:sentry-android-okhttp/6.30.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/io.sentry:sentry-android-okhttp/6.30.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/io.sentry:sentry-android-okhttp/6.29.0/6.30.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/io.sentry:sentry-android-okhttp/6.29.0/6.30.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [io.sentry:sentry-bom](https://togithub.com/getsentry/sentry-java) |
`6.29.0` -> `6.30.0` |
[![age](https://developer.mend.io/api/mc/badges/age/maven/io.sentry:sentry-bom/6.30.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/io.sentry:sentry-bom/6.30.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/io.sentry:sentry-bom/6.29.0/6.30.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/io.sentry:sentry-bom/6.29.0/6.30.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>getsentry/sentry-java
(io.sentry:sentry-android-okhttp)</summary>

###
[`v6.30.0`](https://togithub.com/getsentry/sentry-java/blob/HEAD/CHANGELOG.md#6300)

[Compare
Source](https://togithub.com/getsentry/sentry-java/compare/6.29.0...6.30.0)

##### Features

- Add `sendModules` option for disable sending modules
([#&#8203;2926](https://togithub.com/getsentry/sentry-java/pull/2926))
- Send `db.system` and `db.name` in span data for androidx.sqlite spans
([#&#8203;2928](https://togithub.com/getsentry/sentry-java/pull/2928))
- Check-ins (CRONS) support
([#&#8203;2952](https://togithub.com/getsentry/sentry-java/pull/2952))
- Add API for sending check-ins (CRONS) manually
([#&#8203;2935](https://togithub.com/getsentry/sentry-java/pull/2935))
- Support check-ins (CRONS) for Quartz
([#&#8203;2940](https://togithub.com/getsentry/sentry-java/pull/2940))
- `@SentryCheckIn` annotation and advice config for Spring
([#&#8203;2946](https://togithub.com/getsentry/sentry-java/pull/2946))
- Add option for ignoring certain monitor slugs
([#&#8203;2943](https://togithub.com/getsentry/sentry-java/pull/2943))

##### Fixes

- Always send memory stats for transactions
([#&#8203;2936](https://togithub.com/getsentry/sentry-java/pull/2936))
- This makes it possible to query transactions by the `device.class` tag
on Sentry
- Add `sentry.enable-aot-compatibility` property to SpringBoot Jakarta
`SentryAutoConfiguration` to enable building for GraalVM
([#&#8203;2915](https://togithub.com/getsentry/sentry-java/pull/2915))

##### Dependencies

- Bump Gradle from v8.2.1 to v8.3.0
([#&#8203;2900](https://togithub.com/getsentry/sentry-java/pull/2900))
- \[changelog]\(https://github.com/gradle/gradle/blob/master
release-test/CHANGELOG.md#v830)
- [diff](https://togithub.com/gradle/gradle/compare/v8.2.1...v8.3.0)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/msfjarvis/compose-lobsters).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi4xMDcuMiIsInVwZGF0ZWRJblZlciI6IjM2LjEwNy4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-28 09:50:08 +00:00
Harsh Shandilya ed32186984 refactor(build): adopt Slack lints 2023-09-28 15:14:36 +05:30
renovate[bot]andGitHub eb449740eb chore(deps): update github/codeql-action action to v2.21.9 2023-09-27 16:36:31 +00:00
renovate[bot]andGitHub 327fd43dd6 fix(deps): update dependency com.slack.eithernet:eithernet to v1.6.0 2023-09-27 00:12:38 +00:00
renovate[bot]andGitHub bc2345f415 chore(deps): update plugin licensee to v1.8.0 2023-09-26 21:30:38 +00:00
Harsh Shandilya fd1bdc79f8 feat(README): use theme-context for feature graphics 2023-09-26 17:17:45 +05:30
Harsh Shandilya 22a2419185 feat(scripts): generate dark and light feature graphics 2023-09-26 17:16:46 +05:30
Harsh Shandilya de921bf786 chore(scripts): run shfmt 2023-09-26 17:12:02 +05:30
Harsh Shandilya 3cf6b22d95 Revert "fix(deps): use Swipe snapshots"
Somehow breaks R8, don't really care to figure it out.

This reverts commit d77db45f37.
2023-09-26 16:51:54 +05:30
Harsh Shandilya 82ce45b8e4 refactor(database): move SavedPostSerializer to core 2023-09-26 16:37:28 +05:30
Harsh Shandilya dfe95a646e chore: add database refactor to blame ignore revs 2023-09-26 16:36:42 +05:30
Harsh Shandilya 7b0b206905 refactor(database): split out JVM and Android parts 2023-09-26 16:35:50 +05:30
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
1b1984064c chore(deps): update gradle/gradle-build-action action to v2.8.1 (#399)
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[gradle/gradle-build-action](https://togithub.com/gradle/gradle-build-action)
| action | patch | `v2.8.0` -> `v2.8.1` |

---

### Release Notes

<details>
<summary>gradle/gradle-build-action
(gradle/gradle-build-action)</summary>

###
[`v2.8.1`](https://togithub.com/gradle/gradle-build-action/compare/v2.8.0...v2.8.1)

[Compare
Source](https://togithub.com/gradle/gradle-build-action/compare/v2.8.0...v2.8.1)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/msfjarvis/compose-lobsters).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi45Ny4xIiwidXBkYXRlZEluVmVyIjoiMzYuOTcuMSIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-25 19:09:16 +00:00
renovate[bot]andGitHub 7e03e2571f chore(deps): update dependency dev.msfjarvis.whetstone to v0.8.0 2023-09-23 19:28:34 +00:00
renovate[bot]andGitHub 23f0b32634 chore(deps): update actions/checkout action to v4.1.0 2023-09-23 05:22:37 +00:00
Harsh Shandilya f844062980 fix(renovate): disable compose-bom updates
The current alphas have a regression causing crashes when
expanding/collapsing comments.
2023-09-23 10:49:10 +05:30
Harsh Shandilya 84f982b20e Revert "fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2023.10.00-alpha02"
Temporary test to see if it fixes the crashes I've seen

This reverts commit 45c7dbb3f7.
2023-09-23 10:33:47 +05:30
Harsh Shandilya c6739487a4 fix(android): update widget with a more usable UI 2023-09-23 01:19:18 +05:30
Harsh Shandilya be0f46371e fix(android): update widget when saved post update worker runs 2023-09-23 01:19:18 +05:30
Harsh Shandilya 85351d5b1c fix(android): increase widget size to 5x3 2023-09-23 01:15:41 +05:30
Harsh Shandilya 23366e4536 feat(android): navigate to a specific comments page via intent 2023-09-23 01:15:02 +05:30
Harsh Shandilya 0d1f69d36e refactor(android): expose 'plain' SavedPosts list in VM 2023-09-23 01:14:06 +05:30
Harsh Shandilya d77db45f37 fix(deps): use Swipe snapshots
Fixes COMPOSE-LOBSTERS-1N
2023-09-22 10:11:43 +05:30
renovate[bot]andGitHub 20c5b6c4a5 chore(deps): update agp to v8.3.0-alpha05 2023-09-21 22:30:07 +00:00
Harsh Shandilya 62f512e319 feat(android): basic widget implementation
This needs a Glance version of LobstersCard to function
2023-09-22 00:58:49 +05:30
Harsh Shandilya e740ddb7cc fix(build): recognize appwidget-provider as a valid XML tag 2023-09-22 00:58:07 +05:30
Harsh Shandilya 68924d6f35 chore(gradle): add androix.glance dependencies 2023-09-22 00:58:01 +05:30
Harsh Shandilya 94db512518 fix(deps): upgrade to Whetstone 0.8.0-SNAPSHOT
For BroadcastReceiver injection support
2023-09-22 00:58:01 +05:30
Harsh Shandilya f39e9889f3 feat(android): delete unused DataStore code 2023-09-21 16:11:45 +05:30
Harsh Shandilya b0ffbcd07d refactor(build): fix debug builds and groups to collection tasks 2023-09-21 13:57:12 +05:30
Harsh Shandilya 19412cc963 fix(renovate): also group Compose BOM updates with AndroidX 2023-09-21 00:45:31 +05:30
renovate[bot]andGitHub 45c7dbb3f7 fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2023.10.00-alpha02 2023-09-20 18:50:55 +00:00
renovate[bot]andGitHub 3b0d0e55dc fix(deps): update androidx 2023-09-20 18:20:45 +00:00
renovate[bot]andGitHub ae21ebe80d chore(deps): update actions/setup-java action to v3.13.0 2023-09-20 12:36:56 +00:00
Harsh Shandilya cca14765ce chore(README): refresh module graph graphic 2023-09-20 09:05:52 +05:30
renovate[bot]andGitHub 725718d18c fix(deps): update konvert to v2.3.0 2023-09-20 01:27:39 +00:00
renovate[bot]andHarsh Shandilya 61b000dc48 chore(deps): update dependency com.facebook:ktfmt to v0.46 2023-09-20 00:04:33 +05:30
renovate[bot]andGitHub cf850071e5 chore(deps): update github/codeql-action action to v2.21.8 2023-09-19 11:24:32 +00:00
Harsh Shandilya fe473e70a3 fix(ci): adjust CodeQL build task 2023-09-19 16:54:06 +05:30
Harsh Shandilya ce6540a6f3 fix(scripts): allow running on Darwin hosts 2023-09-19 16:06:56 +05:30
GitHub Actions ac3e60053a feat(release): start next development iteration 2023-09-19 09:54:05 +00:00
GitHub Actions 205ae8d9c7 feat(release): bump version 2023-09-19 09:49:59 +00:00
Harsh Shandilya 772d368caa chore(android): delete startup profile 2023-09-19 14:27:23 +05:30
Harsh Shandilya d2fa330491 chore(android): regenerate baseline profiles 2023-09-19 14:27:23 +05:30
Harsh Shandilya f85856a6d9 fix(ci): run dependency review after checks job 2023-09-19 14:27:23 +05:30
renovate[bot]andGitHub 4ed5988aa8 chore(deps): update r0adkll/upload-google-play action to v1.1.2 2023-09-19 05:21:44 +00:00
renovate[bot]andGitHub ac4bf7f4dd fix(deps): update dependency androidx.test:core to v1.6.0-alpha02 2023-09-19 00:42:03 +00:00
Harsh Shandilya 7b5cfa97d7 chore: update changelog 2023-09-19 00:25:56 +05:30
renovate[bot]andHarsh Shandilya 93292c3d5a chore(deps): update dependency com.facebook:ktfmt to v0.45 2023-09-18 23:38:00 +05:30
Harsh Shandilya 62ebb43e6f fix(common): ensure TagRow has vertical spacing 2023-09-17 01:44:09 +05:30
Harsh Shandilya 5dabebf579 fix(api): simplify test assertion 2023-09-17 01:38:46 +05:30
renovate[bot]andGitHub 96728a3834 chore(deps): update plugin modulegraph to v0.5.0 2023-09-15 19:53:37 +00:00
renovate[bot]andGitHub 10aa416e94 chore(deps): update agp to v8.3.0-alpha04 2023-09-15 17:29:46 +00:00
Harsh Shandilya e283584999 fix(api): use the correct test resource 2023-09-14 23:17:15 +05:30
renovate[bot]andGitHub edea0c6ab1 chore(deps): update github/codeql-action action to v2.21.7 2023-09-14 17:41:12 +00:00
Harsh Shandilya 1cb3eb6472 refactor(api): import CSRF extraction from android module 2023-09-14 00:47:01 +05:30
Harsh Shandilya ddfa62f4fb fix(ci): run CodeQL on Renovate branches 2023-09-14 00:22:14 +05:30
renovate[bot]andGitHub 88a119d66b chore(deps): update github/codeql-action action to v2.21.6 2023-09-13 16:41:41 +00:00
renovate[bot]andGitHub de16ff52af fix(deps): update dependency org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin to v2.8.0 2023-09-12 01:45:32 +00:00
renovate[bot]andGitHub 8dc3a034c1 chore(deps): pin actions/dependency-review-action action to 6c5ccda 2023-09-09 18:19:00 +00:00
Harsh Shandilya f9b2581464 chore(ci): add GHA dependency-review-action 2023-09-09 23:48:40 +05:30
Harsh ShandilyaandGitHub 2f2d2e694e fix(android): remove unnecessary Konvert configuration
We're only using it in the `model` subproject right now.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-09-09 16:48:24 +05:30
Harsh Shandilya 25382acf0e refactor(model): use Konvert to automatically generate mappings 2023-09-09 13:31:28 +05:30
Harsh Shandilya d4672ae8bd chore(deps): upgrade to Whetstone 0.7.0 2023-09-08 15:08:33 +05:30
Harsh Shandilya 4c87b644c0 chore(deps): update anvil to 2.4.8 2023-09-08 13:47:54 +05:30
Harsh Shandilya f546f98227 chore: update rgignore 2023-09-08 13:47:15 +05:30
renovate[bot]andGitHub e878df3d60 chore(deps): update agp to v8.3.0-alpha03 2023-09-08 00:16:20 +00:00
Harsh Shandilya e49a2c2cbc fix(build): disable NewerVersionAvailable Lint 2023-09-07 23:52:15 +05:30
renovate[bot]andGitHub f371c435fd fix(deps): update dependency com.github.ben-manes:gradle-versions-plugin to v0.48.0 2023-09-07 07:36:34 +00:00
Harsh Shandilya 19e7d65006 fix(deps): update dev.chrisbanes.compose:compose-bom to 2023.10.00-alpha01 2023-09-07 13:03:34 +05:30
renovate[bot]andGitHub 60506b4725 fix(deps): update androidx 2023-09-06 23:02:27 +00:00
renovate[bot]andGitHub 9cfa4d8ac4 chore(deps): update actions/upload-artifact action to v3.1.3 2023-09-06 20:25:12 +00:00
renovate[bot]andGitHub 8195a15a01 fix(deps): update sentry to v6.29.0 2023-09-06 10:36:08 +00:00
Harsh Shandilya 721b74fedc chore: refresh Lint baseline 2023-09-06 01:57:27 +05:30
renovate[bot]andGitHub 62ea7cd456 chore(deps): update agp to v8.3.0-alpha02 2023-09-05 18:09:30 +00:00
renovate[bot]andGitHub b60adaf87d chore(deps): update actions/checkout action to v4 2023-09-04 16:56:54 +00:00
renovate[bot]andGitHub 0852f197be chore(deps): update plugin modulegraphassert to v2.5.0 2023-09-03 19:14:41 +00:00
renovate[bot]andGitHub ef6359274d fix(deps): update dependency org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin to v2.7.4 2023-09-01 18:47:57 +00:00
Harsh Shandilya b31a3755bb chore: add TraceLog 2023-09-01 04:05:20 +05:30
Harsh Shandilya c87f6a4239 fix(api): adapt to new user endpoint 2023-09-01 04:05:07 +05:30
Harsh Shandilya c279765386 fix(deps): upgrade to AGP 8.3.0-alpha01 2023-08-31 11:45:23 +05:30
renovate[bot]andGitHub ac3dd45ee6 chore(deps): update androidx to v1.2.0-beta05 2023-08-30 22:45:39 +00:00
Harsh ShandilyaandGitHub 6db7880178 fix: replace unsupported extension syntax 2023-08-30 22:35:21 +05:30
renovate[bot]andGitHub 0c29a6626d fix(deps): update dagger to v2.48 2023-08-30 16:19:34 +00:00
GitHub Actions 183e1606c5 feat(release): start next development iteration 2023-08-30 10:43:33 +00:00
GitHub Actions d5a4d7f91a feat(release): bump version 2023-08-30 10:38:14 +00:00
Harsh Shandilya 5a491429db chore: add dependency updates to changelog 2023-08-30 16:01:05 +05:30
Harsh Shandilya 6265c50caf chore: refresh Lint baseline 2023-08-30 15:55:41 +05:30
Harsh Shandilya 4b4f00ad8e feat(android): enable read posts feature 2023-08-30 15:13:34 +05:30
Harsh Shandilya ed071a0fff chore: update README 2023-08-30 14:53:49 +05:30
Anunay Maheshwari db393d4534 fix(comments): calculate and expose indentLevel from CommentNode 2023-08-30 14:35:16 +05:30
Harsh Shandilya 9dcf26b5a4 fix(model): adjust for new comments structure 2023-08-30 11:32:10 +05:30
Harsh Shandilya 43402f45d8 Revert "chore(android): refresh baseline profiles"
Causes crashes 🤷

This reverts commit 0d23225ec7.
2023-08-29 15:56:47 +05:30
Harsh Shandilya 76b5395fd2 fix(deps): update dev.chrisbanes.compose:compose-bom to 2023.09.00-alpha03 2023-08-29 15:45:34 +05:30
renovate[bot]andGitHub f9fa30a58d fix(deps): update dependency com.github.requery:sqlite-android to v3.43.0 2023-08-29 08:55:26 +00:00
renovate[bot]andGitHub b7660a93b5 fix(deps): update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.21.0 2023-08-29 06:55:57 +00:00
renovate[bot]andGitHub 5858466318 chore(deps): update gradle/gradle-build-action action to v2.8.0 2023-08-28 21:51:32 +00:00
renovate[bot]andGitHub 4d5ce37982 chore(deps): update github/codeql-action action to v2.21.5 2023-08-28 19:49:30 +00:00
renovate[bot]andGitHub d84e6c8e7c chore(deps): update actions/checkout action to v3.6.0 2023-08-24 19:27:43 +00:00
renovate[bot]andGitHub 9768ffa8ff chore(deps): update agp to v8.2.0-beta01 2023-08-24 17:30:48 +00:00
Harsh Shandilya 5cb4af40cd fix(build): simplify Lint task dependencies 2023-08-24 17:16:55 +05:30
Harsh Shandilya b43d238dd1 chore: refresh Lint baseline 2023-08-24 12:40:19 +05:30
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Harsh Shandilya
3c8a23e91e chore(deps): update kotlin and compose to v1.9.10 (#396)
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [org.jetbrains.kotlin.plugin.serialization](https://kotlinlang.org/)
([source](https://togithub.com/JetBrains/kotlin)) | `1.9.0` -> `1.9.10`
|
[![age](https://developer.mend.io/api/mc/badges/age/maven/org.jetbrains.kotlin.plugin.serialization/1.9.10?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/org.jetbrains.kotlin.plugin.serialization/1.9.10?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/org.jetbrains.kotlin.plugin.serialization/1.9.0/1.9.10?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/org.jetbrains.kotlin.plugin.serialization/1.9.0/1.9.10?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [org.jetbrains.kotlin:kotlin-gradle-plugin](https://kotlinlang.org/)
([source](https://togithub.com/JetBrains/kotlin)) | `1.9.0` -> `1.9.10`
|
[![age](https://developer.mend.io/api/mc/badges/age/maven/org.jetbrains.kotlin:kotlin-gradle-plugin/1.9.10?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/org.jetbrains.kotlin:kotlin-gradle-plugin/1.9.10?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/org.jetbrains.kotlin:kotlin-gradle-plugin/1.9.0/1.9.10?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/org.jetbrains.kotlin:kotlin-gradle-plugin/1.9.0/1.9.10?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>JetBrains/kotlin
(org.jetbrains.kotlin.plugin.serialization)</summary>

###
[`v1.9.10`](https://togithub.com/JetBrains/kotlin/releases/tag/v1.9.10):
Kotlin 1.9.10

#### Changelog

##### Compiler

- [`KT-60769`](https://youtrack.jetbrains.com/issue/KT-60769) Partially
revert KT-58371
- [`KT-60659`](https://youtrack.jetbrains.com/issue/KT-60659) Incorrect
'unresolved reference: addFirst' error with JDK 21
- [`KT-60371`](https://youtrack.jetbrains.com/issue/KT-60371) Native
custom allocator link error
- [`KT-60986`](https://youtrack.jetbrains.com/issue/KT-60986) Native:
static caches with custom runtime options are broken on Linux
- [`KT-60770`](https://youtrack.jetbrains.com/issue/KT-60770) Fix
false-positive ABSTRACT_MEMBER_NOT_IMPLEMENTED on toArray with JDK 21
- [`KT-60231`](https://youtrack.jetbrains.com/issue/KT-60231)
NoClassDefFoundError: $$$$$NON_LOCAL_RETURN$$$$$ after upgrade to Kotlin
1.9.0

##### JavaScript

- [`KT-60785`](https://youtrack.jetbrains.com/issue/KT-60785) KJS:
Destructured value class in suspend function fails with Uncaught
TypeError: can't convert to primitive type error
- [`KT-60852`](https://youtrack.jetbrains.com/issue/KT-60852) Kotlin
JS(IR): IllegalArgumentException: Cross module dependency resolution
failed when updating to Kotlin 1.9.0
- [`KT-57509`](https://youtrack.jetbrains.com/issue/KT-57509) KJS:
Compiler generates native JS operator == for comparing values with Any
type

##### Native

- [`KT-60230`](https://youtrack.jetbrains.com/issue/KT-60230) Native:
"unknown options: -ios_simulator_version_min -sdk_version" with Xcode 15
beta 3
- [`KT-60758`](https://youtrack.jetbrains.com/issue/KT-60758) Native:
Building for 'iOS-simulator', but linking in dylib built for 'iOS' in
Xcode 15 beta 4

##### Native. C and ObjC Import

- [`KT-59167`](https://youtrack.jetbrains.com/issue/KT-59167) Native:
cinterop is unable to build interop libraries against the Xcode 15 Beta
1

##### Tools. Gradle

- [`KT-61147`](https://youtrack.jetbrains.com/issue/KT-61147) Kotlin
Compiler 1.9.0 bundles a stripped unshadowed version of Gson
- [`KT-60543`](https://youtrack.jetbrains.com/issue/KT-60543)
NoClassDefFoundError for com/gradle/scan/plugin/BuildScanExtension

#### Checksums

| File | Sha256 |
| --- | --- |
| kotlin-compiler-1.9.10.zip |
7d74863deecf8e0f28ea54c3735feab003d0eac67e8d3a791254b16889c20342 |
| kotlin-native-linux-x86\_64-1.9.10.tar.gz |
1db3679919f4449514e9d82451e7dfa73558ac9bc80b82579cd74d452c8faa5b |
| kotlin-native-macos-x86\_64-1.9.10.tar.gz |
f5650f2560438a692803d8fe07124529c19f1972f84fe09cfa2329b93f43828d |
| kotlin-native-macos-aarch64-1.9.10.tar.gz |
d2cf5a484ac0808ab29fd3f6099df7c07330f81f3cbab949947e42e36138c3de |
| kotlin-native-windows-x86\_64-1.9.10.zip |
a34d56661455e94e1ba4dd09ec3c1adac6148fdedcf55eefb9a79c8ed01ff02c |

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/msfjarvis/compose-lobsters).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNi41Ni4wIiwidXBkYXRlZEluVmVyIjoiMzYuNTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
2023-08-24 04:43:15 +00:00
Harsh Shandilya 63d74ae065 chore: refresh lint baseline 2023-08-23 23:29:40 +05:30
Harsh Shandilya f0d4395da6 chore(database): make test naming consistent 2023-08-23 23:28:01 +05:30
renovate[bot]andGitHub 41fe784641 chore(deps): update androidx 2023-08-23 17:35:34 +00:00
renovate[bot]andGitHub 7c07e90d0e fix(deps): update dependency androidx.test:runner to v1.6.0-alpha04 2023-08-22 21:38:42 +00:00
renovate[bot]andGitHub 6731453c41 fix(deps): update serialization to v1.6.0 2023-08-22 19:55:01 +00:00
Harsh Shandilya 932b474763 chore(build): refresh Gradle Kotlin IC properties 2023-08-20 03:27:12 +05:30
renovate[bot]andGitHub 1600b7a200 chore(deps): update gradle/gradle-build-action action to v2.7.1 2023-08-18 23:34:53 +00:00
Harsh Shandilya 0d23225ec7 chore(android): refresh baseline profiles 2023-08-18 16:17:52 +05:30
renovate[bot]andGitHub 5214355339 chore(deps): update plugin org.gradle.toolchains.foojay-resolver-convention to v0.7.0 2023-08-17 12:46:00 +00:00
renovate[bot]andGitHub 81b96cf21d chore(deps): update dependency gradle to v8.3 2023-08-17 10:12:47 +00:00
Harsh Shandilya 492eff8cde chore: add changelog entries 2023-08-16 14:59:04 +05:30
Harsh Shandilya 49c5029256 refactor: move ClawAppBar to android module 2023-08-16 12:30:04 +05:30
Harsh Shandilya fcd85dc8e1 feat(android): feature flag "read posts" feature 2023-08-16 11:27:57 +05:30
Harsh Shandilya bc3a1266f4 refactor(android): drop Accompanist SystemUI Controller dependency 2023-08-16 11:25:13 +05:30
Harsh Shandilya bc2365b08b feat(android): add support for identifying read posts 2023-08-16 00:37:50 +05:30
Harsh Shandilya 9c32d6721b feat(database): add support for marking posts as read 2023-08-15 23:58:02 +05:30
Harsh Shandilya 1394bc74c4 refactor(database): de-dupe test database setup 2023-08-15 23:58:01 +05:30
Harsh Shandilya cbf0707aa6 chore(common): tweak LobstersCard UI
Cut down on paddings and use colors more explicitly
2023-08-15 16:15:11 +05:30
Harsh Shandilya 67e621160f fix(common): allow custom tints for NetworkImage placeholders 2023-08-15 15:37:23 +05:30
Harsh Shandilya e06a8ba236 refactor(database): disallow injection of raw database types 2023-08-15 14:59:39 +05:30
renovate[bot]andGitHub 5bd37a837c chore(deps): update github/codeql-action action to v2.21.4 2023-08-14 20:26:15 +00:00
renovate[bot]andGitHub 828fb74240 chore(deps): update agp to v8.2.0-alpha16 2023-08-14 17:33:54 +00:00
renovate[bot]andGitHub 8241a6d901 chore(deps): update dependency gradle to v8.3-rc-4 2023-08-14 10:27:33 +00:00
Harsh Shandilya edadcc6744 refactor(database): expose *Queries objects to the DI graph 2023-08-14 15:54:22 +05:30
Harsh Shandilya 44438da292 chore: refresh module graph 2023-08-10 03:09:47 +05:30
Harsh Shandilya 591c68a6e4 scripts: return to monke
I don't like bash but turns out I dislike Python more

This reverts commit 2628bfc2cd, d77fa13903 and 69f63cced4.
2023-08-10 02:58:58 +05:30
renovate[bot]andGitHub 892d68581d chore(deps): update plugin poko to v0.15.0 2023-08-09 19:27:31 +00:00
renovate[bot]andGitHub a4b39ce00e fix(deps): update androidx 2023-08-09 17:56:34 +00:00
renovate[bot]andGitHub 9ce0d3a8b4 fix(deps): update dependency com.slack.eithernet:eithernet to v1.5.0 2023-08-09 01:33:00 +00:00
renovate[bot]andGitHub 23b07c4bad chore(deps): update github/codeql-action action to v2.21.3 2023-08-08 15:51:00 +00:00
renovate[bot]andGitHub f3e28d2e58 fix(deps): update dependency io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin to v3.12.0 2023-08-08 09:49:08 +00:00
Harsh Shandilya 7a5da2af9f chore(deps): upgrade accompanist to 0.33.0-alpha 2023-08-08 11:46:50 +05:30
renovate[bot]andGitHub 4c28da30ae fix(deps): update sentry to v6.28.0 2023-08-04 13:58:52 +00:00
Harsh Shandilya 4961af8a20 fix(android): workaround packaging regression 2023-08-04 02:42:31 +05:30
Harsh Shandilya 1e396bc7ff feat(android): add Licensee to track dependency licenses 2023-08-04 02:19:42 +05:30
Harsh Shandilya 52deb7ca5f Revert "feat: init store module"
Store doesn't seem particularly useful for my needs.

This reverts commits 14007c6e8f and 45701f414b.
2023-08-04 00:39:53 +05:30
Harsh Shandilya 8891667c92 fix(deps): bump serialization to 1.6.0-RC 2023-08-03 23:44:44 +05:30
Harsh ShandilyaandGitHub e7e51f38d4 Merge remote-tracking branches 'origin/renovate/org.gradle.android.cache-fix' and 'origin/renovate/org.jetbrains.kotlinx' 2023-08-03 17:14:50 +00:00
renovate[bot]andGitHub 3de6a94ea0 fix(deps): update dependency org.jetbrains.kotlinx:atomicfu to v0.21.0 2023-08-03 17:09:41 +00:00
renovate[bot]andGitHub ef0db7d5ae fix(deps): update dependency org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin to v2.7.3 2023-08-03 17:09:38 +00:00
Harsh ShandilyaandGitHub 45701f414b feat(store): set up a preliminary implementation for newest posts 2023-08-03 17:09:08 +00:00
Harsh Shandilya 14007c6e8f feat: init store module 2023-08-03 18:23:23 +05:30
Harsh Shandilya 6ca500066f fix(database): move migrations to their correct directory 2023-08-03 17:43:36 +05:30
Harsh Shandilya 69f63cced4 refactor(scripts): convert scripts/encrypt-secret to Python 2023-08-03 16:58:38 +05:30
renovate[bot]andHarsh Shandilya 1e0cc062d5 chore(deps): update dependency gradle to v8.3-rc-3 2023-08-03 16:58:38 +05:30
Harsh Shandilya f6e9b3a83f chore(build): remove unused dependencies 2023-08-03 16:58:38 +05:30
Harsh Shandilya e0eb748318 fix(android): remove native library fix attempts
There is no measurable evidence that these helped at all
2023-08-03 16:58:38 +05:30
Harsh Shandilya d65b8b6799 chore(ci): allow overriding IAU priority 2023-08-03 16:58:38 +05:30
Harsh Shandilya d41a1f444f fix(ci): remove baseline profile workflow
GHA is incapable of running this anymore
2023-08-02 13:39:10 +05:30
Harsh Shandilya 786f674044 fix(api): make commentsUrl in search results absolute 2023-08-02 11:08:10 +05:30
Harsh Shandilya 432a438815 chore(ci): add Python to Spotless 2023-08-02 01:40:36 +05:30
Harsh Shandilya bae671ad23 feat(android): switch comments page to a swipe action 2023-08-02 01:40:36 +05:30
renovate[bot]andGitHub 45b6f3c4d5 chore(deps): update agp to v8.2.0-alpha15 2023-07-31 20:14:53 +00:00
GitHub Actions 79a2a060c7 feat(release): start next development iteration 2023-07-31 14:52:59 +00:00
GitHub Actions 80736d6538 feat(release): bump version 2023-07-31 14:47:02 +00:00
Harsh Shandilya cb77a3ae85 chore: update changelog 2023-07-31 19:11:34 +05:30
Harsh Shandilya 80ab034493 fix(android): use SoLoader to load sqlite native library 2023-07-31 19:10:03 +05:30
Harsh Shandilya 3bb5dfffbe refactor(build): migrate to Baseline Profile Gradle Plugin 2023-07-31 16:48:09 +05:30
GitHub Actions d9ab751dbd chore(android): refresh baseline profile 2023-07-31 06:58:01 +00:00
Harsh Shandilya e3627ca89d fix: prevent upgrading to Anvil k1.8 build 2023-07-29 20:22:24 +05:30
Harsh Shandilya 543edf36e8 chore(deps): update anvil to v2.4.7 2023-07-29 12:12:37 +05:30
GitHub Actions fb5721beda chore(android): refresh baseline profile 2023-07-29 01:33:18 +00:00
renovate[bot]andGitHub 6e67a3de5f chore(deps): update github/codeql-action action to v2.21.2 2023-07-28 15:40:09 +00:00
GitHub Actions 6d944967f0 chore(android): refresh baseline profile 2023-07-28 01:40:03 +00:00
Harsh Shandilya 2628bfc2cd py: scripts/deploy-snapshot 2023-07-27 15:20:31 +00:00
Harsh Shandilya d77fa13903 py: scripts/boot-emulator 2023-07-27 16:55:38 +05:30
GitHub Actions f71aa07949 feat(release): start next development iteration 2023-07-27 08:10:24 +00:00
GitHub Actions a41b465648 feat(release): bump version 2023-07-27 08:06:08 +00:00
Harsh Shandilya a7038600b3 fix(release): update signing key secret in publish workflow
Fixes: ca6b941cbb ("fix(release): update secrets handling scripts")
2023-07-27 13:34:22 +05:30
Harsh Shandilya 3143556c63 fix: re-roll Lint baseline 2023-07-27 12:04:50 +05:30
GitHub Actions 5e2d9a2355 chore(android): refresh baseline profile 2023-07-27 01:38:58 +00:00
Harsh Shandilya b4adfede90 fix(android): avoid crash from empty creation time
Fixes COMPOSE-LOBSTERS-17
2023-07-27 02:57:35 +05:30
Harsh Shandilya ed85ba905d fix(deps): update dev.chrisbanes.compose:compose-bom to 2023.07.00-alpha02 2023-07-27 02:36:28 +05:30
Harsh Shandilya c29e4065d6 chore: update changelog 2023-07-27 02:03:48 +05:30
Harsh Shandilya bcf4f02a01 Revert "Revert "Revert "fix(common): make text in comments screen selectable"""
Still causes crashes :(

This reverts commit c5ec6cd680.

Fixes COMPOSE-LOBSTERS-16
2023-07-27 01:28:21 +05:30
renovate[bot]andGitHub 72b9409383 chore(deps): update github/codeql-action action to v2.21.1 2023-07-26 19:31:22 +00:00
renovate[bot]andGitHub 2c762428af chore(deps): update androidx 2023-07-26 18:27:51 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
58e427c13a chore(deps): update sqldelight to v2.0.0 (#391)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-26 23:57:37 +05:30
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
974f03ee89 fix(deps): update dependency androidx.paging:paging-compose to v3 (#392)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-26 23:57:28 +05:30
renovate[bot]andGitHub f5e6b25ec6 chore(deps): update dependency gradle to v8.3-rc-2 2023-07-26 16:46:13 +00:00
renovate[bot]andGitHub be5f073acf fix(deps): update sentry to v6.27.0 2023-07-26 08:41:17 +00:00
Harsh Shandilya ca6b941cbb fix(release): update secrets handling scripts 2023-07-26 14:10:49 +05:30
GitHub Actions 1e5f830652 chore(android): refresh baseline profile 2023-07-26 06:39:23 +00:00
renovate[bot]andGitHub e72a5fda5c chore(deps): update agp to v8.2.0-alpha14 2023-07-25 21:59:32 +00:00
renovate[bot]andGitHub 5c2fe6e630 fix(deps): update coroutines to v1.7.3 2023-07-25 19:04:26 +00:00
Harsh ShandilyaandGitHub 5907c2a09a fix(scripts): make boot_emulator naming consistent 2023-07-25 21:52:32 +05:30
Harsh Shandilya e3b381c665 chore: refresh feature graphic 2023-07-25 20:25:21 +05:30
Harsh Shandilya f1d30e59b0 feat: add Search flow to Maestro 2023-07-25 20:17:27 +05:30
Harsh Shandilya 7669a85f43 chore: refresh README graphic 2023-07-25 19:25:35 +05:30
GitHub Actions c05db765c8 feat(release): start next development iteration 2023-07-25 10:42:52 +00:00
GitHub Actions 4c8e30bcc9 feat(release): bump version 2023-07-25 10:38:59 +00:00
GitHub Actions d32819b1ff chore(android): refresh baseline profile 2023-07-25 06:39:00 +00:00
Harsh Shandilya a2d046bd0b Revert "fix(benchmark): upgrade to API level 33"
This reverts commit 1defffa504.
2023-07-25 11:46:47 +05:30
Harsh Shandilya 3ad4ff1c63 fix(build): use Whetstone from Maven Central 2023-07-25 11:40:02 +05:30
Harsh Shandilya 1defffa504 fix(benchmark): upgrade to API level 33 2023-07-25 01:31:01 +05:30
Harsh Shandilya 0d78cb4112 fix(benchmark): rework baseline profile benchmark 2023-07-25 01:31:01 +05:30
Harsh Shandilya 7c59130af9 feat(benchmark): restore full UI exploration 2023-07-25 01:31:01 +05:30
Harsh Shandilya 4137d73539 chore: update changelog 2023-07-25 00:56:07 +05:30
renovate[bot]andGitHub 0f8a649e3b chore(deps): update gradle/gradle-build-action action to v2.7.0 2023-07-24 16:23:53 +00:00
Harsh ShandilyaandGitHub 7e7a4bec83 chore(renovate): re-enable Kotlin upgrades 2023-07-24 21:49:52 +05:30
Harsh Shandilya b442b14cc1 fix(deps): upgrade to Kotlin 1.9.0 2023-07-24 21:29:24 +05:30
renovate[bot]andGitHub 97886f6ece chore(deps): update actions/setup-java action to v3.12.0 2023-07-24 14:03:55 +00:00
GitHub Actions 7b9245e62c chore(android): refresh baseline profile 2023-07-24 01:25:48 +00:00
renovate[bot]andGitHub 99aa62d0e4 fix(deps): update junit5 monorepo to v5.10.0 2023-07-23 13:39:47 +00:00
GitHub Actions c3cf8a8a39 chore(android): refresh baseline profile 2023-07-23 01:27:03 +00:00
GitHub Actions 340655f18a chore(android): refresh baseline profile 2023-07-22 01:27:26 +00:00
renovate[bot]andGitHub 10fa84b09e fix(deps): update richtext to v0.17.0 2023-07-21 05:01:52 +00:00
GitHub Actions f21a03b20b chore(android): refresh baseline profile 2023-07-21 01:29:17 +00:00
GitHub Actions 56394fc275 chore(android): refresh baseline profile 2023-07-20 01:27:18 +00:00
Harsh Shandilya 9fd2d9f17b fix(android): avoid triggering another useless search API call 2023-07-20 01:11:45 +05:30
Harsh Shandilya 0c0506b6d7 fix(android): fix content description of search page icon 2023-07-20 01:06:13 +05:30
Harsh Shandilya f94741144c refactor(android): make search page manage localized state 2023-07-19 22:24:43 +05:30
Harsh Shandilya 29c0369d43 fix(build): set proguard files for all build types
Some cursed day you might be enabling R8 on debug builds
2023-07-19 22:24:23 +05:30
Harsh Shandilya e700987d14 chore(deps): update dev.chrisbanes.compose:compose-bom to 2023.07.00-alpha01 2023-07-19 22:15:33 +05:30
Harsh Shandilya c5ec6cd680 Revert "Revert "fix(common): make text in comments screen selectable""
This reverts commit 401214794d.
2023-07-19 21:58:08 +05:30
renovate[bot]andGitHub e48a6d41d5 chore(deps): update github/codeql-action action to v2.21.0 2023-07-19 16:02:19 +00:00
Harsh Shandilya 5870af4017 fix(core): remove unused DispatcherProvider#unconfined 2023-07-19 21:31:43 +05:30
Harsh Shandilya cb4c85b41c chore(build): upgrade to Gradle 8.3 RC1 2023-07-19 21:31:43 +05:30
renovate[bot]andGitHub cd6a04c5fd fix(deps): update sentry to v6.26.0 2023-07-19 13:37:30 +00:00
Harsh Shandilya 401214794d Revert "fix(common): make text in comments screen selectable"
Causes frequent crashes

This reverts commit 778be597dd.
2023-07-19 10:03:04 +00:00
Harsh Shandilya fdd2f7008c Revert "fix(common): use SystemClock for getting current millis"
This broke relative time accounting

This reverts commit 42cc852a20.
2023-07-19 10:02:20 +00:00
renovate[bot]andGitHub 18ef9c63b9 chore(deps): update dependency com.android.test to v8.2.0-alpha13 2023-07-18 21:20:15 +00:00
Harsh Shandilya d343f3db2b feat(api): remove tag search endpoints 2023-07-19 00:50:10 +05:30
Harsh Shandilya 42cc852a20 fix(common): use SystemClock for getting current millis 2023-07-19 00:41:33 +05:30
Harsh Shandilya 44be6eacbb chore: update changelog 2023-07-19 00:04:25 +05:30
Harsh Shandilya 778be597dd fix(common): make text in comments screen selectable
With this change you can now select
- The post title
- The post description if it exists, and
- Each individual comment

Fixes #385
2023-07-18 23:23:24 +05:30
Harsh Shandilya 255439e2b4 feat(common): add a clickable icon to SearchBar 2023-07-18 23:23:24 +05:30
renovate[bot]andGitHub 63c3e26f5c fix(deps): update dependency nl.littlerobots.version-catalog-update:nl.littlerobots.version-catalog-update.gradle.plugin to v0.8.1 2023-07-18 17:38:40 +00:00
Harsh Shandilya d3c3e3ca08 feat(android): wire up search UI into navigation graph 2023-07-18 23:08:07 +05:30
Harsh Shandilya 8d6aba9865 feat(android): add search UI 2023-07-18 23:08:07 +05:30
Harsh Shandilya 5e91e20c51 feat(android): add specialized PagingSource for search endpoint 2023-07-18 23:08:07 +05:30
Harsh Shandilya 84c9dd3762 feat(common): add a simple SearchBar component
Material 3's SearchBar has way too much "interaction" for my liking
2023-07-18 23:08:07 +05:30
renovate[bot]andGitHub 24ef11b315 fix(deps): update dependency androidx.benchmark:benchmark-macro-junit4 to v1.2.0-beta01 2023-07-18 17:34:11 +00:00
Harsh Shandilya bdf218cd85 refactor(api): rework Retrofit DI and expose LobstersSearchApi 2023-07-18 17:53:36 +05:30
Harsh Shandilya b3ff40b12b refactor(core): RetrofitModule -> JsonModule 2023-07-18 17:11:52 +05:30
Harsh Shandilya bad5bf5457 refactor(api): make SearchConverter a singleton 2023-07-18 17:11:06 +05:30
Harsh Shandilya cf3ca27966 fix(api): correct usage of @Query feature in search API 2023-07-18 17:04:50 +05:30
renovate[bot]andHarsh Shandilya 127a0674a2 chore(deps): update gradle/gradle-build-action action to v2.6.1 2023-07-18 17:01:52 +05:30
renovate[bot]andHarsh Shandilya b1a18c5dec fix(deps): update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.20.0 2023-07-18 17:01:52 +05:30
GitHub ActionsandHarsh Shandilya 0a39f56775 chore(android): refresh baseline profile 2023-07-18 17:01:52 +05:30
Harsh Shandilya 5daeb8d580 feat(common): log errors from NetworkError composable
Having the errors in the logcat stream makes debugging quite a lot faster.
2023-07-18 17:01:52 +05:30
Harsh Shandilya 415ddae9f7 refactor(android): enforce DI encapsulation 2023-07-18 17:01:52 +05:30
Harsh Shandilya 4c95680f3b fix(renovate): remove now-unnecessary sentry-sdk regex manager 2023-07-17 16:03:15 +05:30
Harsh Shandilya b6cb9a2077 fix(renovate): consolidate and cleanup disabled packages 2023-07-17 16:01:36 +05:30
Harsh Shandilya 13eefbba2a chore(gradle): ensure all custom repositories are named 2023-07-17 15:43:58 +05:30
Harsh Shandilya 6548f7d654 fix(renovate): drop Poko from Renovate list
This is tied to the Kotlin version
2023-07-17 15:12:09 +05:30
Harsh Shandilya 1e4217598f fix(build): make slimTests skip debug rather than select release 2023-07-17 15:08:52 +05:30
Harsh Shandilya 0359860b82 refactor(android): move link metadata extraction to Unfurl
Crux is doing major changes for no good reason
2023-07-17 15:03:55 +05:30
Harsh Shandilya 37f42dc107 feat(api): add a Retrofit service for search 2023-07-17 08:26:56 +00:00
Harsh Shandilya 7eb4b45ab1 fix(model): ensure all classes have a readable toString 2023-07-17 13:36:42 +05:30
GitHub Actions 3706fdd284 chore(android): refresh baseline profile 2023-07-17 01:28:06 +00:00
renovate[bot]andGitHub f1fa96f8ca fix(deps): update dependency com.chimbori.crux:crux to v5 2023-07-16 10:22:42 +00:00
renovate[bot]andGitHub 36cadcdd78 fix(deps): update dependency com.chimbori.crux:crux to v4 2023-07-16 03:55:22 +00:00
renovate[bot]andGitHub cf3ac329f6 fix(deps): update dependency com.chimbori.crux:crux to v3.13.0 2023-07-16 00:26:09 +00:00
Harsh Shandilya 0581cedfb0 fix: remove useless get 2023-07-16 00:49:16 +05:30
GitHub Actions 0fc5adc197 chore(android): refresh baseline profile 2023-07-15 01:25:21 +00:00
renovate[bot]andGitHub 0680585b77 chore(deps): update github/codeql-action action to v2.20.4 2023-07-14 15:04:14 +00:00
Harsh Shandilya 2a3514e3b5 Revert "fix(android): remove explicit item keys"
This causes subtle UI artifacts that make me more annoyed than the occasional crash.

This reverts commit 2a97383e7d.
2023-07-14 19:08:32 +05:30
renovate[bot]andGitHub fd8b65be72 chore(deps): update sentry to v6.25.2 2023-07-14 10:57:40 +00:00
renovate[bot]andGitHub 50870b5fb5 fix(deps): update dagger to v2.47 2023-07-14 05:07:17 +00:00
GitHub Actions 7c5d935801 chore(android): refresh baseline profile 2023-07-14 01:31:32 +00:00
GitHub Actions 2862ada772 chore(android): refresh baseline profile 2023-07-13 01:25:54 +00:00
renovate[bot]andGitHub 65d1457386 chore(deps): update sentry to v6.25.1 2023-07-12 10:33:55 +00:00
GitHub Actions 0f63611c2d chore(android): refresh baseline profile 2023-07-12 01:25:10 +00:00
renovate[bot]andGitHub 7767f1c6d7 chore(deps): update agp to v8.2.0-alpha12 2023-07-11 19:08:20 +00:00
GitHub Actions f351b60073 chore(android): refresh baseline profile 2023-07-11 01:27:20 +00:00
Harsh Shandilya 752dee8ed6 fix(ci): submit generated dependency graph from running tests 2023-07-11 06:28:33 +05:30
Harsh Shandilya 0573e8cb2d fix(ci): remove build-tools workaround 2023-07-11 06:14:04 +05:30
Harsh Shandilya 75fd41a0d8 fix(ci): make CodeQL only run on schedule 2023-07-11 06:14:04 +05:30
renovate[bot]andGitHub 59f8577d1f chore(deps): update plugin org.gradle.toolchains.foojay-resolver-convention to v0.6.0 2023-07-10 18:46:20 +00:00
renovate[bot]andGitHub 85d4b50d28 chore(deps): update gradle/gradle-build-action action to v2.6.0 2023-07-10 18:32:28 +00:00
renovate[bot]andGitHub c3499d434b chore(deps): update dependency gradle to v8.2.1 2023-07-10 15:18:37 +00:00
GitHub Actions 701e0d7fcc chore(android): refresh baseline profile 2023-07-10 01:28:01 +00:00
Harsh Shandilya 9a5a417418 feat(build): add copyright license headers to XML files 2023-07-09 22:59:58 +05:30
renovate[bot]andHarsh Shandilya 1221992d26 chore(deps): update agp to v8.2.0-alpha11 2023-07-09 22:56:37 +05:30
renovate[bot]andHarsh Shandilya 144cdb5e50 chore(deps): update github/codeql-action action to v2.20.3 2023-07-09 22:56:37 +05:30
GitHub Actions 8133b2c091 chore(android): refresh baseline profile 2023-07-05 01:24:08 +00:00
renovate[bot]andGitHub 869cc650e3 chore(deps): update sentry to v6.25.0 2023-07-04 17:23:45 +00:00
GitHub Actions 7a3262338d chore(android): refresh baseline profile 2023-07-04 01:26:35 +00:00
renovate[bot]andGitHub 85ff15e8ca chore(deps): update github/codeql-action action to v2.20.2 2023-07-03 11:17:13 +00:00
GitHub Actions 3d34c4f466 chore(android): refresh baseline profile 2023-07-03 06:43:06 +00:00
GitHub Actions 6da6364a55 feat(release): start next development iteration 2023-07-02 18:43:07 +00:00
GitHub Actions 26b04cce16 feat(release): bump version 2023-07-02 18:39:14 +00:00
GitHub Actions 9ab2400e1f chore(android): refresh baseline profile 2023-07-02 17:01:00 +00:00
GitHub Actions c3b30cc86c chore(android): refresh baseline profile 2023-07-02 01:25:14 +00:00
Harsh Shandilya 2a97383e7d fix(android): remove explicit item keys
Hail mary fix for Sentry issue COMPOSE-LOBSTERS-2
2023-07-01 18:59:17 +05:30
Harsh Shandilya dd20885270 fix(deps): bump coroutines to 1.7.2 2023-07-01 18:57:26 +05:30
Harsh Shandilya fe752f839a feat(build): migrate to Gradle JVM Toolchains 2023-07-01 18:21:10 +05:30
GitHub ActionsandHarsh Shandilya be9a888816 chore(android): refresh baseline profile 2023-07-01 18:21:10 +05:30
renovate[bot]andGitHub 648e7b31cf chore(deps): update dependency gradle to v8.2 2023-06-30 21:58:31 +00:00
GitHub Actions 21b520f786 chore(android): refresh baseline profile 2023-06-30 01:27:40 +00:00
renovate[bot]andGitHub 8bbcabc8f6 chore(deps): update gradle/gradle-build-action action to v2.5.1 2023-06-29 19:44:16 +00:00
Harsh Shandilya 0e4e344a2f fix(deps): upgrade workmanager to 2.9.0-alpha01 2023-06-29 18:12:26 +05:30
GitHub Actions 7b25b6aa85 chore(android): refresh baseline profile 2023-06-29 01:25:13 +00:00
renovate[bot]andGitHub 5343168b8a chore(deps): update gradle/gradle-build-action action to v2.5.0 2023-06-29 00:05:15 +00:00
renovate[bot]andGitHub 9b39fcf1fc fix(deps): update dependency androidx.navigation:navigation-compose to v2.7.0-beta02 2023-06-28 22:59:50 +00:00
renovate[bot]andGitHub 8ce7ac96d0 chore(deps): update dependency gradle to v8.2-rc-3 2023-06-28 10:44:19 +00:00
Harsh Shandilya b5c57500b1 feat: revert back to old text pipeline
Things have been entirely too slow on the lobste.rs front and I don't care much to continue pushing for it.

Fixes #382
Fixes #383
2023-06-28 10:58:39 +05:30
Harsh Shandilya c089e5ae5a fix(build): make slim tests optional 2023-06-28 10:46:59 +05:30
Harsh Shandilya d8a76cf1e7 Revert "fix(build): temporarily revert to AGP 8.0.x"
This reverts commit 1e888494ee.
2023-06-28 10:46:59 +05:30
renovate[bot]andGitHub 92fce55feb fix(deps): update dependency org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin to v2.7.2 2023-06-28 03:22:11 +00:00
GitHub Actions 60a430baa4 chore(android): refresh baseline profile 2023-06-28 01:35:58 +00:00
Harsh Shandilya b0c8de888c chore(deps): bump sqldelight to 2.0.0-rc02 2023-06-28 00:18:54 +05:30
renovate[bot]andGitHub 73ab2dd1d3 fix(deps): update dependency androidx.test:runner to v1.6.0-alpha03 2023-06-27 16:48:14 +00:00
GitHub Actions 7c4f843f42 chore(android): refresh baseline profile 2023-06-27 01:33:28 +00:00
GitHub Actions 123ec904e3 chore(android): refresh baseline profile 2023-06-26 01:32:43 +00:00
GitHub Actions 80c9211d37 chore(android): refresh baseline profile 2023-06-25 01:32:29 +00:00
GitHub Actions b030694f63 chore(android): refresh baseline profile 2023-06-24 01:35:33 +00:00
GitHub Actions e40e196354 chore(android): refresh baseline profile 2023-06-23 01:32:30 +00:00
renovate[bot]andGitHub b7abef3f8f chore(deps): update sentry to v6.24.0 2023-06-22 16:00:38 +00:00
Harsh ShandilyaandGitHub 5bde6cd9cb chore(deps): bump Compose to June alpha release 2023-06-22 21:29:15 +05:30
Harsh Shandilya cb8c90ace9 fix(renovate): include JitPack repository 2023-06-22 12:09:21 +05:30
Harsh Shandilya 9c2c238e1e fix(build): raise target SDK to 34 2023-06-22 11:27:42 +05:30
renovate[bot]andHarsh Shandilya 21a7baa309 fix(deps): update dependency androidx.benchmark:benchmark-macro-junit4 to v1.2.0-alpha16 2023-06-22 11:23:58 +05:30
GitHub Actions a9d75148fd chore(android): refresh baseline profile 2023-06-22 01:35:13 +00:00
renovate[bot]andGitHub 3209b5b1fe chore(deps): update github/codeql-action action to v2.20.1 2023-06-21 13:16:25 +00:00
renovate[bot]andGitHub c749a97ded fix(deps): update dependency io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin to v3.11.1 2023-06-21 09:28:39 +00:00
GitHub Actions f1ab468ceb chore(android): refresh baseline profile 2023-06-21 01:30:06 +00:00
renovate[bot]andGitHub ebd0e5cb5d chore(deps): update plugin modulegraphassert to v2.4.1 2023-06-19 22:42:11 +00:00
GitHub Actions 19bf81ac0e chore(android): refresh baseline profile 2023-06-19 01:35:03 +00:00
renovate[bot]andGitHub 569d5af8fb fix(deps): update dependency com.google.truth:truth to v1.1.5 2023-06-18 16:26:46 +00:00
GitHub Actions dc754dabb3 chore(android): refresh baseline profile 2023-06-18 01:37:26 +00:00
GitHub Actions ed42532416 chore(android): refresh baseline profile 2023-06-17 01:38:56 +00:00
GitHub Actions 211f39da52 chore(android): refresh baseline profile 2023-06-16 01:34:00 +00:00
renovate[bot]andHarsh Shandilya fefac25781 chore(deps): update sentry 2023-06-15 23:27:40 +05:30
Harsh Shandilya e0c9c88ca9 chore(common): prettify HTMLText preview 2023-06-15 23:27:40 +05:30
Harsh Shandilya ea7f7b6306 fix(common): add some visual distinction for blockquotes 2023-06-15 23:27:40 +05:30
GitHub Actions 8ceca6c5ed chore(android): refresh baseline profile 2023-06-15 01:36:06 +00:00
GitHub Actions e9ff85ad44 chore(android): refresh baseline profile 2023-06-14 01:35:35 +00:00
renovate[bot]andGitHub b8e6d4d3fe chore(deps): update github/codeql-action action to v2.20.0 2023-06-13 22:15:55 +00:00
GitHub Actions e7fdfcab69 chore(android): refresh baseline profile 2023-06-13 01:38:12 +00:00
Harsh Shandilya ad8c830b17 fix(common): make HTMLText use M3 Text component 2023-06-13 02:47:17 +05:30
renovate[bot]andHarsh Shandilya 25d2d4ddb7 chore(deps): update actions/checkout action to v3.5.3 2023-06-13 01:44:31 +05:30
Harsh Shandilya 22d1755fd2 fix(android): use SoLoader to load libraries 2023-06-13 01:44:31 +05:30
Harsh Shandilya d397680d33 chore: add changelog entry 2023-06-09 20:09:44 +05:30
Harsh Shandilya 40cd7758dc chore: remove unused Markdown dependencies 2023-06-09 20:09:44 +05:30
Harsh Shandilya 2dc8eae861 refactor: migrate to HTMLText 2023-06-09 20:09:44 +05:30
Harsh Shandilya 2d23ceee83 feat(common): add HTMLText composable
This allows rendering raw HTML text directly without roundtripping it as Markdown
2023-06-09 20:09:44 +05:30
renovate[bot]andGitHub cccc6fd64b fix(deps): update dependency com.github.ben-manes:gradle-versions-plugin to v0.47.0 2023-06-09 11:04:49 +00:00
GitHub Actions aced95c542 chore(android): refresh baseline profile 2023-06-09 01:30:17 +00:00
Harsh Shandilya 90edeefd6e fix: remove useless toList 2023-06-09 02:04:58 +05:30
GitHub Actions a5b90851c8 feat(release): start next development iteration 2023-06-08 15:03:41 +00:00
GitHub Actions 7d0c6972ef feat(release): bump version 2023-06-08 15:02:17 +00:00
Harsh Shandilya 18cb5dc07c chore: refresh feature graphic 2023-06-08 20:18:09 +05:30
Harsh Shandilya 5343e13215 fix(scripts): ensure demo mode is correctly enabled 2023-06-08 19:55:55 +05:30
renovate[bot]andGitHub 4d06a2722c fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2023.04.00-beta02 2023-06-08 12:14:43 +00:00
Harsh Shandilya b9f5bee35e fix(scripts): make setup-age architecture agnostic 2023-06-08 11:53:55 +00:00
Harsh Shandilya 72078b2768 fix(scripts): bump age to v1.1.1 2023-06-08 11:53:55 +00:00
GitHub Actions 465191609b chore(android): refresh baseline profile 2023-06-08 11:48:51 +00:00
Harsh ShandilyaandGitHub 6e1858a55e fix(benchmark): adjust for API changes 2023-06-08 07:03:28 +00:00
renovate[bot]andGitHub 3eeb947914 fix(deps): update dependency io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin to v3.10.0 2023-06-08 00:02:53 +00:00
renovate[bot]andGitHub d2c99fa8b7 fix(deps): update androidx 2023-06-07 19:06:35 +00:00
renovate[bot]andGitHub dbba96426d chore(deps): update sentry 2023-06-07 15:43:33 +00:00
Harsh Shandilya a5be35a667 feat(core): manually wire in Sentry OkHttp integration 2023-06-07 21:04:24 +05:30
Harsh Shandilya 6e291a8df1 refactor(scripts): rework how Maestro flows are run 2023-06-07 18:07:18 +05:30
Harsh Shandilya 24898cf9fb chore: refresh feature graphic 2023-06-07 17:19:43 +05:30
Harsh Shandilya 66e64ac305 chore: update changelog 2023-06-07 16:24:08 +05:30
Harsh Shandilya ee6bcc864f feat: update iconography for consistency 2023-06-07 16:24:02 +05:30
Harsh Shandilya 8de49d670b fix(android): add visual indication when there are no saved posts 2023-06-07 16:11:18 +05:30
GitHub Actions 13b1c699f6 chore(android): refresh baseline profile 2023-06-07 01:34:08 +00:00
Harsh Shandilya 86a70ffb48 feat(common): remove animation for comment text 2023-06-07 02:42:15 +05:30
Harsh Shandilya 2bb71238bc fix(android): dismiss existing snackbars when showing a new one 2023-06-07 02:37:43 +05:30
Harsh Shandilya 7d491de86c fix(android): prevent comments page from stacking when spammed 2023-06-07 02:19:54 +05:30
Harsh Shandilya 02575a917b fix(android): check for previous back stack entry 2023-06-07 02:05:14 +05:30
renovate[bot]andGitHub 5206851b22 chore(deps): update dependency gradle to v8.2-rc-2 2023-06-06 19:03:10 +00:00
GitHub Actions 74c36f27ae chore(android): refresh baseline profile 2023-06-06 01:36:55 +00:00
Harsh Shandilya 2048a2bb9b chore: add test resources to .rgignore 2023-06-06 00:45:13 +05:30
renovate[bot]andGitHub ea48cdb4f3 chore(deps): update plugin modulegraphassert to v2.4.0 2023-06-05 16:10:44 +00:00
Harsh Shandilya 942b9f3fb4 fix(android): report fully drawn status 2023-06-05 16:50:29 +05:30
Harsh Shandilya 5f6d635c7a fix(android): inline useless function 2023-06-05 14:58:28 +05:30
Harsh Shandilya 47a398f518 refactor: move metadata-extractor to android 2023-06-05 13:24:22 +05:30
Harsh Shandilya 9fdd72220f feat(scripts): add a quick way to refresh the README graphic 2023-06-05 13:24:22 +05:30
Harsh Shandilya 0a1913e056 feat(build): add module-graph-assert plugin 2023-06-05 10:04:41 +05:30
Harsh Shandilya 68db3dcda6 refactor: move coroutine-utils into core 2023-06-05 09:52:12 +05:30
Harsh Shandilya c50c9c8528 chore: refresh module graph 2023-06-05 09:46:09 +05:30
Harsh Shandilya 8a418f6649 refactor: make SavedPostSerializer an object 2023-06-05 09:41:52 +05:30
Harsh Shandilya acdc924047 chore: cleanup redundant @OptIn annotations 2023-06-05 09:34:48 +05:30
GitHub Actions 2fa1d3f06f chore(android): refresh baseline profile 2023-06-05 01:37:40 +00:00
Harsh Shandilya 7ffa225487 feat(database): add test for SavedPostSerializer 2023-06-05 02:51:53 +05:30
Harsh Shandilya c1659eb2dd chore(gitignore): add claw-export.json 2023-06-05 02:18:09 +05:30
Harsh Shandilya 1e888494ee fix(build): temporarily revert to AGP 8.0.x
Android Studio's canary version is going through some trouble recognizing test sources
2023-06-05 02:16:57 +05:30
Harsh Shandilya 054ba13dc3 fix(ci): enforce concurrency for all workflows 2023-06-05 02:00:15 +05:30
Harsh Shandilya 301760c39f refactor(android): make String.toLocalDateTime private 2023-06-05 01:59:17 +05:30
Harsh Shandilya 79fd814c14 fix(android): add Snackbars to data transfer flow 2023-06-05 01:50:23 +05:30
Harsh Shandilya a82d0e7063 fix(android): only show data transfer action on home screen 2023-06-05 00:56:20 +05:30
Harsh Shandilya c6ea1182e0 refactor: remove explicit calls to rememberVectorPainter 2023-06-04 17:14:09 +00:00
Harsh Shandilya 5e7b79eb89 fix(android): hide data transfer action on data transfer screen 2023-06-04 21:19:22 +05:30
Harsh Shandilya 3738d94789 feat(android): wire up import/export settings to UI 2023-06-04 18:45:14 +05:30
Harsh Shandilya fb0e372917 feat(android): add DataTransferRepository 2023-06-04 18:45:14 +05:30
Harsh Shandilya 8945f9e33f feat(database): build a custom serializer for SavedPost 2023-06-04 18:45:14 +05:30
Harsh Shandilya 2895e7ffe7 refactor(android): split out comments functionality 2023-06-04 18:45:14 +05:30
GitHub Actions f102166fae chore(android): refresh baseline profile 2023-06-04 01:28:30 +00:00
Harsh Shandilya c51e28b8e1 fix: touch up version catalog 2023-06-04 01:33:25 +05:30
GitHub Actions a9923eb8c0 feat(release): start next development iteration 2023-06-03 18:50:53 +00:00
GitHub Actions de2f3964e0 feat(release): bump version 2023-06-03 18:46:20 +00:00
Harsh Shandilya 7c5ccbf63b fix: make nav transitions run at 2x of defaults 2023-06-04 00:03:38 +05:30
Harsh Shandilya b4b96222ed chore: reorder manifest attributes 2023-06-04 00:03:38 +05:30
Harsh Shandilya a920f899fb fix(android): automatically extract native libraries 2023-06-04 00:03:38 +05:30
GitHub Actions 31b39a49d6 chore(android): refresh baseline profile 2023-06-03 01:33:42 +00:00
renovate[bot]andGitHub bfb4e9741a chore(deps): update msfjarvis/keep-a-changelog-new-release action to v2.1.0 2023-06-02 22:59:13 +00:00
GitHub Actions bc5c5a13b4 chore(android): refresh baseline profile 2023-06-02 01:22:03 +00:00
renovate[bot]andGitHub 19c50f40cd chore(deps): update github/codeql-action action to v2.3.6 2023-06-01 19:54:14 +00:00
renovate[bot]andGitHub bb0a987d80 fix(deps): update dependency io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin to v3.8.0 2023-06-01 10:22:25 +00:00
Harsh Shandilya dba380e4c4 fix(gradle): remove default-enabled feature prop 2023-06-01 12:46:32 +05:30
Harsh Shandilya 4a52524212 fix(gradle): correct property name for CC 2023-06-01 12:46:32 +05:30
Harsh Shandilya 1a94ba5a40 fix(gradle): upgrade to 8.2-rc-1 2023-06-01 12:38:05 +05:30
GitHub Actions 2022255200 chore(android): refresh baseline profile 2023-06-01 01:33:44 +00:00
renovate[bot]andGitHub ab1951f9c5 fix(deps): update dependency com.slack.eithernet:eithernet to v1.4.1 2023-05-31 19:31:40 +00:00
renovate[bot]andGitHub a9176b8508 chore(deps): update dependency io.sentry:sentry-android to v6.21.0 2023-05-31 08:54:31 +00:00
GitHub Actions 02ad998b06 chore(android): refresh baseline profile 2023-05-31 01:23:45 +00:00
GitHub Actions 31059abf23 feat(release): start next development iteration 2023-05-31 01:11:15 +00:00
GitHub Actions fc70931c2c feat(release): bump version 2023-05-31 01:07:01 +00:00
renovate[bot]andGitHub af4a6c4672 chore(deps): update agp to v8.2.0-alpha06 2023-05-31 00:40:15 +00:00
Harsh Shandilya 3347224018 feat(database): use Requery's repackaged SQLite for databases 2023-05-31 06:09:44 +05:30
Harsh Shandilya 558062a915 Revert "feat: add some navigation transitions"
This was fun but good lord it is ugly

This reverts commit 4f4b480a13.
2023-05-31 05:57:25 +05:30
Harsh Shandilya a7ab941543 chore(deps): update sqldelight to v2.0.0-rc01 2023-05-31 05:54:11 +05:30
renovate[bot]andGitHub 57b5f33720 fix(deps): update dependency com.google.truth:truth to v1.1.4 2023-05-30 17:18:20 +00:00
GitHub Actions f36d0ef5e6 chore(android): refresh baseline profile 2023-05-30 01:24:00 +00:00
GitHub Actions 0d9b0fec6b chore(android): refresh baseline profile 2023-05-29 06:19:36 +00:00
Harsh Shandilya d1b83410d0 fix(ci): adjust baseline profile path 2023-05-29 11:12:39 +05:30
Harsh Shandilya 990bb26276 fix(deps): update accompanist to 0.31.3-beta 2023-05-29 11:05:56 +05:30
Harsh Shandilya 4f4b480a13 feat: add some navigation transitions 2023-05-28 18:14:11 +05:30
Harsh Shandilya b2490cd014 fix: wrap DatabasePosts content in a Box 2023-05-28 18:13:53 +05:30
Harsh Shandilya 9d85563cf2 fix: remove deeplink for lobste.rs
It makes logging in to the website from a browser fairly annoying for minimal gain
2023-05-28 17:25:04 +05:30
Harsh Shandilya ac573d9311 chore: add changelog entry for adaptive nav 2023-05-28 17:22:52 +05:30
Harsh Shandilya 1e5ae4048c fix: make nav rail animate horizontally 2023-05-28 14:01:04 +05:30
Harsh Shandilya 3db05fb3b1 fix: remove dubious return 2023-05-28 14:01:04 +05:30
Harsh ShandilyaandGitHub 5a098e125a Apply suggestions from code review 2023-05-28 13:39:39 +05:30
Yash-Garg 78b77fd4c1 feat: add adaptive navigation for different screen sizes 2023-05-28 13:17:55 +05:30
renovate[bot]andGitHub b2470ca89b chore(deps): pin actions/cache action to 88522ab 2023-05-27 23:56:18 +00:00
Harsh Shandilya 4764698583 fix(ci): manually cache Android SDK build-tools
This is necessary to avoid the extremely slow re-download on each run
2023-05-28 03:19:10 +05:30
Harsh Shandilya c91a34aae5 chore: update changelog 2023-05-27 01:36:06 +05:30
Harsh Shandilya 8dc76f6ce5 fix(renovate): avoid R8 updates 2023-05-26 19:21:49 +05:30
Harsh Shandilya 0ebe949da6 Revert "feat(renovate): keep R8 up-to-date with ToT"
This reverts commit 25c78eed91.
2023-05-26 19:19:18 +05:30
Harsh Shandilya 6c1a40d614 fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2023.04.00-beta01.1 2023-05-26 19:18:29 +05:30
renovate[bot]andGitHub 9a81d06e2d chore(deps): update dependency io.sentry:sentry-android to v6.20.0 2023-05-26 12:40:11 +00:00
renovate[bot]andGitHub 687cd210af chore(deps): update r8 digest to c765114 2023-05-26 09:54:10 +00:00
Harsh ShandilyaandGitHub 87135c0e1b fix(renovate): stop treating R8 as a Maven dependency 2023-05-26 15:23:23 +05:30
Harsh Shandilya 48cfa6b7f1 fix(deps): update AndroidX Navigation and kotlinx.serialization 2023-05-26 01:55:49 +05:30
Harsh Shandilya 25c78eed91 feat(renovate): keep R8 up-to-date with ToT 2023-05-26 01:20:08 +05:30
renovate[bot]andGitHub 6a50387c39 chore(deps): update agp to v8.2.0-alpha05 2023-05-25 19:41:42 +00:00
renovate[bot]andHarsh Shandilya bac6f65dd0 chore(deps): update github/codeql-action action to v2.3.5 2023-05-26 01:08:19 +05:30
Harsh Shandilya 5ec34fea3b fix(ci): accept all SDK licenses 2023-05-26 01:08:19 +05:30
Harsh Shandilya 539e53c6b1 fix: add Retrofit R8 rules 2023-05-26 01:08:19 +05:30
Harsh Shandilya dfe108d13e fix(deps): use an unreleased R8 build with verifier crash fix 2023-05-26 01:08:19 +05:30
Harsh Shandilya 37e6c87046 feat: move up to AGP 8.2.x 2023-05-25 22:19:58 +05:30
renovate[bot]andGitHub e92929910d chore(deps): update github/codeql-action action to v2.3.4 2023-05-25 04:40:10 +00:00
GitHub Actions 7488afdbb3 chore(android): refresh baseline profile 2023-05-25 01:27:30 +00:00
renovate[bot]andGitHub 2dbc99a27a chore(deps): update agp to v8.0.2 2023-05-24 21:57:29 +00:00
renovate[bot]andGitHub 1dd26feebb fix(deps): update androidx 2023-05-24 18:55:21 +00:00
renovate[bot]andGitHub 203847dcd7 fix(deps): update dependency dev.chrisbanes.compose:compose-bom to v2023.04.00-beta01 2023-05-24 18:06:07 +00:00
renovate[bot]andGitHub a4a3620f71 fix(deps): update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.19.0 2023-05-24 04:02:03 +00:00
GitHub Actions 5fba9bfe7b chore(android): refresh baseline profile 2023-05-24 01:27:21 +00:00
renovate[bot]andGitHub c05aa75f1e fix(deps): update dependency com.google.testparameterinjector:test-parameter-injector to v1.12 2023-05-23 11:44:26 +00:00
GitHub Actions 2f378aaeec chore(android): refresh baseline profile 2023-05-22 01:27:24 +00:00
renovate[bot]andGitHub e92279634d fix(deps): update coil to v2.4.0 2023-05-21 19:07:33 +00:00
Harsh Shandilya 1bc15b7b7c fix(renovate): disable Coil updates
Coil 2.4.0 uses Kotlin 1.8.21 that we can't use yet
2023-05-21 20:41:20 +05:30
GitHub Actions 7d8083b268 chore(android): refresh baseline profile 2023-05-21 01:26:45 +00:00
GitHub Actions 7035159fa6 chore(android): refresh baseline profile 2023-05-20 01:23:53 +00:00
renovate[bot]andGitHub a2a9446e3b fix(deps): update dependency com.slack.eithernet:eithernet to v1.4.0 2023-05-19 19:34:10 +00:00
renovate[bot]andGitHub 5c40fedde2 chore(deps): update sentry to v6.19.1 2023-05-19 12:45:15 +00:00
GitHub Actions a44ca13e3a chore(android): refresh baseline profile 2023-05-19 01:22:06 +00:00
GitHub Actions 67f3595d33 chore(android): refresh baseline profile 2023-05-18 01:27:06 +00:00
Harsh Shandilya ae10d433e6 refactor: switch to Material Icons
Our previous system resulted in leaner code but was way too annoying to add
new icons to.
2023-05-18 02:03:17 +05:30
Harsh Shandilya e33768d9ca fix(android): set assist URI for profile page 2023-05-18 02:03:17 +05:30
renovate[bot]andGitHub 7624fa204d fix(deps): update dependency io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin to v3.7.0 2023-05-17 12:31:46 +00:00
renovate[bot]andGitHub 4738674f7f chore(deps): update sentry to v6.19.0 2023-05-16 13:05:10 +00:00
Harsh Shandilya 7cbc96161e feat(build): raise target bytecode to Java 17 2023-05-16 16:14:10 +05:30
Harsh Shandilya d940ba252e chore: expand changelog 2023-05-16 13:32:46 +05:30
GitHub Actions 60507cc817 chore(android): refresh baseline profile 2023-05-15 01:20:52 +00:00
GitHub Actions 3a99c28233 chore(android): refresh baseline profile 2023-05-14 01:23:15 +00:00
Harsh Shandilya 7e91628339 feat: switch over to Compose alphas 2023-05-13 19:27:28 +05:30
GitHub Actions eb053eb5bf chore(android): refresh baseline profile 2023-05-13 01:24:08 +00:00
renovate[bot]andGitHub 7462b1a2f7 fix(deps): update dagger to v2.46.1 2023-05-12 22:00:05 +00:00
Harsh Shandilya 8d557c3898 fix(deps): update coroutines to 1.7.1 2023-05-13 02:49:04 +05:30
Harsh Shandilya 6b1c53c31a chore(gradle): sort dependencies 2023-05-12 13:15:36 +05:30
GitHub Actions 5e27937358 chore(android): refresh baseline profile 2023-05-12 01:20:49 +00:00
renovate[bot]andGitHub a8aad809ba fix(deps): update dependency io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin to v3.6.0 2023-05-11 17:18:55 +00:00
Harsh ShandilyaandGitHub d94ca0e9c6 fix(deps): remove unused kotest dependencies (#375) 2023-05-11 04:19:58 +00:00
GitHub Actions aa51535e65 chore(android): refresh baseline profile 2023-05-11 01:27:50 +00:00
Harsh Shandilya 7737c82db9 fix: switch TopAppBar to non-deprecated APIs 2023-05-11 01:30:36 +05:30
renovate[bot]andGitHub 7ee64e0ead fix(deps): update androidx 2023-05-10 19:51:26 +00:00
Harsh Shandilya 987990704c fix(renovate): group all AndroidX updates 2023-05-11 01:20:53 +05:30
GitHub Actions e8975e70f5 chore(android): refresh baseline profile 2023-05-09 01:23:53 +00:00
GitHub Actions 72409a0b73 chore(android): refresh baseline profile 2023-05-08 01:25:09 +00:00
Harsh Shandilya 3dfd2d7862 chore: rework dependency declaration 2023-05-07 11:16:19 +00:00
Harsh ShandilyaandGitHub c93d2f73a9 fix(maestro): correct tap index
I initially wrote this to tap the 1st and 3rd save button but failed to account for the fact that once the first button was pressed, its text property would no longer be "Add to saved posts" which results in index=2 actually pointing to the 4th absolute position in the list.
2023-05-06 12:25:08 +05:30
Harsh Shandilya 66d638f952 fix(benchmark): raise min SDK to align with API requirements 2023-05-06 02:24:37 +05:30
Harsh Shandilya 815a8f186b chore: rejig README 2023-05-06 02:23:39 +05:30
Harsh Shandilya ae745b917e chore: refresh README feature image 2023-05-06 02:22:04 +05:30
Harsh Shandilya bd759c53cd chore(deps): update coroutines to 1.7.0 2023-05-06 02:02:34 +05:30
renovate[bot]andGitHub 8dca324f71 chore(deps): update plugin modulegraph to v0.4.0 2023-05-05 19:49:51 +00:00
Harsh Shandilya dd7a7d9977 feat: use Maestro to automatically generate Play Store screenshots 2023-05-05 21:01:31 +05:30
Harsh Shandilya a7c81a77f2 fix(android): make nav content description less shouty 2023-05-05 20:42:27 +05:30
Harsh Shandilya 15b1e68611 Revert "feat: add gradle-dependencies-sort plugin"
The lexer/parser on this is very sensitive to custom APIs being used in the
`dependencies {}` DSL.

This reverts commit 069c5a4389.
2023-05-05 20:31:29 +05:30
Harsh Shandilya a5e25e2eb5 refactor(build): simplify test dependency setup 2023-05-05 20:31:29 +05:30
renovate[bot]andGitHub c10ec27b51 chore(deps): update github/codeql-action action to v2.3.3 2023-05-04 20:26:50 +00:00
Harsh Shandilya 9c86a9124d fix: sort dependencies 2023-05-04 15:16:31 +05:30
Harsh Shandilya 069c5a4389 feat: add gradle-dependencies-sort plugin 2023-05-04 15:09:41 +05:30
Harsh Shandilya b498cf4b62 feat: fix Sentry disabling logic again 2023-05-04 14:09:05 +05:30
GitHub Actions 70ee848a41 chore(android): refresh baseline profile 2023-05-04 01:28:37 +00:00
GitHub Actions 60fd6a4af4 feat(release): start next development iteration 2023-05-03 22:38:06 +00:00
GitHub Actions 04ed687dbb feat(release): bump version 2023-05-03 22:37:02 +00:00
Harsh Shandilya d694415a4a chore: re-sync Lint baseline 2023-05-04 03:53:36 +05:30
Harsh Shandilya 3f2a9c999b chore: sync changelog 2023-05-04 03:52:18 +05:30
Harsh Shandilya ea40650214 feat(android): migrate away from kotest 2023-05-04 03:38:23 +05:30
Harsh Shandilya ae66aced83 feat(api): migrate away from kotest 2023-05-04 03:33:47 +05:30
Harsh Shandilya 5d2eebf093 fix(api): add test util for type assertion 2023-05-04 03:33:47 +05:30
Harsh Shandilya 5c8057d71f fix(model): implement contains operator fun for Tags 2023-05-04 03:33:47 +05:30
Harsh Shandilya 4d78a73602 feat(database): migrate away from kotest 2023-05-04 03:33:47 +05:30
Harsh Shandilya 7c5a9eb683 feat(build): add JUnit 5 and Truth deps 2023-05-04 03:33:47 +05:30
renovate[bot]andGitHub df423d28d6 fix(deps): update dependency androidx.profileinstaller:profileinstaller to v1.3.1 2023-05-03 20:29:20 +00:00
renovate[bot]andHarsh Shandilya a92616c5a3 fix(deps): update dependency androidx.benchmark:benchmark-macro-junit4 to v1.2.0-alpha14 2023-05-04 01:58:30 +05:30
renovate[bot]andHarsh Shandilya 2fc29f65ca fix(deps): update dependency androidx.compose:compose-bom to v2023.05.00 2023-05-04 01:58:30 +05:30
Harsh Shandilya aab712e680 fix(android): migrate to new paging-compose APIs 2023-05-04 01:58:30 +05:30
renovate[bot]andGitHub 4bca86d91e fix(deps): update dependency androidx.paging:paging-compose to v1.0.0-alpha19 2023-05-03 18:41:29 +00:00
GitHub Actions 63cca3eba2 chore(android): refresh baseline profile 2023-05-03 01:28:04 +00:00
Harsh Shandilya cba2ed5944 fix: strip out invalid R8 rules 2023-05-03 01:58:22 +05:30
Harsh Shandilya ee5886c9b9 chore(benchmark): use method reference 2023-05-02 19:45:28 +05:30
Harsh Shandilya e96dadae34 fix(scripts): adjust emulator bootup routines 2023-05-02 19:45:28 +05:30
Harsh Shandilya a23ad82b60 fix(scripts): migrate away from deprecated ANDROID_SDK_ROOT 2023-05-02 19:45:28 +05:30
GitHub Actions f816580886 chore(android): refresh baseline profile 2023-05-02 01:28:03 +00:00
renovate[bot]andGitHub a5f8f1a4c2 chore(deps): update agp to v8.0.1 2023-05-01 18:30:20 +00:00
GitHub Actions 0d47f06be3 chore(android): refresh baseline profile 2023-05-01 01:31:57 +00:00
GitHub Actions c4eb2d2116 chore(android): refresh baseline profile 2023-04-30 01:32:24 +00:00
renovate[bot]andGitHub 8c1dc62211 fix(deps): update dependency org.jsoup:jsoup to v1.16.1 2023-04-29 08:41:46 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Harsh Shandilya
b1a66bb8dd chore(deps): update dependency com.facebook:ktfmt to v0.44 (#374)
* chore(deps): update dependency com.facebook:ktfmt to v0.44

* chore: reformat

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
2023-04-29 09:48:04 +05:30
GitHub Actions 61a2cefcc3 chore(android): refresh baseline profile 2023-04-29 01:27:42 +00:00
renovate[bot]andGitHub ad775bf8e1 fix(deps): update dagger to v2.46 2023-04-28 22:48:14 +00:00
renovate[bot]andGitHub a80e8bb298 fix(deps): update dependency io.sentry:sentry-bom to v6.18.1 2023-04-28 19:06:41 +00:00
renovate[bot]andGitHub 2db51746ac chore(deps): update github/codeql-action action to v2.3.2 2023-04-28 05:12:08 +00:00
GitHub Actions 3d7e6d7f4c chore(android): refresh baseline profile 2023-04-28 01:20:55 +00:00
Harsh Shandilya 6918cf5f76 fix(core): adjust OkHttp config 2023-04-27 18:52:21 +05:30
renovate[bot]andGitHub cd05ed4da9 chore(deps): update sentry to v6.18.0 2023-04-27 12:49:45 +00:00
renovate[bot]andGitHub b669900c75 chore(deps): update github/codeql-action action to v2.3.1 2023-04-27 03:05:16 +00:00
GitHub Actions 3a9bf04a4d chore(android): refresh baseline profile 2023-04-27 01:23:43 +00:00
Harsh Shandilya 0cd4257e73 Revert "feat(build): upgrade to AGP 8.1.0-beta01"
Newer AGP releases cause incorrect desugaring of the Crux dependency

This reverts commit 68a20e0d11.
2023-04-26 14:37:03 +00:00
Harsh ShandilyaandGitHub 6f55da754c fix(deps): de-commonize AndroidX Test versioning 2023-04-25 21:11:50 +05:30
Harsh ShandilyaandGitHub 31adb45152 fix(deps): rollback AndroidX Test version to 1.6.0-alpha01
alpha02 doesn't exist
2023-04-25 20:03:31 +05:30
Harsh Shandilya 68a20e0d11 feat(build): upgrade to AGP 8.1.0-beta01 2023-04-25 18:42:05 +05:30
renovate[bot]andGitHub 52657b0c08 fix(deps): update dependency androidx.test:runner to v1.6.0-alpha02 2023-04-25 05:06:38 +00:00
Harsh Shandilya a2123b7a5d chore: remove unnecessary suppress 2023-04-25 01:23:06 +05:30
Harsh Shandilya 207f98ca17 feat(common): add a preview for LobstersCard 2023-04-25 01:20:43 +05:30
Harsh Shandilya 58170b6072 feat: disable Sentry performance reporting and profiling
These features are going paid and I do not care enough to foot the bill
2023-04-24 23:36:47 +05:30
GitHub Actions 744955bf11 chore(android): refresh baseline profile 2023-04-24 01:21:34 +00:00
renovate[bot]andGitHub cd6d53d19e fix(deps): update dependency com.squareup.okhttp3:okhttp-bom to v4.11.0 2023-04-23 02:00:02 +00:00
GitHub Actions 50e03fbd50 chore(android): refresh baseline profile 2023-04-22 01:19:16 +00:00
renovate[bot]andGitHub 6dd219ee05 chore(deps): update github/codeql-action action to v2.3.0 2023-04-21 20:06:55 +00:00
renovate[bot]andGitHub 2a6cd96c8c chore(deps): update dependency gradle to v8.1.1 2023-04-21 15:30:29 +00:00
Harsh Shandilya 1323668fe6 feat(build): add a task to collect Lint SARIF reports 2023-04-20 18:00:01 +05:30
Harsh Shandilya 24b747eb38 fix(build): correct plugin application ordering 2023-04-20 18:00:01 +05:30
Harsh Shandilya ed31d1fefb chore(lint): update lint baselines 2023-04-20 18:00:01 +05:30
Harsh Shandilya 237a06f1cf feat(build): apply Android Lint plugin to JVM modules 2023-04-20 18:00:01 +05:30
renovate[bot]andGitHub 06528e7504 fix(deps): update dependency androidx.test.uiautomator:uiautomator to v2.3.0-alpha03 2023-04-20 06:00:10 +00:00
renovate[bot]andGitHub 387f9a2601 fix(deps): update dependency androidx.navigation:navigation-compose to v2.6.0-beta01 2023-04-20 05:17:28 +00:00
renovate[bot]andGitHub 4bcfd083d6 fix(deps): update dependency androidx.core:core-splashscreen to v1.0.1 2023-04-20 01:49:30 +00:00
renovate[bot]andGitHub 0e922176fe fix(deps): update dependency androidx.activity:activity-compose to v1.7.1 2023-04-19 22:03:59 +00:00
Harsh Shandilya 250e7c20e5 feat(common): use FlowRow from Compose Foundation 2023-04-20 01:44:43 +05:30
Harsh Shandilya c3de960966 feat(deps): upgrade to Compose 2023.04.01 2023-04-20 01:19:27 +05:30
renovate[bot]andGitHub 866995b2d3 fix(deps): update dependency com.slack.lint.compose:compose-lint-checks to v1.2.0 2023-04-19 16:53:22 +00:00
Harsh Shandilya 825ee23afe chore: convert launcher assets from PNG to WebP 2023-04-19 17:25:09 +05:30
Harsh Shandilya 66ce35927a refactor(build): extract out Lint config 2023-04-19 17:16:06 +05:30
Harsh Shandilya 468d363c65 feat(build): rework Lint config
- Export SARIF output
- Expand enabled ruleset
- Make HTML reports more detailed
2023-04-19 15:19:15 +05:30
Harsh Shandilya 009744cb47 fix(ci): ensure full history is cloned 2023-04-19 14:51:37 +05:30
Harsh Shandilya 2d63a1e79f chore: sync up copyright headers 2023-04-19 12:38:36 +05:30
Harsh Shandilya 5452c55e86 chore(build): enable Spotless license header sync by default 2023-04-19 12:37:44 +05:30
Harsh Shandilya 6b164f84d9 refactor(build): migrate to Kotlin compilerOptions DSL 2023-04-19 12:36:03 +05:30
Harsh Shandilya bf104a1d85 chore(build): reorder DSL declarations 2023-04-19 12:29:27 +05:30
renovate[bot]andGitHub 1d32ec810f fix(deps): update dependency com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter to v1 2023-04-19 05:18:18 +00:00
GitHub Actions 1f7b9dbbc4 chore(android): refresh baseline profile 2023-04-19 01:22:24 +00:00
renovate[bot]andGitHub 8c0bfc2143 fix(deps): update kotest to v5.6.1 2023-04-18 20:18:21 +00:00
GitHub Actions 279ddd9974 feat(release): start next development iteration 2023-04-18 08:50:27 +00:00
GitHub Actions 71b29c0b56 feat(release): bump version 2023-04-18 08:48:54 +00:00
Harsh Shandilya b331a85a2a chore: remove Qodana configurations 2023-04-18 14:06:49 +05:30
Harsh Shandilya e8037e8d60 chore(codeql): run analysis on pushes to main branch 2023-04-18 13:57:29 +05:30
Harsh Shandilya ea0dd4cb78 feat(core): implement certificate pinning for lobste.rs 2023-04-18 13:44:31 +05:30
GitHub ActionsandHarsh Shandilya 4734ab4a22 chore(android): refresh baseline profile 2023-04-18 13:44:31 +05:30
Harsh Shandilya 4df97acd73 fix(codeql): manually build project 2023-04-18 13:44:31 +05:30
GitHub ActionsandHarsh Shandilya 8ec233d761 chore(android): refresh baseline profile 2023-04-18 13:44:31 +05:30
renovate[bot]andHarsh Shandilya 135a1fc5ed fix(deps): update kotest to v5.6.0 2023-04-18 13:44:31 +05:30
GitHub ActionsandHarsh Shandilya 4cb5b09001 chore(android): refresh baseline profile 2023-04-18 13:44:31 +05:30
Harsh Shandilya 3bb8b51cb5 chore: update changelog 2023-04-18 13:44:31 +05:30
GitHub ActionsandHarsh Shandilya 1ee31873ab chore(android): refresh baseline profile 2023-04-18 13:44:31 +05:30
Harsh Shandilya 79fac06a4c fix(benchmark): adjust baseline profile iterations 2023-04-18 13:44:31 +05:30
Harsh Shandilya 553bbedc95 feat(benchmark): migrate to Gradle Managed Devices 2023-04-18 13:44:31 +05:30
Harsh Shandilya d31fe53f78 chore: change benchmark package name 2023-04-18 13:44:18 +05:30
Harsh Shandilya be74e52156 fix: adjust baseline profile emulator options 2023-04-18 13:44:18 +05:30
Harsh Shandilya a2157ae618 feat: rework Sentry disabling logic for benchmark builds 2023-04-18 13:44:18 +05:30
Harsh Shandilya 8b7bcaa92f fix(renovate): disable Kotlin updates
Renovate can't understand how to stop
2023-04-18 13:44:18 +05:30
renovate[bot]andHarsh Shandilya 157998ddf5 fix(deps): update dependency org.gradle.android.cache-fix:org.gradle.android.cache-fix.gradle.plugin to v2.7.1 2023-04-18 13:44:18 +05:30
renovate[bot]andHarsh Shandilya cd302bb1bb chore(deps): update gradle/gradle-build-action action to v2.4.2 2023-04-18 13:44:18 +05:30
GitHub ActionsandHarsh Shandilya 52341757e4 chore(android): refresh baseline profile 2023-04-18 13:44:18 +05:30
GitHub ActionsandHarsh Shandilya a74633df54 chore(android): refresh baseline profile 2023-04-18 13:44:18 +05:30
Harsh Shandilya b936b54132 feat: rework system bar colors 2023-04-18 13:44:18 +05:30
Harsh Shandilya cf111f7852 fix: include Anvil updates in Kotlin bundle 2023-04-18 13:44:18 +05:30
renovate[bot]andHarsh Shandilya f23f9498cd chore(deps): update github/codeql-action action to v2.2.12 2023-04-18 13:44:18 +05:30
Harsh Shandilya 7c019353df feat(deps): upgrade AGP to 8.0.0 2023-04-18 13:44:18 +05:30
renovate[bot]andGitHub 3954e63141 chore(deps): update actions/checkout action to v3.5.2 2023-04-13 15:11:26 +00:00
renovate[bot]andGitHub d04d638b27 chore(deps): update gradle/gradle-build-action action to v2.4.1 2023-04-13 08:23:27 +00:00
renovate[bot]andGitHub 3ad414dadd chore(deps): update actions/checkout action to v3.5.1 2023-04-13 02:43:26 +00:00
GitHub Actions 8bc9bd4dbb chore(android): refresh baseline profile 2023-04-13 01:30:13 +00:00
renovate[bot]andGitHub b0c3066adc chore(deps): update dependency gradle to v8.1 2023-04-12 15:06:23 +00:00
GitHub Actions c5dfd4fffe chore(android): refresh baseline profile 2023-04-12 01:30:16 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
7de7b4f843 chore(deps): update dependency gradle to v8.1-rc-4 (#369)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-12 00:30:14 +05:30
GitHub Actions 7079c5a6f1 chore(android): refresh baseline profile 2023-04-09 01:24:44 +00:00
GitHub Actions 46ebda2673 chore(android): refresh baseline profile 2023-04-08 01:20:21 +00:00
GitHub Actions eee9df7d8a chore(android): refresh baseline profile 2023-04-07 01:30:51 +00:00
renovate[bot]andGitHub f8be557e6e chore(deps): update github/codeql-action action to v2.2.11 2023-04-06 17:43:27 +00:00
renovate[bot]andGitHub d6f776e12e fix(deps): update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.18.0 2023-04-06 05:46:57 +00:00
GitHub Actions 6fd3f32f7e chore(android): refresh baseline profile 2023-04-06 01:25:12 +00:00
renovate[bot]andHarsh Shandilya adbb400728 fix(deps): update dependency androidx.navigation:navigation-compose to v2.6.0-alpha09
(cherry picked from commit 4a0fa59c9189eb18eff966c47d2307a5591cfbc5)
2023-04-06 01:33:59 +05:30
renovate[bot]andHarsh Shandilya 8f6a46aa2e fix(deps): update dependency androidx.datastore:datastore-preferences to v1.1.0-alpha04
(cherry picked from commit 8a78f2bd470adfad7130826b7b550d0c20e4a4e7)
2023-04-06 01:33:59 +05:30
renovate[bot]andHarsh Shandilya 0ec52b84fe fix(deps): update dependency androidx.compose:compose-bom to v2023.04.00
(cherry picked from commit c67e4d2923965a671e3043a9f503c3a0ea88013e)
2023-04-06 01:33:59 +05:30
renovate[bot]andHarsh Shandilya b436f10e18 chore(deps): update github/codeql-action action to v2.2.10
(cherry picked from commit 5fed8bd9d309fb18f4b24b09458e859fd939d9f5)
2023-04-06 01:06:50 +05:30
renovate[bot]andHarsh Shandilya 75ebf57c68 fix(deps): update dependency androidx.benchmark:benchmark-macro-junit4 to v1.2.0-alpha13
(cherry picked from commit 8293dccef8722344993e3cc55e4e6806e16db804)
2023-04-06 01:06:50 +05:30
GitHub Actions b3cea28687 chore(android): refresh baseline profile 2023-04-05 01:30:38 +00:00
renovate[bot]andGitHub 878b51fa30 fix(deps): update dependency io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin to v3.5.0 2023-04-04 19:19:14 +00:00
renovate[bot]andGitHub 81f024d197 chore(deps): update dependency gradle to v8.1-rc-3 2023-04-04 12:41:24 +00:00
renovate[bot]andHarsh Shandilya a21d665f5d chore(deps): update plugin modulegraph to v0.3.0
(cherry picked from commit d600239ba264490346e4fcaef321c50d8883119e)
2023-04-04 11:24:46 +05:30
renovate[bot]andGitHub 954bc9710b fix(deps): update accompanist to v0.30.1 2023-04-04 04:05:45 +00:00
GitHub Actions 5faeef190d chore(android): refresh baseline profile 2023-04-04 01:22:37 +00:00
GitHub Actions 43c5f93b60 chore(android): refresh baseline profile 2023-04-03 01:28:56 +00:00
Harsh Shandilya adfac94094 feat: add a module graph to the README 2023-04-02 23:44:54 +05:30
GitHub Actions bc60929fe9 chore(android): refresh baseline profile 2023-04-02 01:25:34 +00:00
GitHub Actions fdf2564f15 chore(android): refresh baseline profile 2023-04-01 01:22:47 +00:00
renovate[bot]andGitHub 8b6d422d96 chore(deps): update sentry to v6.17.0 2023-03-31 11:01:58 +00:00
GitHub Actions d2c0fea75f chore(android): refresh baseline profile 2023-03-31 01:23:47 +00:00
GitHub Actions efa5afb441 chore(android): refresh baseline profile 2023-03-30 01:28:39 +00:00
Harsh Shandilya 830144d5b1 fix(gradle): CC is now stable 2023-03-29 15:18:15 +05:30
Harsh Shandilya f6b684ceb0 chore(build): upgrade to Gradle 8.1 RC2 2023-03-29 15:18:00 +05:30
GitHub Actions cd3dfc065b chore(android): refresh baseline profile 2023-03-29 01:25:25 +00:00
Harsh Shandilya 72c1529bb9 chore: sort dependencies with gradle-dependencies-sorter 2023-03-28 12:15:18 +05:30
GitHub Actions 1b17da668d chore(android): refresh baseline profile 2023-03-28 01:32:21 +00:00
renovate[bot]andGitHub 3e7f50f4bf chore(deps): update actions/setup-java action to v3.11.0 2023-03-27 16:11:28 +00:00
renovate[bot]andGitHub 12bc6a06fb chore(deps): update github/codeql-action action to v2.2.9 2023-03-27 15:47:54 +00:00
GitHub Actions c3f146723a chore(android): refresh baseline profile 2023-03-27 01:26:13 +00:00
renovate[bot]andGitHub f64254ccef fix(deps): update coil to v2.3.0 2023-03-26 03:37:24 +00:00
GitHub Actions 0a43d9c9f6 chore(android): refresh baseline profile 2023-03-26 01:25:07 +00:00
GitHub Actions dcb9bfeb18 chore(android): refresh baseline profile 2023-03-25 01:27:05 +00:00
renovate[bot]andGitHub d6f5ea444d fix(deps): update dependency androidx.datastore:datastore-preferences to v1.1.0-alpha03 2023-03-24 19:06:44 +00:00
renovate[bot]andGitHub 3a3e02a937 fix(deps): update dependency com.google.testparameterinjector:test-parameter-injector to v1.11 2023-03-24 14:03:24 +00:00
GitHub Actions b5109fc872 feat(release): start next development iteration 2023-03-24 09:56:53 +00:00
GitHub Actions d9ed25478f feat(release): bump version 2023-03-24 09:55:40 +00:00
Harsh Shandilya f5c9da6aa0 chore: update changelog 2023-03-24 15:24:23 +05:30
Harsh Shandilya 293c04b2ad fix(build): remove DSL_SCOPE_VIOLATION suppression 2023-03-24 14:59:34 +05:30
Harsh Shandilya e91b344bea fix(build): remove no longer needed SAM conversion flag 2023-03-24 14:59:34 +05:30
Harsh Shandilya 491d8a6e71 fix(build): remove no longer needed afterEvaluate 2023-03-24 14:37:01 +05:30
Harsh Shandilya 04054914f5 chore(build): upgrade to Gradle 8.1 RC1 2023-03-24 14:35:56 +05:30
Harsh Shandilya d273c6f7b5 fix(ci): use exact versions 2023-03-24 14:27:03 +05:30
renovate[bot]andGitHub 9cf134e916 chore(deps): update actions/checkout action to v3.5.0 2023-03-24 06:43:57 +00:00
renovate[bot]andGitHub abd1e73d82 chore(deps): update actions/checkout digest to 8f4b7f8 2023-03-24 06:04:09 +00:00
GitHub Actions 5625aebb0c chore(android): refresh baseline profile 2023-03-24 01:25:53 +00:00
renovate[bot]andGitHub b84393c0d6 fix(deps): update accompanist to v0.30.0 2023-03-23 03:06:25 +00:00
GitHub Actions c0021ff5dc chore(android): refresh baseline profile 2023-03-23 01:28:23 +00:00
renovate[bot]andGitHub 9e1893612c chore(deps): update github/codeql-action digest to 67a35a0 2023-03-22 21:09:02 +00:00
Harsh Shandilya 3c2c577628 fix(deps): upgrade AndroidX dependencies 2023-03-23 01:00:07 +05:30
Harsh Shandilya 190b7b4026 fix(gradle): remove unused version declaration 2023-03-23 01:00:07 +05:30
renovate[bot]andGitHub 6fa03bad66 chore(deps): update dependency androidx.compose.compiler:compiler to v1.4.4 2023-03-22 18:49:52 +00:00
GitHub Actions 0a84659b70 chore(android): refresh baseline profile 2023-03-22 01:21:36 +00:00
GitHub Actions dec5873682 chore(android): refresh baseline profile 2023-03-21 01:30:49 +00:00
renovate[bot]andGitHub 8fc18f8324 fix(deps): update dependency io.sentry.android.gradle:io.sentry.android.gradle.gradle.plugin to v3.4.3 2023-03-20 21:00:07 +00:00
GitHub Actions 590240b283 chore(android): refresh baseline profile 2023-03-20 01:24:09 +00:00
GitHub Actions 4b90ff49fd chore(android): refresh baseline profile 2023-03-19 01:27:20 +00:00
renovate[bot]andGitHub 2223cea395 chore(deps): update reactivecircus/android-emulator-runner digest to d94c3fb 2023-03-18 11:39:49 +00:00
GitHub Actions ad692b73ba chore(android): refresh baseline profile 2023-03-18 01:23:26 +00:00
renovate[bot]andGitHub de57d089eb chore(deps): update sentry to v6.16.0 2023-03-17 10:57:52 +00:00
GitHub Actions 303a706d8a chore(android): refresh baseline profile 2023-03-17 01:23:23 +00:00
GitHub Actions 108bbbda87 chore(android): refresh baseline profile 2023-03-16 01:24:39 +00:00
renovate[bot]andGitHub 65f060a8d2 chore(deps): update actions/checkout action to v3.4.0 2023-03-15 23:04:10 +00:00
renovate[bot]andGitHub f35f0af6d8 chore(deps): update actions/checkout digest to 24cb908 2023-03-15 20:05:42 +00:00
renovate[bot]andGitHub 6c30892def chore(deps): update github/codeql-action digest to 168b99b 2023-03-15 16:58:44 +00:00
GitHub Actions 1016c85e3c chore(android): refresh baseline profile 2023-03-15 01:27:15 +00:00
renovate[bot]andGitHub 887c05c2b9 fix(deps): update dependency nl.littlerobots.version-catalog-update:nl.littlerobots.version-catalog-update.gradle.plugin to v0.8.0 2023-03-14 10:50:38 +00:00
renovate[bot]andHarsh Shandilya 98cb50fab7 chore(deps): update actions/cache action to v3.3.1
(cherry picked from commit 5d965a3cf41e5ef781451c232c5965800b2d0a7b)
2023-03-14 16:19:03 +05:30
renovate[bot]andHarsh Shandilya 38d75b0e51 fix(deps): update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.17.0
(cherry picked from commit f693de3a5ef4c2c90b6e715d9221b2cc6e7a3e0a)
2023-03-14 16:19:03 +05:30
Harsh Shandilya 20a2389eb0 feat(android): set up DataStore 2023-03-14 16:19:03 +05:30
GitHub Actions 9cbc754574 chore(android): refresh baseline profile 2023-03-12 01:19:11 +00:00
GitHub Actions b564283419 chore(android): refresh baseline profile 2023-03-11 01:21:57 +00:00
renovate[bot]andGitHub 32dd218131 chore(deps): update github/codeql-action digest to 16964e9 2023-03-10 19:28:32 +00:00
GitHub Actions 09a36aa4c6 chore(android): refresh baseline profile 2023-03-10 01:29:02 +00:00
Harsh Shandilya c1f1d67bfa feat(android): add a repository for extracting CSRF token 2023-03-10 01:29:04 +05:30
renovate[bot]andGitHub 93d2397572 chore(deps): update actions/cache action to v3.3.0 2023-03-09 14:07:15 +00:00
renovate[bot]andGitHub 4b89dc202e fix(deps): update dependency androidx.profileinstaller:profileinstaller to v1.3.0-rc01 2023-03-09 08:02:47 +00:00
renovate[bot]andGitHub 0718e18fb0 fix(deps): update dependency androidx.navigation:navigation-compose to v2.6.0-alpha07 2023-03-09 04:31:28 +00:00
renovate[bot]andGitHub 90483889c4 fix(deps): update dependency androidx.lifecycle:lifecycle-viewmodel-compose to v2.6.0 2023-03-09 01:50:37 +00:00
GitHub Actions b7ef4cb2d6 chore(android): refresh baseline profile 2023-03-09 01:23:10 +00:00
renovate[bot]andGitHub b73261a339 fix(deps): update dependency androidx.benchmark:benchmark-macro-junit4 to v1.2.0-alpha11 2023-03-08 22:06:44 +00:00
renovate[bot]andGitHub 0b4fd240cc fix(deps): update dependency androidx.activity:activity-compose to v1.7.0-rc01 2023-03-08 19:58:16 +00:00
Harsh Shandilya b1af5d2349 chore: fix OkHttp capitalisation in changelog 2023-03-09 01:09:39 +05:30
Harsh Shandilya 456205dece chore(deps): bump compose-lint-checks 2023-03-09 01:08:21 +05:30
GitHub Actions 8d092a761a chore(android): refresh baseline profile 2023-03-08 01:28:52 +00:00
Harsh Shandilya 05e9c25742 fix: update incorrect comment 2023-03-08 02:50:17 +05:30
Harsh Shandilya 998171af9e chore: update changelog 2023-03-08 02:43:11 +05:30
Harsh Shandilya 3c62dd9542 fix: address Lint warnings in icon resources 2023-03-08 02:27:51 +05:30
Harsh Shandilya 55cc397333 chore: add labels to Crossfade elements 2023-03-08 02:27:51 +05:30
Harsh Shandilya b969b5f0bf refactor: use immutable collections where flagged by Lint 2023-03-08 02:27:51 +05:30
Harsh Shandilya d7cc55ed53 chore(build): make Lint errors fatal 2023-03-08 02:27:51 +05:30
Harsh Shandilya 9ab8a3e149 fix(api): avoid unnecessary build warning 2023-03-08 02:27:51 +05:30
Harsh Shandilya 0ae48dee33 feat(build): remove Detekt and switch to Slack's Compose lints 2023-03-08 02:27:51 +05:30
Harsh ShandilyaandGitHub d612ed44d9 chore: update changelog 2023-03-07 13:00:52 +05:30
Harsh Shandilya cb798cf011 feat: upgrade to OkHttp 4.10.0 2023-03-07 12:53:51 +05:30
GitHub Actions 8392841554 chore(android): refresh baseline profile 2023-03-07 01:35:08 +00:00
Harsh Shandilya 24d4d3279a fix: remove unused version catalog key 2023-03-07 01:00:07 +05:30
Harsh Shandilya 84bdcb340b feat: add Play Store feature graphic 2023-03-06 10:51:16 +05:30
Harsh Shandilya e4a28684ef feat: refresh icon assets 2023-03-06 10:49:58 +05:30
GitHub Actions 0f5698bb58 chore(android): refresh baseline profile 2023-03-06 01:24:49 +00:00
GitHub Actions ca2da81af5 chore(android): refresh baseline profile 2023-03-05 22:05:24 +00:00
Harsh Shandilya a26fd0862f fix(build): skip Sentry setup for CI benchmarks 2023-03-06 03:17:49 +05:30
Harsh Shandilya ab905d4061 fix(build): set a default for sentryDsn 2023-03-06 02:45:26 +05:30
renovate[bot]andGitHub 7c27e26da7 chore(deps): update jetbrains/qodana-jvm-android docker tag to v2023 2023-03-04 09:56:19 +00:00
renovate[bot]andGitHub 7f49333c42 chore(deps): update dependency gradle to v8.0.2 2023-03-04 05:58:54 +00:00
GitHub Actions 50d2af7be4 feat(release): start next development iteration 2023-03-02 21:52:11 +00:00
235 changed files with 47272 additions and 40325 deletions
+3
View File
@@ -6,3 +6,6 @@ cbdfa67d075ec1f8ceec0f3559498cbca01783a0
# Renamed Renovate config file
f304304bc5b64edf189aaa473b05df912067a8bd
# Refactored database module into core and impl
7b0b206905b8dc1f824a2d2a10e3d94c6b9dd11c
+1
View File
@@ -2,3 +2,4 @@
**/dependencies/** linguist-generated
**/clawicons/** linguist-generated
android/src/main/baseline-prof.txt linguist-generated -diff
android/src/main/generated/** linguist-generated -diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

+22 -47
View File
@@ -1,4 +1,5 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base",
":dependencyDashboard",
@@ -15,15 +16,25 @@
"https://maven.google.com/",
"https://repo1.maven.org/maven2",
"https://plugins.gradle.org/m2/",
"https://jitpack.io",
],
},
{
"matchPackagePatterns": [
"^kotlin",
"^org.jetbrains.kotlin",
"^androidx.compose.compiler"
"matchPackageNames": [
"androidx.compose.compiler:compiler",
"dev.drewhamilton.poko",
"org.jetbrains.kotlin:kotlin-gradle-plugin",
"org.jetbrains.kotlin.plugin.serialization",
],
"groupName": "kotlin"
"groupName": "Kotlin and Compose",
},
{
"matchPackagePatterns": [
"^androidx.*",
],
"matchPackageNames": [
],
"groupName": "androidx"
},
{
"matchPackagePatterns": [
@@ -33,16 +44,12 @@
"groupName": "sentry"
},
{
"managers": [
"gradle"
"matchPackageNames": [
"com.android.tools:r8",
"com.squareup.anvil",
"dev.chrisbanes.compose:compose-bom",
],
"packagePatterns": [
// 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
"enabled": false,
},
],
"regexManagers": [
@@ -57,17 +64,6 @@
"depNameTemplate": "com.facebook:ktfmt",
"registryUrlTemplate": "https://repo1.maven.org/maven2/",
},
{
"fileMatch": [
"Detekt\.kt$"
],
"matchStrings": [
"COMPOSE_RULES_VERSION = \"(?<currentValue>.*)\""
],
"datasourceTemplate": "maven",
"depNameTemplate": "io.nlopez.compose.rules:detekt",
"registryUrlTemplate": "https://repo1.maven.org/maven2/",
},
{
"fileMatch": [
"gradle/libs.versions.toml"
@@ -79,26 +75,5 @@
"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",
},
{
"fileMatch": [
"gradle/libs.versions.toml"
],
"matchStrings": [
"sentry-sdk = \"(?<currentValue>.*)\""
],
"datasourceTemplate": "maven",
"depNameTemplate": "io.sentry:sentry-android",
"registryUrlTemplate": "https://repo1.maven.org/maven2/",
}
]
],
}
-126
View File
@@ -1,126 +0,0 @@
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@3f07048e3d294f56e9b90ac5ea2c6f74e9ad0f98 # v3.10.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@6095a76664413da4c8c134ee32e8a8ae900f0f1f # v2.4.0
with:
gradle-home-cache-cleanup: true
# Restore AVD from cache
- name: Cache AVD
uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0 # v3.2.6
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
env:
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
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
+30 -18
View File
@@ -18,45 +18,57 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Set up JDK
uses: actions/setup-java@3f07048e3d294f56e9b90ac5ea2c6f74e9ad0f98 # v3.10.0
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
with:
distribution: temurin
java-version: 18
- name: Run unit tests
uses: gradle/gradle-build-action@6095a76664413da4c8c134ee32e8a8ae900f0f1f # v2.4.0
uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # v2.9.0
with:
arguments: --no-configuration-cache --stacktrace check
gradle-home-cache-cleanup: true
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
- name: Run Detekt
uses: gradle/gradle-build-action@6095a76664413da4c8c134ee32e8a8ae900f0f1f # v2.4.0
with:
arguments: --no-configuration-cache --stacktrace detektMain
arguments: --no-configuration-cache --stacktrace check -PslimTests
gradle-home-cache-cleanup: true
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
dependency-graph: generate-and-submit
- name: (Fail-only) Upload test report
if: failure()
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: Test report
path: android/build/reports
dependency-review:
runs-on: ubuntu-latest
needs:
- check
steps:
- name: Checkout repository
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Dependency Review
uses: actions/dependency-review-action@6c5ccdad469c9f8a2996bfecaec55a631a347034 # v3
with:
base-ref: refs/heads/main
head-ref: ${{ github.ref }}
deploy-release-snapshot:
runs-on: ubuntu-latest
if: "github.event_name == 'push' && github.event.ref == 'refs/heads/main'"
needs: [ "check" ]
needs:
- check
- dependency-review
steps:
- name: Checkout repository
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Set up JDK
uses: actions/setup-java@3f07048e3d294f56e9b90ac5ea2c6f74e9ad0f98 # v3.10.0
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
with:
distribution: temurin
java-version: 18
@@ -64,12 +76,12 @@ jobs:
- name: Decrypt secrets
run: |
./scripts/setup-age.sh
./scripts/signing-setup.sh "$ENCRYPT_KEY"
./scripts/signing-setup.sh "$AGE_SECRET_KEY"
env:
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
AGE_SECRET_KEY: ${{ secrets.AGE_SECRET_KEY }}
- name: Build release app
uses: gradle/gradle-build-action@6095a76664413da4c8c134ee32e8a8ae900f0f1f # v2.4.0
uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # v2.9.0
env:
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
with:
+33 -6
View File
@@ -1,7 +1,15 @@
name: "CodeQL"
name: CodeQL
on:
push:
branches:
- renovate/**
workflow_dispatch:
schedule:
- cron: '31 7 * * 3'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
analyze:
@@ -13,14 +21,33 @@ jobs:
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Set up JDK
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
with:
distribution: temurin
java-version: 18
- name: Setup Gradle caching
uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # v2.9.0
with:
gradle-home-cache-cleanup: true
cache-read-only: true
- name: Initialize CodeQL
uses: github/codeql-action/init@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2
uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
with:
languages: java
- name: Autobuild
uses: github/codeql-action/autobuild@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2
tools: latest
queries: +security-extended
- name: Build project
shell: bash
run: |
./gradlew assembleDebug assembleRelease
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@32dc499307d133bb5085bae78498c0ac2cf762d5 # v2
uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
with:
category: "/language:java"
-16
View File
@@ -1,16 +0,0 @@
name: Qodana
on:
workflow_dispatch:
jobs:
qodana:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3
with:
fetch-depth: 0
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@7afb26c0c2f325c0d5c21ea1f617c79c7f899337 # v2022.3.4
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
+17 -7
View File
@@ -1,19 +1,28 @@
name: Release to Google Play
on:
workflow_dispatch:
inputs:
inAppUpdatePriority:
description: 'In app update priority (0-5)'
type: number
default: "0"
required: false
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
publish-google-play-release:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
token: ${{ secrets.POST_RELEASE_GH_TOKEN }}
fetch-depth: 0
- name: Set up JDK
uses: actions/setup-java@3f07048e3d294f56e9b90ac5ea2c6f74e9ad0f98 # v3.10.0
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
with:
distribution: temurin
java-version: 18
@@ -25,7 +34,7 @@ jobs:
git config user.email noreply@github.com
- name: Setup Gradle caching
uses: gradle/gradle-build-action@6095a76664413da4c8c134ee32e8a8ae900f0f1f # v2.4.0
uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # v2.9.0
with:
gradle-home-cache-cleanup: true
cache-read-only: true
@@ -33,9 +42,9 @@ jobs:
- name: Decrypt secrets
run: |
./scripts/setup-age.sh
./scripts/signing-setup.sh "$ENCRYPT_KEY"
./scripts/signing-setup.sh "$AGE_SECRET_KEY"
env:
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
AGE_SECRET_KEY: ${{ secrets.AGE_SECRET_KEY }}
- name: Get current version
shell: bash
@@ -45,7 +54,7 @@ jobs:
echo VERSION="${VERSION}" >> $GITHUB_ENV
- name: Update changelog
uses: msfjarvis/keep-a-changelog-new-release@ce8769801992253adb0209055c236a0cd192500b # 2.0.0
uses: msfjarvis/keep-a-changelog-new-release@bf43ae42f4e42f137572950af426efcf6e777207 # 2.1.0
with:
tag: v${{ env.VERSION }}
version: ${{ env.VERSION }}
@@ -83,7 +92,7 @@ jobs:
printf '%s' "${CHANGELOG}" >> distribution/whatsnew/whatsnew-en-GB
- name: Publish bundle to Google Play
uses: r0adkll/upload-google-play@70c7397e868b00eccd390222f492ab3e30520d09 # v1.1.1
uses: r0adkll/upload-google-play@9cf8fd30c9e616ec761db3b9abb2b0f15842ce58 # v1.1.2
with:
mappingFile: android/bundle/mapping.txt
packageName: dev.msfjarvis.claw.android
@@ -92,6 +101,7 @@ jobs:
status: completed
track: production
whatsNewDirectory: distribution/whatsnew
inAppUpdatePriority: ${{ inputs.inAppUpdatePriority }}
- name: Post-release work
shell: bash
+2
View File
@@ -245,3 +245,5 @@ hs_err_pid*
keystore.properties
distribution/
screenshots/
claw-export.json
+1
View File
@@ -1,2 +1,3 @@
*.json
baseline-prof.txt
**/test/resources/**
+168 -1
View File
@@ -7,6 +7,145 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [1.37.0] - 2023-10-06
### Changed
* Fixed a crash that infrequently happened in the comments page
* Fixed a crash when trying to list saved posts
* Fixed a crash in home screen widget when user had less than 50 saved posts
* Upgraded to Compose 1.6.0-alpha07
## [1.36.0] - 2023-10-04
### Added
* Introduce an initial attempt at a home screen widget
### Changed
* Fixed a crash triggered when swiping items
* Adjusted pull to refresh component to match Material You theme
## [1.35.0] - 2023-09-19
### Changed
* Fixed missing vertical spacing between post tags
* Fixed user profile links not displaying correctly in-app
* Update to Compose October release
## [1.34.0] - 2023-08-30
### Added
* Add a swipe action on each story to open the comments page on `lobste.rs`
* Automatically mark posts as "read" and visually distinguish between them
### Changed
* Tweak list items to reduce vertical size and adjust colors
* Drop bogus workarounds for native library crashes
* Updated Jetpack Compose and SQLite
### Fixed
* Rework how comments are displayed to adapt to lobste.rs API change
## [1.33.0] - 2023-07-31
### Changed
* Yet another attempt at fixing native library crashes
* Rework how baseline profiles are generated
## [1.32.0] - 2023-07-27
### Changed
* Upgrade to AndroidX July 26 release
* Revert selectable text feature due to sporadic crashes
## [1.31.0] - 2023-07-25
### Added
* Added the ability to search for posts
* Text in the comments page is now selectable
### Changed
* Upgrade to Compose July release
* Upgrade to Kotlin 1.9.0
## [1.30.0] - 2023-07-02
### Changed
* Added another workaround for native library loading crash
## [1.29.0] - 2023-06-08
### Added
* Backup and restore options for saved posts
### Fixed
* Spamming the comments button no longer causes it to be opened multiple times
* Saved posts screen now has a visual indication when you have nothing saved
* Iconography has been updated across the board to be more consistent
## [1.28.0] - 2023-06-03
### Changed
* Navigation transitions have been slightly sped up
### Fixed
* Add workaround for a native library loading crash observed on some devices
## [1.27.0] - 2023-05-31
### Changed
* Small accessibility improvements
* Slightly tweak the layout for story items to take less vertical space
* Upgrade to Compose `1.5.0-beta01` release
* Set accessibility web URI for profile screen
* Directly use Material Icons from upstream artifacts
* Upgrade dependencies
* Add adaptive navigation support (thanks @Yash-Garg)
* Use latest SQLite for backing databases
## [1.26.0] - 2023-05-03
### Changed
* Upgrade to Compose May release
* Disable Sentry performance reporting
* Migrate to Compose Foundation `FlowRow` in `LobstersCard`
## [1.25.0] - 2023-04-18
### Changed
* Make the app draw edge to edge
* Simplify Top App Bar color scheme
* Rework how baseline profiles are generated
* Upgrade to Compose April release
## [1.24.0] - 2023-03-24
### Changed
* Rebuild app icon assets to align better with Material guidelines
* Adopt Slack's Compose lints and address issues found by it
* Upgrade to OkHttp 4.x
* Upgrade to Compose March release
* Start work on support for logging in with lobste.rs
## [1.23.0] - 2023-03-02
### Added
@@ -182,7 +321,35 @@ 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/v1.23.0...HEAD
[Unreleased]: https://github.com/msfjarvis/compose-lobsters/compare/v1.37.0...HEAD
[1.37.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.36.0...v1.37.0
[1.36.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.35.0...v1.36.0
[1.35.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.34.0...v1.35.0
[1.34.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.33.0...v1.34.0
[1.33.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.32.0...v1.33.0
[1.32.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.31.0...v1.32.0
[1.31.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.30.0...v1.31.0
[1.30.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.29.0...v1.30.0
[1.29.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.28.0...v1.29.0
[1.28.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.27.0...v1.28.0
[1.27.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.26.0...v1.27.0
[1.26.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.25.0...v1.26.0
[1.25.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.24.0...v1.25.0
[1.24.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.23.0...v1.24.0
[1.23.0]: https://github.com/msfjarvis/compose-lobsters/compare/v1.22.0...v1.23.0
+32 -4
View File
@@ -8,12 +8,40 @@ Unofficial Android app for read-only access to [lobste.rs](https://lobste.rs), b
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).
Snapshots from the development branch can be obtained [here](https://github.com/msfjarvis/compose-lobsters/releases/tag/nightly).
<img src="https://github.com/msfjarvis/compose-lobsters/blob/main/.github/readme_feature_light.webp#gh-light-mode-only"
alt="A grid of screenshots from the app, in clockwise order: the main screen, the comments page, the search page and the saved posts page"
width="550" />
<img src="https://github.com/msfjarvis/compose-lobsters/blob/main/.github/readme_feature_dark.webp#gh-dark-mode-only"
alt="A grid of screenshots from the app, in clockwise order: the main screen, the comments page, the search page and the saved posts page"
width="550" />
## Module dependency graph
```mermaid
%%{
init: {
'theme': 'dark'
}
}%%
graph TB
model --> database
benchmark --> android
android --> api
android --> common
android --> core
android --> database
android --> model
android --> benchmark
api --> model
common --> core
common --> database
common --> model
```
## License
See [LICENSE](LICENSE)
-1
View File
@@ -1 +0,0 @@
-dontobfuscate
+65 -31
View File
@@ -4,7 +4,9 @@
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
@file:Suppress("DSL_SCOPE_VIOLATION", "UnstableApiUsage")
@file:Suppress("UnstableApiUsage")
import dev.msfjarvis.claw.gradle.addTestDependencies
plugins {
id("dev.msfjarvis.claw.android-application")
@@ -14,7 +16,45 @@ plugins {
id("dev.msfjarvis.claw.sentry")
id("dev.msfjarvis.claw.versioning-plugin")
alias(libs.plugins.anvil)
alias(libs.plugins.modulegraphassert)
alias(libs.plugins.whetstone)
alias(libs.plugins.baselineprofile)
alias(libs.plugins.licensee)
alias(libs.plugins.tracelog)
}
android {
namespace = "dev.msfjarvis.claw.android"
defaultConfig.applicationId = "dev.msfjarvis.claw.android"
buildFeatures.compose = true
composeOptions {
useLiveLiterals = false
kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get()
}
// kotlinx.serialization 1.6.0-RC regression
packagingOptions.resources.pickFirsts += "**/*.bin"
}
baselineProfile {
mergeIntoMain = true
saveInSrc = true
from(projects.benchmark.dependencyProject)
}
licensee {
allow("Apache-2.0")
allow("MIT")
ignoreDependencies("org.commonmark") { because("Commonmark is BSD licensed") }
allowUrl("https://jsoup.org/license") { because("Jsoup is MIT licensed") }
allowUrl("https://opensource.org/licenses/isc-license.txt") {
because("kotlin-result is ISC licensed")
}
}
moduleGraphAssert {
assertOnAnyBuild = true
maxHeight = 4
restricted = arrayOf(":core -X> :.*")
}
whetstone {
@@ -24,47 +64,41 @@ whetstone {
}
}
android {
namespace = "dev.msfjarvis.claw.android"
defaultConfig { applicationId = "dev.msfjarvis.claw.android" }
buildFeatures { compose = true }
composeOptions {
useLiveLiterals = false
kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get()
}
buildTypes {
create("benchmark") {
signingConfig = signingConfigs["debug"]
matchingFallbacks += "release"
isDebuggable = false
proguardFile("benchmark-rules.pro")
}
}
}
dependencies {
kapt(libs.dagger.compiler)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.dagger)
implementation(projects.api)
implementation(projects.common)
implementation(projects.core)
implementation(projects.coroutineUtils)
implementation(projects.database)
implementation(projects.metadataExtractor)
implementation(projects.model)
implementation(libs.accompanist.sysuicontroller)
implementation(platform(libs.okhttp.bom))
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.compose.material)
implementation(libs.androidx.compose.glance)
implementation(libs.androidx.compose.glance.m3)
implementation(libs.androidx.compose.material.icons.extended)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.material3.window.size)
implementation(libs.androidx.core.splashscreen)
implementation(libs.androidx.lifecycle.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.paging.compose)
implementation(libs.androidx.profileinstaller)
implementation(libs.androidx.work.runtime.ktx)
implementation(libs.androidx.work.runtime)
implementation(libs.coil)
implementation(libs.copydown)
implementation(libs.dagger)
implementation(libs.jsoup)
implementation(libs.kotlinx.collections.immutable)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.material3.pulltorefresh)
implementation(libs.napier)
implementation(libs.sqldelight.extensions.coroutines)
implementation(libs.swipe)
implementation(libs.unfurl)
implementation(projects.api)
implementation(projects.common)
implementation(projects.core)
implementation(projects.database.impl)
implementation(projects.model)
kapt(libs.dagger.compiler)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.okhttp.mockwebserver)
addTestDependencies(project)
}
+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 7.4.0-alpha09" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha09)" variant="all" version="7.4.0-alpha09">
<issues format="6" by="lint 8.3.0-alpha02" type="baseline" client="gradle" dependencies="true" name="AGP (8.3.0-alpha02)" variant="all" version="8.3.0-alpha02">
</issues>
Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

+7 -10
View File
@@ -1,22 +1,19 @@
-allowaccessmodification
-dontpreverify
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
-keepattributes *Annotation*
-keepclasseswithmembernames class * {
native <methods>;
native <methods>;
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * implements android.os.Parcelable {
public static final ** CREATOR;
public static final ** CREATOR;
}
-keep class androidx.annotation.Keep
@@ -24,13 +21,13 @@
-keep @androidx.annotation.Keep class * {*;}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <methods>;
@androidx.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <fields>;
@androidx.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <init>(...);
@androidx.annotation.Keep <init>(...);
}
+20
View File
@@ -1,2 +1,22 @@
-dontobfuscate
-keepattributes SourceFile, LineNumberTable
# From https://github.com/square/retrofit/blob/master/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro
# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
# Keep inherited services.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>
# With R8 full mode generic signatures are stripped for classes that are not
# kept. Suspend functions are wrapped in continuations where the type argument
# is used.
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
# R8 full mode strips generic signatures from return types if not kept.
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>
+6 -1
View File
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
~ 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.
-->
<resources>
<string name="app_name">Claw β</string>
</resources>
+25 -15
View File
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
~ 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
@@ -6,13 +11,13 @@
<application
android:name=".ClawApplication"
android:dataExtractionRules="@xml/data_extraction_rules"
android:enableOnBackInvokedCallback="true"
android:fullBackupContent="@xml/full_backup_content"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/Theme.Claw.SplashScreen"
android:enableOnBackInvokedCallback="true"
tools:targetApi="tiramisu">
<profileable
android:shell="true"
@@ -25,19 +30,6 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:ssp="//lobste.rs" />
<data android:host="lobste.rs" />
<data android:path="/" />
<data android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -163,5 +155,23 @@
<action android:name="androidx.profileinstaller.action.BENCHMARK_OPERATION" />
</intent-filter>
</receiver>
<receiver android:name=".glance.WidgetReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/saved_posts_widget_info" />
</receiver>
<!-- Required: set your sentry.io project identifier (DSN) -->
<meta-data android:name="io.sentry.dsn" android:value="${sentryDsn}" />
<!-- enable automatic breadcrumbs for user interactions (clicks, swipes, scrolls) -->
<meta-data android:name="io.sentry.traces.user-interaction.enable" android:value="${enableSentry}" />
<meta-data android:name="io.sentry.breadcrumbs.user-interaction" android:value="${enableSentry}" />
<!-- enable screenshot for crashes -->
<meta-data android:name="io.sentry.attach-screenshot" android:value="${enableSentry}" />
<!-- enable view hierarchy for crashes -->
<meta-data android:name="io.sentry.attach-view-hierarchy" android:value="${enableSentry}" />
</application>
</manifest>
-35819
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -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.
@@ -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,11 +11,16 @@ import android.net.Uri
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.ui.platform.LocalUriHandler
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import com.deliveryhero.whetstone.Whetstone
import com.deliveryhero.whetstone.activity.ContributesActivityInjector
import dev.msfjarvis.claw.android.ui.LobstersApp
import dev.msfjarvis.claw.common.comments.HTMLConverter
import dev.msfjarvis.claw.common.theme.LobstersTheme
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
import javax.inject.Inject
@@ -26,16 +31,25 @@ class MainActivity : ComponentActivity() {
@Inject lateinit var htmlConverter: HTMLConverter
private var webUri: String? = null
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
installSplashScreen()
Whetstone.inject(this)
enableEdgeToEdge()
setContent {
LobstersApp(
urlLauncher = urlLauncher,
htmlConverter = htmlConverter,
setWebUri = { url -> webUri = url },
)
val windowSizeClass = calculateWindowSizeClass(this)
LobstersTheme(
dynamicColor = true,
providedValues = arrayOf(LocalUriHandler provides urlLauncher),
) {
LobstersApp(
urlLauncher = urlLauncher,
htmlConverter = htmlConverter,
windowSizeClass = windowSizeClass,
setWebUri = { url -> webUri = url },
)
}
}
}
@@ -49,4 +63,8 @@ class MainActivity : ComponentActivity() {
}
}
}
companion object {
const val NAVIGATION_KEY = "postId"
}
}
@@ -0,0 +1,73 @@
/*
* 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.android.glance
import android.content.Context
import android.os.Build
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import androidx.glance.GlanceId
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.appWidgetBackground
import androidx.glance.appwidget.lazy.LazyColumn
import androidx.glance.appwidget.lazy.items
import androidx.glance.appwidget.provideContent
import androidx.glance.background
import androidx.glance.layout.Alignment
import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.padding
import androidx.glance.material3.ColorProviders
import androidx.glance.text.Text
import androidx.glance.text.TextStyle
import dev.msfjarvis.claw.common.theme.DarkThemeColors
import dev.msfjarvis.claw.common.theme.LightThemeColors
import dev.msfjarvis.claw.database.local.SavedPost
class SavedPostsWidget(
private val posts: List<SavedPost>,
) : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent {
GlanceTheme(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) GlanceTheme.colors
else ColorProviders(light = LightThemeColors, dark = DarkThemeColors)
) {
WidgetHost()
}
}
}
@Composable
private fun WidgetHost() {
LazyColumn(
modifier =
GlanceModifier.fillMaxSize()
.background(GlanceTheme.colors.background)
.appWidgetBackground(),
horizontalAlignment = Alignment.CenterHorizontally
) {
item {
val style = MaterialTheme.typography.titleLarge
Text(
text = "Saved posts",
style =
TextStyle(
color = GlanceTheme.colors.onBackground,
fontSize = style.fontSize,
fontWeight = style.fontWeight.toGlance(),
fontStyle = style.fontStyle.toGlance(),
),
modifier = GlanceModifier.padding(vertical = 8.dp),
)
}
items(posts) { post -> WidgetListEntry(post = post) }
}
}
}
@@ -0,0 +1,89 @@
/*
* 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.android.glance
import android.content.Intent
import android.net.Uri
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import androidx.glance.GlanceComposable
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.action.ActionParameters.Key
import androidx.glance.action.actionParametersOf
import androidx.glance.action.actionStartActivity
import androidx.glance.action.clickable
import androidx.glance.appwidget.action.actionStartActivity
import androidx.glance.appwidget.cornerRadius
import androidx.glance.background
import androidx.glance.layout.Alignment
import androidx.glance.layout.Box
import androidx.glance.layout.Row
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
import androidx.glance.layout.wrapContentWidth
import androidx.glance.text.Text
import androidx.glance.text.TextAlign
import androidx.glance.text.TextStyle
import dev.msfjarvis.claw.android.MainActivity
import dev.msfjarvis.claw.android.MainActivity.Companion.NAVIGATION_KEY
import dev.msfjarvis.claw.database.local.SavedPost
private val destinationKey = Key<String>(NAVIGATION_KEY)
@Composable
@GlanceComposable
fun WidgetListEntry(
post: SavedPost,
modifier: GlanceModifier = GlanceModifier,
) {
val titleStyle = MaterialTheme.typography.titleMedium
val subtitleStyle = MaterialTheme.typography.labelLarge
val commentsAction =
actionStartActivity<MainActivity>(actionParametersOf(destinationKey to post.shortId))
val postAction =
if (post.url.isNotEmpty()) actionStartActivity(Intent(Intent.ACTION_VIEW, Uri.parse(post.url)))
else commentsAction
Box(modifier.padding(8.dp)) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier =
GlanceModifier.fillMaxWidth()
.background(GlanceTheme.colors.surfaceVariant)
.cornerRadius(16.dp)
.padding(8.dp),
) {
Text(
text = post.title,
modifier = GlanceModifier.defaultWeight().padding(start = 4.dp).clickable(postAction),
style =
TextStyle(
color = GlanceTheme.colors.onSurfaceVariant,
fontSize = titleStyle.fontSize,
fontWeight = titleStyle.fontWeight.toGlance(),
fontStyle = titleStyle.fontStyle.toGlance(),
)
)
post.commentCount?.let { count ->
Text(
text = "$count comments",
modifier =
GlanceModifier.wrapContentWidth().padding(end = 4.dp).clickable(commentsAction),
style =
TextStyle(
color = GlanceTheme.colors.onSurfaceVariant,
fontSize = subtitleStyle.fontSize,
fontWeight = subtitleStyle.fontWeight.toGlance(),
fontStyle = subtitleStyle.fontStyle.toGlance(),
textAlign = TextAlign.End,
)
)
}
}
}
}
@@ -0,0 +1,32 @@
/*
* 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.android.glance
import android.content.Context
import android.content.Intent
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
import com.deliveryhero.whetstone.Whetstone
import com.deliveryhero.whetstone.broadcastreceiver.ContributesBroadcastReceiverInjector
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
@ContributesBroadcastReceiverInjector
class WidgetReceiver : GlanceAppWidgetReceiver() {
@Inject lateinit var viewModel: ClawViewModel
override val glanceAppWidget: GlanceAppWidget
get() = SavedPostsWidget(runBlocking { viewModel.savedPosts.first().take(50) })
override fun onReceive(context: Context, intent: Intent) {
Whetstone.inject(this, context)
super.onReceive(context, intent)
}
}
@@ -0,0 +1,27 @@
/*
* 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.android.glance
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
fun FontWeight?.toGlance(): androidx.glance.text.FontWeight? {
return when (this) {
FontWeight.Normal -> androidx.glance.text.FontWeight.Normal
FontWeight.Medium -> androidx.glance.text.FontWeight.Medium
FontWeight.Bold -> androidx.glance.text.FontWeight.Bold
else -> null
}
}
fun FontStyle?.toGlance(): androidx.glance.text.FontStyle? {
return when (this) {
FontStyle.Normal -> androidx.glance.text.FontStyle.Normal
FontStyle.Italic -> androidx.glance.text.FontStyle.Italic
else -> null
}
}
@@ -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.
@@ -16,5 +16,5 @@ import dev.msfjarvis.claw.common.comments.HTMLConverter
@Module
@ContributesTo(ApplicationScope::class)
interface HTMLConverterModule {
@Binds fun HTMLConverterImpl.bind(): HTMLConverter
@Binds fun bindHTMLConverter(impl: HTMLConverterImpl): HTMLConverter
}
@@ -1,25 +1,44 @@
/*
* 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.android.injection
import com.chimbori.crux.Crux
import com.deliveryhero.whetstone.app.ApplicationScope
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.github.aakira.napier.Napier
import me.saket.unfurl.UnfurlLogger
import me.saket.unfurl.Unfurler
import okhttp3.OkHttpClient
@Module
@ContributesTo(ApplicationScope::class)
object MetadataExtractorModule {
@Provides
fun provideCrux(
fun provideUnfurlLogger(): UnfurlLogger {
return object : UnfurlLogger {
override fun log(message: String) {
Napier.d { message }
}
override fun log(e: Throwable, message: String) {
Napier.e(e) { message }
}
}
}
@Provides
fun provideUnfurler(
okHttpClient: OkHttpClient,
): Crux {
return Crux(okHttpClient = okHttpClient)
logger: UnfurlLogger,
): Unfurler {
return Unfurler(
httpClient = okHttpClient,
logger = logger,
)
}
}
@@ -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.
@@ -7,9 +7,9 @@
package dev.msfjarvis.claw.android.injection
import android.content.Context
import com.deliveryhero.whetstone.ForScope
import com.deliveryhero.whetstone.activity.ActivityScope
import com.squareup.anvil.annotations.ContributesTo
import com.squareup.anvil.annotations.optional.ForScope
import dagger.Module
import dagger.Provides
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
@@ -1,15 +0,0 @@
/*
* 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 javax.inject.Qualifier
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DatabaseDispatcher
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class MainDispatcher
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class IODispatcher
@@ -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.
@@ -13,7 +13,7 @@ import com.slack.eithernet.ApiResult.Success
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dev.msfjarvis.claw.android.injection.IODispatcher
import dev.msfjarvis.claw.core.injection.IODispatcher
import dev.msfjarvis.claw.model.LobstersPost
import java.io.IOException
import kotlinx.coroutines.CoroutineDispatcher
@@ -0,0 +1,67 @@
/*
* 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.android.paging
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.slack.eithernet.ApiResult
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
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.core.injection.IODispatcher
import dev.msfjarvis.claw.model.LobstersPost
import java.io.IOException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
/**
* Duplicate of [LobstersPagingSource] with an additional optimization to not continue loading
* further pages if nothing is found in the current one. This is required to prevent the app from
* hammering the search endpoint with up to 70 consecutive requests for the search results of a
* blank query.
*/
class SearchPagingSource
@AssistedInject
constructor(
@Assisted private val remoteFetcher: RemoteFetcher<LobstersPost>,
@IODispatcher private val ioDispatcher: CoroutineDispatcher,
) : PagingSource<Int, LobstersPost>() {
override fun getRefreshKey(state: PagingState<Int, LobstersPost>): Int? {
return state.anchorPosition?.let { anchorPosition ->
(anchorPosition / PAGE_SIZE).coerceAtLeast(STARTING_PAGE_INDEX)
}
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LobstersPost> {
val page = params.key ?: STARTING_PAGE_INDEX
return when (val result = withContext(ioDispatcher) { remoteFetcher.getItemsAtPage(page) }) {
is ApiResult.Success -> {
// Optimization: prevent fetching more pages if we found no items, this means
// there is no active search query.
val nextKey = if (result.value.isEmpty()) null else page + 1
LoadResult.Page(
itemsBefore = (page - 1) * PAGE_SIZE,
data = result.value,
prevKey = if (page == STARTING_PAGE_INDEX) null else page - 1,
nextKey = nextKey,
)
}
is ApiResult.Failure.NetworkFailure -> LoadResult.Error(result.error)
is ApiResult.Failure.UnknownFailure -> LoadResult.Error(result.error)
is ApiResult.Failure.HttpFailure,
is ApiResult.Failure.ApiFailure ->
LoadResult.Error(IOException("API returned an invalid response"))
}
}
@AssistedFactory
interface Factory {
fun create(remoteFetcher: RemoteFetcher<LobstersPost>): SearchPagingSource
}
}
@@ -6,25 +6,40 @@
*/
package dev.msfjarvis.claw.android.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.ImportExport
import androidx.compose.material.icons.filled.NewReleases
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Whatshot
import androidx.compose.material.icons.outlined.FavoriteBorder
import androidx.compose.material.icons.outlined.NewReleases
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material.icons.outlined.Whatshot
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
@@ -38,43 +53,45 @@ import androidx.navigation.navArgument
import androidx.navigation.navDeepLink
import androidx.paging.compose.collectAsLazyPagingItems
import com.deliveryhero.whetstone.compose.injectedViewModel
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import dev.msfjarvis.claw.android.MainActivity
import dev.msfjarvis.claw.android.R
import dev.msfjarvis.claw.android.ui.datatransfer.DataTransferScreen
import dev.msfjarvis.claw.android.ui.decorations.ClawAppBar
import dev.msfjarvis.claw.android.ui.decorations.ClawNavigationBar
import dev.msfjarvis.claw.android.ui.decorations.ClawNavigationRail
import dev.msfjarvis.claw.android.ui.decorations.NavigationItem
import dev.msfjarvis.claw.android.ui.lists.DatabasePosts
import dev.msfjarvis.claw.android.ui.lists.NetworkPosts
import dev.msfjarvis.claw.android.ui.lists.SearchList
import dev.msfjarvis.claw.android.ui.navigation.ClawNavigationType
import dev.msfjarvis.claw.android.ui.navigation.Destinations
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.common.comments.CommentsPage
import dev.msfjarvis.claw.common.comments.HTMLConverter
import dev.msfjarvis.claw.common.res.ClawIcons
import dev.msfjarvis.claw.common.theme.LobstersTheme
import dev.msfjarvis.claw.common.ui.decorations.ClawAppBar
import dev.msfjarvis.claw.common.ui.surfaceColorAtNavigationBarElevation
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
import dev.msfjarvis.claw.common.user.UserProfile
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.coroutines.launch
@OptIn(
ExperimentalComposeUiApi::class,
ExperimentalMaterial3Api::class,
)
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun LobstersApp(
urlLauncher: UrlLauncher,
htmlConverter: HTMLConverter,
windowSizeClass: WindowSizeClass,
setWebUri: (String?) -> Unit,
modifier: Modifier = Modifier,
viewModel: ClawViewModel = injectedViewModel(),
) {
val systemUiController = rememberSystemUiController()
val hottestListState = rememberLazyListState()
val newestListState = rememberLazyListState()
val savedListState = rememberLazyListState()
val searchListState = rememberLazyListState()
val navController = rememberNavController()
val coroutineScope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
val postActions = rememberPostActions(urlLauncher, navController, viewModel)
val backStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = backStackEntry?.destination?.route
@@ -82,67 +99,69 @@ fun LobstersApp(
val hottestPosts = viewModel.hottestPosts.collectAsLazyPagingItems()
val newestPosts = viewModel.newestPosts.collectAsLazyPagingItems()
val savedPosts by viewModel.savedPosts.collectAsState(emptyMap())
val savedPosts by viewModel.savedPostsByMonth.collectAsState(persistentMapOf())
LobstersTheme(
dynamicColor = true,
providedValues = arrayOf(LocalUriHandler provides urlLauncher),
) {
val currentUiMode = LocalConfiguration.current.uiMode
val systemBarsColor = MaterialTheme.colorScheme.surfaceColorAtNavigationBarElevation()
val backgroundColor = MaterialTheme.colorScheme.background
val navItems =
listOf(
NavigationItem(
label = "Hottest",
route = Destinations.Hottest.route,
icon = ClawIcons.Flame,
selectedIcon = ClawIcons.FlameFilled,
) {
coroutineScope.launch { hottestListState.animateScrollToItem(index = 0) }
},
NavigationItem(
label = "Newest",
route = Destinations.Newest.route,
icon = ClawIcons.New,
selectedIcon = ClawIcons.NewFilled,
) {
coroutineScope.launch { newestListState.animateScrollToItem(index = 0) }
},
NavigationItem(
label = "Saved",
route = Destinations.Saved.route,
icon = ClawIcons.HeartBorder,
selectedIcon = ClawIcons.Heart,
) {
coroutineScope.launch { savedListState.animateScrollToItem(index = 0) }
},
val navigationType = ClawNavigationType.fromSize(windowSizeClass.widthSizeClass)
val postIdOverride = context.getActivity()?.intent?.extras?.getString(MainActivity.NAVIGATION_KEY)
LaunchedEffect(false) {
if (postIdOverride != null) {
navController.navigate(
Destinations.Comments.route.replace(Destinations.Comments.placeholder, postIdOverride)
)
SideEffect { systemUiController.setStatusBarColor(color = systemBarsColor) }
// Track UI mode as a key to force a navbar color update when dark theme is toggled
LaunchedEffect(currentDestination, currentUiMode) {
val color =
if (navItems.none { item -> item.route == currentDestination }) {
backgroundColor
} else {
systemBarsColor
}
systemUiController.setNavigationBarColor(color = color)
}
}
Scaffold(
topBar = {
val navItems =
persistentListOf(
NavigationItem(
label = "Hottest",
route = Destinations.Hottest.route,
icon = Icons.Outlined.Whatshot,
selectedIcon = Icons.Filled.Whatshot,
) {
coroutineScope.launch { hottestListState.animateScrollToItem(index = 0) }
},
NavigationItem(
label = "Newest",
route = Destinations.Newest.route,
icon = Icons.Outlined.NewReleases,
selectedIcon = Icons.Filled.NewReleases,
) {
coroutineScope.launch { newestListState.animateScrollToItem(index = 0) }
},
NavigationItem(
label = "Saved",
route = Destinations.Saved.route,
icon = Icons.Outlined.FavoriteBorder,
selectedIcon = Icons.Filled.Favorite,
) {
coroutineScope.launch { savedListState.animateScrollToItem(index = 0) }
},
NavigationItem(
label = "Search",
route = Destinations.Search.route,
icon = Icons.Outlined.Search,
selectedIcon = Icons.Filled.Search,
) {
coroutineScope.launch { searchListState.animateScrollToItem(index = 0) }
},
)
Scaffold(
topBar = {
if (currentDestination != Destinations.Search.route) {
ClawAppBar(
backgroundColor = systemBarsColor,
navigationIcon = {
if (navItems.none { it.route == currentDestination }) {
if (
navController.previousBackStackEntry != null &&
navItems.none { it.route == currentDestination }
) {
IconButton(
onClick = { if (!navController.popBackStack()) context.getActivity()?.finish() }
onClick = { if (!navController.popBackStack()) context.getActivity()?.finish() },
) {
Icon(
painter = ClawIcons.ArrowBack,
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Go back to previous screen",
)
}
@@ -153,48 +172,69 @@ fun LobstersApp(
Text(text = stringResource(R.string.app_name), fontWeight = FontWeight.Bold)
}
},
actions = {
if (navItems.any { it.route == currentDestination }) {
IconButton(onClick = { navController.navigate(Destinations.DataTransfer.route) }) {
Icon(
imageVector = Icons.Filled.ImportExport,
contentDescription = "Data transfer options",
)
}
}
},
)
},
bottomBar = {
}
},
bottomBar = {
AnimatedVisibility(visible = navigationType == ClawNavigationType.BOTTOM_NAVIGATION) {
ClawNavigationBar(
navController = navController,
items = navItems,
isVisible = navItems.any { it.route == currentDestination },
)
},
modifier = modifier.semantics { testTagsAsResourceId = true },
) { paddingValues ->
}
},
snackbarHost = { SnackbarHost(snackbarHostState) },
modifier = modifier.semantics { testTagsAsResourceId = true },
) { paddingValues ->
Row(modifier = Modifier.padding(paddingValues)) {
AnimatedVisibility(visible = navigationType == ClawNavigationType.NAVIGATION_RAIL) {
ClawNavigationRail(
navController = navController,
items = navItems,
isVisible = navItems.any { it.route == currentDestination },
)
}
NavHost(
navController = navController,
startDestination = Destinations.startDestination.route,
modifier = Modifier.padding(paddingValues),
// Make animations 2x faster than default specs
enterTransition = { fadeIn(animationSpec = tween(350)) },
exitTransition = { fadeOut(animationSpec = tween(350)) },
) {
val uri = LobstersApi.BASE_URL
composable(
route = Destinations.Hottest.route,
deepLinks =
listOf(navDeepLink { uriPattern = uri }, navDeepLink { uriPattern = "$uri/" }),
) {
composable(route = Destinations.Hottest.route) {
setWebUri("https://lobste.rs/")
NetworkPosts(
lazyPagingItems = hottestPosts,
listState = hottestListState,
isPostSaved = viewModel::isPostSaved,
isPostRead = viewModel::isPostRead,
postActions = postActions,
)
}
composable(
route = Destinations.Newest.route,
) {
composable(route = Destinations.Newest.route) {
setWebUri("https://lobste.rs/")
NetworkPosts(
lazyPagingItems = newestPosts,
listState = newestListState,
isPostSaved = viewModel::isPostSaved,
isPostRead = viewModel::isPostRead,
postActions = postActions,
)
}
composable(Destinations.Saved.route) {
composable(route = Destinations.Saved.route) {
setWebUri(null)
DatabasePosts(
items = savedPosts,
@@ -202,6 +242,17 @@ fun LobstersApp(
postActions = postActions,
)
}
composable(Destinations.Search.route) {
setWebUri("https://lobste.rs/search")
SearchList(
items = viewModel.searchResults,
listState = searchListState,
isPostSaved = viewModel::isPostSaved,
postActions = postActions,
searchQuery = viewModel.searchQuery,
setSearchQuery = { query -> viewModel.searchQuery = query },
)
}
composable(
route = Destinations.Comments.route,
arguments = listOf(navArgument("postId") { type = NavType.StringType }),
@@ -211,7 +262,10 @@ fun LobstersApp(
navDeepLink { uriPattern = "$uri/s/${Destinations.Comments.placeholder}" },
),
) { backStackEntry ->
val postId = requireNotNull(backStackEntry.arguments?.getString("postId"))
val postId =
requireNotNull(backStackEntry.arguments?.getString("postId")) {
"Navigating to ${Destinations.Comments.route} without necessary 'postId' argument"
}
setWebUri("https://lobste.rs/s/$postId")
CommentsPage(
postId = postId,
@@ -227,12 +281,24 @@ fun LobstersApp(
deepLinks =
listOf(navDeepLink { uriPattern = "$uri/u/${Destinations.User.placeholder}" }),
) { backStackEntry ->
val username = requireNotNull(backStackEntry.arguments?.getString("username"))
val username =
requireNotNull(backStackEntry.arguments?.getString("username")) {
"Navigating to ${Destinations.User.route} without necessary 'username' argument"
}
setWebUri("https://lobste.rs/u/$username")
UserProfile(
username = username,
getProfile = viewModel::getUserProfile,
)
}
composable(route = Destinations.DataTransfer.route) {
DataTransferScreen(
context = context,
importPosts = viewModel::importPosts,
exportPosts = viewModel::exportPosts,
snackbarHostState = snackbarHostState,
)
}
}
}
}
@@ -0,0 +1,138 @@
/*
* 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.android.ui.datatransfer
import android.content.Context
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
import androidx.activity.result.contract.ActivityResultContracts.GetContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Download
import androidx.compose.material.icons.filled.Upload
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
import java.io.InputStream
import java.io.OutputStream
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
private const val MIME_TYPE = "application/json"
@Composable
fun DataTransferScreen(
context: Context,
importPosts: suspend (InputStream) -> Unit,
exportPosts: suspend (OutputStream) -> Unit,
snackbarHostState: SnackbarHostState,
modifier: Modifier = Modifier,
) {
val coroutineScope = rememberCoroutineScope()
Column(modifier = modifier) {
ImportOption(context, coroutineScope, importPosts, snackbarHostState)
ExportOption(context, coroutineScope, exportPosts, snackbarHostState)
}
}
@Composable
private fun ImportOption(
context: Context,
coroutineScope: CoroutineScope,
importPosts: suspend (InputStream) -> Unit,
snackbarHostState: SnackbarHostState,
) {
val importAction =
rememberLauncherForActivityResult(GetContent()) { uri ->
if (uri == null) {
coroutineScope.launch { snackbarHostState.showSnackbarDismissing("No file selected") }
return@rememberLauncherForActivityResult
}
coroutineScope.launch {
context.contentResolver.openInputStream(uri)?.use { stream ->
importPosts(stream)
snackbarHostState.showSnackbarDismissing("Successfully imported posts")
}
}
}
SettingsActionItem(
title = "Import saved posts",
description = "Import saved posts from a previously generated export",
icon = Icons.Filled.Download,
) {
importAction.launch(MIME_TYPE)
}
}
@Composable
private fun ExportOption(
context: Context,
coroutineScope: CoroutineScope,
exportPosts: suspend (OutputStream) -> Unit,
snackbarHostState: SnackbarHostState,
) {
val exportAction =
rememberLauncherForActivityResult(CreateDocument(MIME_TYPE)) { uri ->
if (uri == null) {
coroutineScope.launch { snackbarHostState.showSnackbarDismissing("No file selected") }
return@rememberLauncherForActivityResult
}
coroutineScope.launch {
context.contentResolver.openOutputStream(uri)?.use { stream ->
exportPosts(stream)
snackbarHostState.showSnackbarDismissing("Successfully exported posts")
}
}
}
SettingsActionItem(
title = "Export posts to file",
description = "Write all saved posts into a JSON file that can be imported at a later date",
icon = Icons.Filled.Upload,
) {
exportAction.launch("claw-export.json")
}
}
@Composable
private fun SettingsActionItem(
title: String,
modifier: Modifier = Modifier,
description: String? = null,
icon: ImageVector? = null,
onClick: (() -> Unit)? = null,
) {
ListItem(
headlineContent = { Text(title) },
supportingContent = { description?.let { Text(it) } },
leadingContent = {
icon?.let {
Icon(
imageVector = icon,
contentDescription = null,
modifier = Modifier.height(32.dp),
)
}
},
modifier = modifier.clickable { onClick?.invoke() },
)
}
/** Shows a Snackbar but dismisses any existing ones first. */
private suspend fun SnackbarHostState.showSnackbarDismissing(
text: String,
) {
currentSnackbarData?.dismiss()
showSnackbar(text)
}
@@ -4,29 +4,25 @@
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package dev.msfjarvis.claw.common.ui.decorations
package dev.msfjarvis.claw.android.ui.decorations
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import dev.msfjarvis.claw.common.theme.LobstersTheme
import dev.msfjarvis.claw.common.ui.preview.DevicePreviews
import dev.msfjarvis.claw.common.ui.preview.ThemePreviews
import dev.msfjarvis.claw.common.ui.surfaceColorAtNavigationBarElevation
@Composable
@OptIn(ExperimentalMaterial3Api::class)
fun ClawAppBar(
backgroundColor: Color,
modifier: Modifier = Modifier,
navigationIcon: @Composable () -> Unit = {},
title: @Composable () -> Unit = {},
@@ -35,7 +31,7 @@ fun ClawAppBar(
TopAppBar(
title = title,
modifier = modifier.shadow(8.dp),
colors = TopAppBarDefaults.smallTopAppBarColors(containerColor = backgroundColor),
colors = TopAppBarDefaults.topAppBarColors(),
navigationIcon = navigationIcon,
actions = actions,
)
@@ -47,7 +43,6 @@ fun ClawAppBar(
fun ClawAppBarPreview() {
LobstersTheme {
ClawAppBar(
backgroundColor = MaterialTheme.colorScheme.surfaceColorAtNavigationBarElevation(),
title = { Text("Claw", fontWeight = FontWeight.Bold) },
)
}
@@ -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.
@@ -19,17 +19,18 @@ import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag
import androidx.navigation.NavController
import dev.msfjarvis.claw.android.ui.navigation.Destinations
import kotlinx.collections.immutable.ImmutableList
private const val AnimationDuration = 100
const val AnimationDuration = 100
@Composable
fun ClawNavigationBar(
navController: NavController,
items: List<NavigationItem>,
items: ImmutableList<NavigationItem>,
isVisible: Boolean,
modifier: Modifier = Modifier,
) {
@@ -54,10 +55,10 @@ fun ClawNavigationBar(
val isCurrentDestination = navController.currentDestination?.route == navItem.route
NavigationBarItem(
icon = {
Crossfade(isCurrentDestination) {
Crossfade(isCurrentDestination, label = "nav-label") {
Icon(
painter = if (it) navItem.selectedIcon else navItem.icon,
contentDescription = navItem.label.uppercase()
imageVector = if (it) navItem.selectedIcon else navItem.icon,
contentDescription = navItem.label.replaceFirstChar(Char::uppercase),
)
}
},
@@ -66,13 +67,13 @@ fun ClawNavigationBar(
onClick = {
if (isCurrentDestination) {
navItem.listStateResetCallback()
return@NavigationBarItem
}
navController.graph.startDestinationRoute?.let { startDestination ->
navController.popBackStack(startDestination, false)
}
if (navItem.route != Destinations.startDestination.route) {
navController.navigate(navItem.route)
} else {
navController.graph.startDestinationRoute?.let { startDestination ->
navController.popBackStack(startDestination, false)
}
if (navItem.route != Destinations.startDestination.route) {
navController.navigate(navItem.route)
}
}
},
modifier = Modifier.testTag(navItem.label.uppercase()),
@@ -85,7 +86,7 @@ fun ClawNavigationBar(
class NavigationItem(
val label: String,
val route: String,
val icon: Painter,
val selectedIcon: Painter,
val icon: ImageVector,
val selectedIcon: ImageVector,
val listStateResetCallback: () -> Unit,
)
@@ -0,0 +1,84 @@
/*
* 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.android.ui.decorations
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.LinearOutSlowInEasing
import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.foundation.layout.Spacer
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationRail
import androidx.compose.material3.NavigationRailItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.navigation.NavController
import dev.msfjarvis.claw.android.ui.navigation.Destinations
import kotlinx.collections.immutable.ImmutableList
@Composable
fun ClawNavigationRail(
navController: NavController,
items: ImmutableList<NavigationItem>,
isVisible: Boolean,
modifier: Modifier = Modifier,
) {
AnimatedVisibility(
visible = isVisible,
enter =
slideInHorizontally(
// Enters by sliding in from offset -fullWidth to 0.
initialOffsetX = { fullWidth -> -fullWidth },
animationSpec = tween(durationMillis = AnimationDuration, easing = LinearOutSlowInEasing),
),
exit =
slideOutHorizontally(
// Exits by sliding out from offset 0 to -fullWidth.
targetOffsetX = { fullWidth -> -fullWidth },
animationSpec = tween(durationMillis = AnimationDuration, easing = FastOutLinearInEasing),
),
modifier = Modifier,
) {
NavigationRail(modifier = modifier) {
Spacer(Modifier.weight(1f))
items.forEach { navItem ->
val isCurrentDestination = navController.currentDestination?.route == navItem.route
NavigationRailItem(
icon = {
Crossfade(isCurrentDestination, label = "nav-label") {
Icon(
imageVector = if (it) navItem.selectedIcon else navItem.icon,
contentDescription = navItem.label.replaceFirstChar(Char::uppercase),
)
}
},
label = { Text(text = navItem.label) },
selected = isCurrentDestination,
onClick = {
if (isCurrentDestination) {
navItem.listStateResetCallback()
} else {
navController.graph.startDestinationRoute?.let { startDestination ->
navController.popBackStack(startDestination, false)
}
if (navItem.route != Destinations.startDestination.route) {
navController.navigate(navItem.route)
}
}
},
modifier = Modifier.testTag(navItem.label.uppercase()),
)
}
Spacer(Modifier.weight(1f))
}
}
}
@@ -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.
@@ -19,8 +19,6 @@ import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
import dev.msfjarvis.claw.database.local.SavedPost
import dev.msfjarvis.claw.model.LinkMetadata
import dev.msfjarvis.claw.model.LobstersPostDetails
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
fun Context.getActivity(): ComponentActivity? {
return when (this) {
@@ -30,14 +28,6 @@ fun Context.getActivity(): ComponentActivity? {
}
}
/**
* Parses a given [String] into a [LocalDateTime]. This method is only intended to be used for dates
* in the format returned by the Lobsters API, and is not a general purpose parsing solution.
*/
fun String.toLocalDateTime(): LocalDateTime {
return LocalDateTime.from(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(this))
}
@Composable
fun rememberPostActions(
urlLauncher: UrlLauncher,
@@ -46,14 +36,17 @@ fun rememberPostActions(
): PostActions {
return remember {
object : PostActions {
override fun viewPost(postUrl: String, commentsUrl: String) {
override fun viewPost(postId: String, postUrl: String, commentsUrl: String) {
viewModel.markPostAsRead(postId)
urlLauncher.openUri(postUrl.ifEmpty { commentsUrl })
}
override fun viewComments(postId: String) {
navController.navigate(
viewModel.markPostAsRead(postId)
val currentRoute = navController.currentDestination?.route
val newRoute =
Destinations.Comments.route.replace(Destinations.Comments.placeholder, postId)
)
if (currentRoute != Destinations.Comments.route) navController.navigate(newRoute)
}
override fun viewCommentsPage(commentsUrl: String) {
@@ -6,40 +6,68 @@
*/
package dev.msfjarvis.claw.android.ui.lists
import androidx.activity.compose.ReportDrawn
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Divider
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Inbox
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import dev.msfjarvis.claw.common.posts.PostActions
import dev.msfjarvis.claw.common.ui.decorations.MonthHeader
import dev.msfjarvis.claw.database.local.SavedPost
import java.time.Month
import kotlinx.collections.immutable.ImmutableMap
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun DatabasePosts(
items: Map<Month, List<SavedPost>>,
items: ImmutableMap<Month, List<SavedPost>>,
listState: LazyListState,
postActions: PostActions,
modifier: Modifier = Modifier,
) {
LazyColumn(
state = listState,
modifier = modifier,
) {
items.forEach { (month, posts) ->
stickyHeader { MonthHeader(month = month) }
items(posts, { it.shortId }) { item ->
ListItem(
item = item,
isSaved = { true },
postActions = postActions,
ReportDrawn()
Box(modifier = modifier.fillMaxSize()) {
if (items.isEmpty()) {
Column(modifier = Modifier.align(Alignment.Center)) {
Icon(
imageVector = Icons.Filled.Inbox,
contentDescription = "Empty inbox icon",
modifier = Modifier.align(Alignment.CenterHorizontally).size(36.dp),
)
Divider()
Text(text = "No saved posts", style = MaterialTheme.typography.headlineSmall)
}
} else {
LazyColumn(state = listState) {
items.forEach { (month, posts) ->
stickyHeader(contentType = "month-header") { MonthHeader(month = month) }
items(
items = posts,
key = { it.shortId },
contentType = { "LobstersItem" },
) { item ->
ListItem(
item = item,
isSaved = { true },
isRead = { false },
postActions = postActions,
)
HorizontalDivider()
}
}
}
}
}
@@ -1,31 +1,50 @@
/*
* 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.android.ui.lists
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Reply
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import dev.msfjarvis.claw.common.posts.LobstersCard
import dev.msfjarvis.claw.common.posts.PostActions
import dev.msfjarvis.claw.database.local.SavedPost
import me.saket.swipe.SwipeAction
import me.saket.swipe.SwipeableActionsBox
@Composable
fun ListItem(
item: SavedPost,
isSaved: suspend (SavedPost) -> Boolean,
isRead: suspend (String) -> Boolean,
postActions: PostActions,
modifier: Modifier = Modifier,
) {
val saved by produceState(false, item) { value = isSaved(item) }
LobstersCard(
post = item,
isSaved = saved,
postActions = postActions,
modifier = modifier,
)
val read by produceState(false, item.shortId) { value = isRead(item.shortId) }
val commentsAction =
SwipeAction(
icon = rememberVectorPainter(Icons.AutoMirrored.Filled.Reply),
background = MaterialTheme.colorScheme.tertiary,
onSwipe = { postActions.viewCommentsPage(item.commentsUrl) },
)
SwipeableActionsBox(
endActions = listOf(commentsAction),
) {
LobstersCard(
post = item,
isSaved = saved,
isRead = read,
postActions = postActions,
modifier = modifier,
)
}
}
@@ -1,11 +1,12 @@
/*
* 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.android.ui.lists
import androidx.activity.compose.ReportDrawnWhen
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -13,36 +14,37 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.contentColorFor
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.paging.LoadState
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.items
import androidx.paging.compose.itemContentType
import androidx.paging.compose.itemKey
import dev.msfjarvis.claw.common.posts.PostActions
import dev.msfjarvis.claw.common.posts.toDbModel
import dev.msfjarvis.claw.common.ui.NetworkError
import dev.msfjarvis.claw.common.ui.ProgressBar
import dev.msfjarvis.claw.database.local.SavedPost
import dev.msfjarvis.claw.model.LobstersPost
import dev.msfjarvis.claw.model.toSavedPost
import eu.bambooapps.material3.pullrefresh.PullRefreshIndicator
import eu.bambooapps.material3.pullrefresh.pullRefresh
import eu.bambooapps.material3.pullrefresh.rememberPullRefreshState
@OptIn(ExperimentalMaterialApi::class)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NetworkPosts(
lazyPagingItems: LazyPagingItems<LobstersPost>,
listState: LazyListState,
isPostSaved: suspend (SavedPost) -> Boolean,
isPostRead: suspend (String) -> Boolean,
postActions: PostActions,
modifier: Modifier = Modifier,
) {
ReportDrawnWhen { lazyPagingItems.itemCount > 0 }
val refreshLoadState = lazyPagingItems.loadState.refresh
val isRefreshing = refreshLoadState == LoadState.Loading
val pullRefreshState = rememberPullRefreshState(isRefreshing, lazyPagingItems::refresh)
@@ -57,16 +59,22 @@ fun NetworkPosts(
LazyColumn(
state = listState,
) {
items(items = lazyPagingItems, key = { it.shortId }) { item ->
items(
count = lazyPagingItems.itemCount,
key = lazyPagingItems.itemKey { it.shortId },
contentType = lazyPagingItems.itemContentType { "LobstersItem" },
) { index ->
val item = lazyPagingItems[index]
if (item != null) {
val dbModel = item.toDbModel()
val dbModel = item.toSavedPost()
ListItem(
item = dbModel,
isSaved = isPostSaved,
isRead = isPostRead,
postActions = postActions,
)
Divider()
HorizontalDivider()
}
}
if (lazyPagingItems.loadState.append == LoadState.Loading) {
@@ -85,8 +93,7 @@ fun NetworkPosts(
refreshing = isRefreshing,
state = pullRefreshState,
modifier = Modifier.align(Alignment.TopCenter),
backgroundColor = MaterialTheme.colorScheme.surface,
contentColor = contentColorFor(MaterialTheme.colorScheme.surface),
shadowElevation = 6.dp, // From M2 implementation
)
}
}
@@ -0,0 +1,95 @@
/*
* 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.android.ui.lists
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.SearchOff
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.isTraversalGroup
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.paging.PagingData
import androidx.paging.compose.collectAsLazyPagingItems
import dev.msfjarvis.claw.common.posts.PostActions
import dev.msfjarvis.claw.common.ui.SearchBar
import dev.msfjarvis.claw.database.local.SavedPost
import dev.msfjarvis.claw.model.LobstersPost
import kotlinx.coroutines.flow.Flow
@Composable
fun SearchList(
items: Flow<PagingData<LobstersPost>>,
listState: LazyListState,
isPostSaved: suspend (SavedPost) -> Boolean,
postActions: PostActions,
searchQuery: String,
setSearchQuery: (String) -> Unit,
modifier: Modifier = Modifier,
) {
val lazyPagingItems = items.collectAsLazyPagingItems()
val triggerSearch = { query: String ->
setSearchQuery(query)
lazyPagingItems.refresh()
}
DisposableEffect(true) {
// Clear search field when navigating away
onDispose { setSearchQuery("") }
}
var searchActive by remember { mutableStateOf(false) }
Column(modifier = Modifier.semantics { isTraversalGroup = true }.zIndex(1f).fillMaxWidth()) {
SearchBar(
value = searchQuery,
onValueChange = setSearchQuery,
onSearch = {
triggerSearch(it)
searchActive = true
},
modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp).testTag("search_bar"),
)
if (searchActive) {
NetworkPosts(
lazyPagingItems = lazyPagingItems,
listState = listState,
isPostSaved = isPostSaved,
isPostRead = { false },
postActions = postActions,
modifier = modifier,
)
} else {
Box(modifier = Modifier.fillMaxSize()) {
Column(modifier = Modifier.align(Alignment.Center)) {
Icon(
imageVector = Icons.Filled.SearchOff,
contentDescription = "No search results",
modifier = Modifier.align(Alignment.CenterHorizontally).size(36.dp),
)
Text(text = "Nothing to see here", style = MaterialTheme.typography.headlineSmall)
}
}
}
}
}
@@ -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.
@@ -21,6 +21,10 @@ sealed class Destinations {
override val route = "saved"
}
object Search : Destinations() {
override val route = "search"
}
object Comments : Destinations() {
const val placeholder = "{postId}"
override val route = "comments/$placeholder"
@@ -31,6 +35,10 @@ sealed class Destinations {
override val route = "user/$placeholder"
}
object DataTransfer : Destinations() {
override val route: String = "datatransfer"
}
companion object {
val startDestination
get() = Hottest
@@ -0,0 +1,24 @@
/*
* 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.android.ui.navigation
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
enum class ClawNavigationType {
BOTTOM_NAVIGATION,
NAVIGATION_RAIL;
companion object {
fun fromSize(windowSize: WindowWidthSizeClass): ClawNavigationType {
return when (windowSize) {
WindowWidthSizeClass.Medium,
WindowWidthSizeClass.Expanded -> NAVIGATION_RAIL
else -> BOTTOM_NAVIGATION
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2022 Harsh Shandilya.
* 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.
@@ -6,25 +6,43 @@
*/
package dev.msfjarvis.claw.android.viewmodel
import androidx.lifecycle.ViewModel
import android.app.Application
import android.content.Context
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.glance.appwidget.updateAll
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import com.deliveryhero.whetstone.app.ApplicationScope
import com.deliveryhero.whetstone.viewmodel.ContributesViewModel
import com.slack.eithernet.ApiResult.Failure
import com.slack.eithernet.ApiResult.Success
import dev.msfjarvis.claw.android.injection.IODispatcher
import com.squareup.anvil.annotations.optional.ForScope
import dev.msfjarvis.claw.android.glance.SavedPostsWidget
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.android.paging.SearchPagingSource
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.api.LobstersSearchApi
import dev.msfjarvis.claw.core.injection.IODispatcher
import dev.msfjarvis.claw.core.injection.MainDispatcher
import dev.msfjarvis.claw.database.local.SavedPost
import dev.msfjarvis.claw.model.Comment
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.net.HttpURLConnection
import java.time.LocalDateTime
import java.time.Month
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import javax.inject.Inject
import kotlinx.collections.immutable.ImmutableMap
import kotlinx.collections.immutable.toImmutableMap
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@@ -36,11 +54,18 @@ class ClawViewModel
@Inject
constructor(
private val api: LobstersApi,
private val searchApi: LobstersSearchApi,
private val commentsRepository: CommentsRepository,
private val readPostsRepository: ReadPostsRepository,
private val savedPostsRepository: SavedPostsRepository,
private val linkMetadataRepository: LinkMetadataRepository,
private val dataTransferRepository: DataTransferRepository,
private val pagingSourceFactory: LobstersPagingSource.Factory,
private val searchPagingSourceFactory: SearchPagingSource.Factory,
@IODispatcher private val ioDispatcher: CoroutineDispatcher,
) : ViewModel() {
@MainDispatcher private val mainDispatcher: CoroutineDispatcher,
@ForScope(ApplicationScope::class) context: Context,
) : AndroidViewModel(context as Application) {
private val hottestPostsPager =
Pager(PagingConfig(pageSize = PAGE_SIZE), initialKey = STARTING_PAGE_INDEX) {
pagingSourceFactory.create(api::getHottestPosts)
@@ -49,6 +74,10 @@ constructor(
Pager(PagingConfig(pageSize = PAGE_SIZE), initialKey = STARTING_PAGE_INDEX) {
pagingSourceFactory.create(api::getNewestPosts)
}
private val searchResultsPager =
Pager(PagingConfig(pageSize = PAGE_SIZE), initialKey = STARTING_PAGE_INDEX) {
searchPagingSourceFactory.create { searchApi.searchPosts(searchQuery, it) }
}
val hottestPosts
get() = hottestPostsPager.flow
@@ -56,19 +85,30 @@ constructor(
val newestPosts
get() = newestPostsPager.flow
private val savedPostsFlow
get() = savedPostsRepository.savedPosts
val savedPosts
get() = savedPostsFlow.map(::mapSavedPosts)
get() =
savedPostsRepository.savedPosts.map {
it.sortedByDescending { post -> post.createdAt.toLocalDateTime() }
}
private fun mapSavedPosts(items: List<SavedPost>): Map<Month, List<SavedPost>> {
val sorted = items.sortedByDescending { post -> post.createdAt.toLocalDateTime() }
return sorted.groupBy { post -> post.createdAt.toLocalDateTime().month }
val savedPostsByMonth
get() = savedPosts.map(::mapSavedPosts)
val searchResults
get() = searchResultsPager.flow
var searchQuery by mutableStateOf("")
private fun mapSavedPosts(items: List<SavedPost>): ImmutableMap<Month, List<SavedPost>> {
val sorted =
items.sortedWith { post1, post2 ->
post2.createdAt.toLocalDateTime().compareTo(post1.createdAt.toLocalDateTime())
}
return sorted.groupBy { post -> post.createdAt.toLocalDateTime().month }.toImmutableMap()
}
suspend fun isPostSaved(post: SavedPost): Boolean {
return savedPostsFlow.first().any { savedPost -> savedPost.shortId == post.shortId }
return savedPosts.first().any { savedPost -> savedPost.shortId == post.shortId }
}
fun toggleSave(post: SavedPost) {
@@ -79,6 +119,10 @@ constructor(
} else {
savedPostsRepository.savePost(post)
}
val newPosts = savedPosts.first()
withContext(mainDispatcher) {
SavedPostsWidget(newPosts.take(50)).updateAll(getApplication())
}
}
}
@@ -99,10 +143,10 @@ constructor(
}
}
suspend fun getSeenComments(postId: String) = savedPostsRepository.getSeenComments(postId)
suspend fun getSeenComments(postId: String) = commentsRepository.getSeenComments(postId)
fun markSeenComments(postId: String, comments: List<Comment>) {
viewModelScope.launch { savedPostsRepository.markSeenComments(postId, comments) }
viewModelScope.launch { commentsRepository.markSeenComments(postId, comments) }
}
suspend fun getLinkMetadata(url: String) =
@@ -118,4 +162,24 @@ constructor(
is Failure.ApiFailure -> throw IOException("API returned an invalid response")
}
}
suspend fun importPosts(input: InputStream) = dataTransferRepository.importPosts(input)
suspend fun exportPosts(output: OutputStream) = dataTransferRepository.exportPosts(output)
fun markPostAsRead(postId: String) {
viewModelScope.launch { readPostsRepository.markRead(postId) }
}
suspend fun isPostRead(postId: String) = readPostsRepository.isRead(postId)
/**
* Parses a given [String] into a [LocalDateTime]. This method is only intended to be used for
* dates in the format returned by the Lobsters API, and is not a general purpose parsing
* solution.
*/
private fun String.toLocalDateTime(): LocalDateTime {
if (isEmpty()) return LocalDateTime.now(ZoneId.systemDefault())
return LocalDateTime.from(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(this))
}
}
@@ -0,0 +1,32 @@
/*
* 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.android.viewmodel
import dev.msfjarvis.claw.core.injection.DatabaseDispatcher
import dev.msfjarvis.claw.database.local.PostComments
import dev.msfjarvis.claw.database.local.PostCommentsQueries
import dev.msfjarvis.claw.model.Comment
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
class CommentsRepository
@Inject
constructor(
private val postCommentsQueries: PostCommentsQueries,
@DatabaseDispatcher private val dbDispatcher: CoroutineDispatcher,
) {
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 }))
}
}
}
@@ -0,0 +1,53 @@
/*
* 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.android.viewmodel
import dev.msfjarvis.claw.core.injection.DatabaseDispatcher
import dev.msfjarvis.claw.core.injection.IODispatcher
import dev.msfjarvis.claw.database.SavedPostSerializer
import dev.msfjarvis.claw.database.local.SavedPost
import dev.msfjarvis.claw.database.local.SavedPostQueries
import java.io.InputStream
import java.io.OutputStream
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.encodeToStream
@OptIn(ExperimentalSerializationApi::class)
class DataTransferRepository
@Inject
constructor(
private val json: Json,
private val savedPostQueries: SavedPostQueries,
@DatabaseDispatcher private val dbDispatcher: CoroutineDispatcher,
@IODispatcher private val ioDispatcher: CoroutineDispatcher,
) {
private val serializer = ListSerializer(SavedPostSerializer)
suspend fun importPosts(input: InputStream) {
val posts: List<SavedPost> =
withContext(ioDispatcher) {
json.decodeFromStream(
serializer,
input,
)
}
withContext(dbDispatcher) {
savedPostQueries.transaction { posts.forEach(savedPostQueries::insertOrReplacePost) }
}
}
suspend fun exportPosts(output: OutputStream) {
val posts = withContext(dbDispatcher) { savedPostQueries.selectAllPosts().executeAsList() }
withContext(ioDispatcher) { json.encodeToStream(serializer, posts, output) }
}
}
@@ -1,21 +1,26 @@
/*
* 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.
*/
package dev.msfjarvis.claw.android.viewmodel
import dev.msfjarvis.claw.metadata.MetadataExtractor
import dev.msfjarvis.claw.core.injection.IODispatcher
import dev.msfjarvis.claw.model.LinkMetadata
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import me.saket.unfurl.Unfurler
class LinkMetadataRepository
@Inject
constructor(
private val metadataExtractor: MetadataExtractor,
private val unfurler: Unfurler,
@IODispatcher private val dispatcher: CoroutineDispatcher,
) {
suspend fun getLinkMetadata(url: String): LinkMetadata {
return metadataExtractor.getExtractedMetadata(url)
val result = withContext(dispatcher) { unfurler.unfurl(url) }
return LinkMetadata(url, result?.favicon?.toString())
}
}
@@ -0,0 +1,28 @@
/*
* 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.android.viewmodel
import dev.msfjarvis.claw.core.injection.DatabaseDispatcher
import dev.msfjarvis.claw.database.local.ReadPostsQueries
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
class ReadPostsRepository
@Inject
constructor(
private val readPostsQueries: ReadPostsQueries,
@DatabaseDispatcher private val dbDispatcher: CoroutineDispatcher,
) {
suspend fun markRead(postId: String) {
withContext(dbDispatcher) { readPostsQueries.markRead(postId) }
}
suspend fun isRead(postId: String): Boolean =
withContext(dbDispatcher) { readPostsQueries.isRead(postId).executeAsOneOrNull() != null }
}
@@ -8,11 +8,9 @@ package dev.msfjarvis.claw.android.viewmodel
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.core.injection.DatabaseDispatcher
import dev.msfjarvis.claw.database.local.SavedPost
import dev.msfjarvis.claw.model.Comment
import dev.msfjarvis.claw.database.local.SavedPostQueries
import io.github.aakira.napier.Napier
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -21,11 +19,9 @@ import kotlinx.coroutines.withContext
class SavedPostsRepository
@Inject
constructor(
database: LobstersDatabase,
private val savedPostQueries: SavedPostQueries,
@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) {
@@ -47,15 +43,6 @@ constructor(
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"
}
@@ -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.
@@ -7,16 +7,18 @@
package dev.msfjarvis.claw.android.work
import android.content.Context
import androidx.glance.appwidget.updateAll
import androidx.work.CoroutineWorker
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.Success
import com.squareup.anvil.annotations.optional.ForScope
import dev.msfjarvis.claw.android.glance.SavedPostsWidget
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 dev.msfjarvis.claw.model.toSavedPost
import javax.inject.Inject
import kotlinx.coroutines.flow.first
@@ -40,9 +42,9 @@ constructor(
.first()
.map { post -> lobstersApi.getPostDetails(post.shortId) }
.filterIsInstance<Success<LobstersPostDetails>>()
.map { result -> result.value.toDbModel() }
.toList()
.map { result -> result.value.toSavedPost() }
.let { savedPostsRepository.savePosts(it) }
SavedPostsWidget(savedPostsRepository.savedPosts.first().take(50)).updateAll(applicationContext)
return Result.success()
}
}
@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
~ 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.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
<monochrome android:drawable="@mipmap/ic_launcher_foreground" />
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 B

After

Width:  |  Height:  |  Size: 44 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 B

After

Width:  |  Height:  |  Size: 44 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 B

After

Width:  |  Height:  |  Size: 46 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 B

After

Width:  |  Height:  |  Size: 52 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<bool name="use_light_status_bar">false</bool>
</resources>
-4
View File
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<bool name="use_light_status_bar">true</bool>
</resources>
+6 -1
View File
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
~ 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.
-->
<resources>
<string name="app_name">Claw</string>
</resources>
+7 -4
View File
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
~ 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.
-->
<resources>
<style name="Theme.Claw.SplashScreen" parent="Theme.SplashScreen">
@@ -14,7 +19,5 @@
<item name="android:windowActionModeOverlay">true</item>
</style>
<style name="Theme.Claw" parent="Base.Theme.Claw">
<item name="android:windowLightStatusBar">@bool/use_light_status_bar</item>
</style>
<style name="Theme.Claw" parent="Base.Theme.Claw" />
</resources>
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<data-extraction-rules>
<cloud-backup>
<include
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<full-backup-content>
<include
domain="database"
@@ -0,0 +1,15 @@
<!--
~ 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.
-->
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/glance_default_loading_layout"
android:minWidth="349dp"
android:minHeight="110dp"
android:minResizeWidth="349dp"
android:minResizeHeight="110dp"
android:resizeMode="vertical|horizontal"
android:updatePeriodMillis="1800000"
android:widgetCategory="home_screen" />
-20
View File
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<!-- Required: set your sentry.io project identifier (DSN) -->
<meta-data android:name="io.sentry.dsn" android:value="${sentryDsn}" />
<!-- enable automatic breadcrumbs for user interactions (clicks, swipes, scrolls) -->
<meta-data android:name="io.sentry.traces.user-interaction.enable" android:value="true" />
<meta-data android:name="io.sentry.breadcrumbs.user-interaction" android:value="true" />
<!-- enable screenshot for crashes -->
<meta-data android:name="io.sentry.attach-screenshot" android:value="true" />
<!-- enable view hierarchy for crashes -->
<meta-data android:name="io.sentry.attach-view-hierarchy" android:value="true" />
<!-- enable the performance API by setting a sample-rate, adjust in production env -->
<meta-data android:name="io.sentry.traces.sample-rate" android:value="0.8" />
<!-- enable profiling when starting transactions, adjust in production env -->
<meta-data android:name="io.sentry.traces.profiling.sample-rate" android:value="0.8" />
</application>
</manifest>
+2 -2
View File
@@ -1,5 +1,5 @@
#
# This file was automatically generated by 'versioning-plugin'. DO NOT EDIT MANUALLY.
#
versioning-plugin.versionCode=12300
versioning-plugin.versionName=1.23.0
versioning-plugin.versionCode=13700
versioning-plugin.versionName=1.37.0
+10 -8
View File
@@ -1,14 +1,14 @@
/*
* 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.
*/
@file:Suppress("DSL_SCOPE_VIOLATION", "UnstableApiUsage")
import dev.msfjarvis.claw.gradle.addTestDependencies
plugins {
id("dev.msfjarvis.claw.kotlin-android")
id("dev.msfjarvis.claw.android-library")
id("dev.msfjarvis.claw.kotlin-android")
alias(libs.plugins.anvil)
alias(libs.plugins.whetstone)
}
@@ -18,14 +18,16 @@ android { namespace = "dev.msfjarvis.claw.api" }
anvil { generateDaggerFactories.set(true) }
dependencies {
api(projects.model)
api(libs.retrofit)
api(libs.eithernet)
api(libs.retrofit)
api(projects.model)
implementation(libs.dagger)
implementation(libs.javax.inject)
implementation(libs.jsoup)
testImplementation(testFixtures(libs.eithernet))
testImplementation(libs.kotest.assertions.core)
testImplementation(libs.kotest.runner.junit5)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.kotlinx.serialization.json)
testImplementation(libs.retrofit.kotlinxSerializationConverter)
addTestDependencies(project)
}
+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 8.0.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-alpha08)" variant="all" version="8.0.0-alpha08">
<issues format="6" by="lint 8.3.0-alpha02" type="baseline" client="gradle" dependencies="true" name="AGP (8.3.0-alpha02)" variant="all" version="8.3.0-alpha02">
</issues>
@@ -0,0 +1,9 @@
/*
* 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.api
@JvmInline value class CSRFToken(val value: String)
@@ -9,7 +9,6 @@ package dev.msfjarvis.claw.api
import com.slack.eithernet.ApiResult
import dev.msfjarvis.claw.model.LobstersPost
import dev.msfjarvis.claw.model.LobstersPostDetails
import dev.msfjarvis.claw.model.Tags
import dev.msfjarvis.claw.model.User
import retrofit2.http.GET
import retrofit2.http.Path
@@ -27,14 +26,10 @@ interface LobstersApi {
@GET("s/{postId}.json")
suspend fun getPostDetails(@Path("postId") postId: String): ApiResult<LobstersPostDetails, Unit>
@GET("u/{username}.json")
@GET("~{username}.json")
suspend fun getUser(@Path("username") username: String): ApiResult<User, Unit>
@GET("t/{tags}.json")
suspend fun getPostsByTags(
@Path("tags") tag: Tags,
@Query("page") page: Int,
): ApiResult<List<LobstersPost>, Unit>
@GET("/") suspend fun getCSRFToken(): ApiResult<CSRFToken, Unit>
companion object {
const val BASE_URL = "https://lobste.rs"
@@ -0,0 +1,20 @@
/*
* 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.api
import com.slack.eithernet.ApiResult
import dev.msfjarvis.claw.model.LobstersPost
import retrofit2.http.GET
import retrofit2.http.Query
interface LobstersSearchApi {
@GET("/search?what=stories&order=newest")
suspend fun searchPosts(
@Query("q") searchQuery: String,
@Query("page") page: Int,
): ApiResult<List<LobstersPost>, Unit>
}
@@ -0,0 +1,36 @@
/*
* 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.api.converters
import dev.msfjarvis.claw.api.CSRFToken
import dev.msfjarvis.claw.api.LobstersApi
import java.lang.reflect.Type
import okhttp3.ResponseBody
import org.jsoup.Jsoup
import retrofit2.Converter
import retrofit2.Retrofit
object CSRFTokenConverter : Converter<ResponseBody, CSRFToken> {
override fun convert(value: ResponseBody): CSRFToken {
val token =
Jsoup.parse(value.string(), LobstersApi.BASE_URL)
.select("meta[name=\"csrf-token\"]")
.first()!!
.attr("content")
return CSRFToken(token)
}
object Factory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<out Annotation>,
retrofit: Retrofit,
): Converter<ResponseBody, CSRFToken> {
return CSRFTokenConverter
}
}
}
@@ -0,0 +1,85 @@
/*
* 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.api.converters
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.model.LobstersPost
import dev.msfjarvis.claw.model.User
import java.lang.reflect.Type
import okhttp3.ResponseBody
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import retrofit2.Converter
import retrofit2.Retrofit
object SearchConverter : Converter<ResponseBody, List<LobstersPost>> {
override fun convert(value: ResponseBody): List<LobstersPost> {
val elements =
Jsoup.parse(value.string(), LobstersApi.BASE_URL).select("div.story_liner.h-entry")
return elements.map(::parsePost)
}
private fun parsePost(elem: Element): LobstersPost {
val parent = elem.parent() ?: error("$elem must have a parent")
val shortId = parent.attr("data-shortid")
val titleElement = elem.select("span.link.h-cite > a")
val title = titleElement.text()
val url = titleElement.attr("href")
val tags = elem.select("span.tags > a").map(Element::text)
val (commentCount, commentsUrl) = getCommentsData(elem.select("span.comments_label"))
val submitter =
getSubmitter(elem.select("div.byline").first() ?: error("No byline element found"))
return LobstersPost(
shortId = shortId,
title = title,
url = url,
commentCount = commentCount,
commentsUrl = commentsUrl,
tags = tags,
submitter = submitter,
// The value of these fields is irrelevant for our use case
createdAt = "",
description = "",
)
}
private fun getCommentsData(elem: Elements): Pair<Int, String> {
val linkElement = elem.select("a")
val countString = linkElement.text().trimStart().substringBefore(" ")
val commentsUrl = LobstersApi.BASE_URL + linkElement.attr("href")
return (countString.toIntOrNull() ?: 0) to commentsUrl
}
/**
* Make a bare-bones [User] object given a byline [elem]. We only need this to be usable for
* displaying in a list.
*/
private fun getSubmitter(elem: Element): User {
val userElement = elem.select("a.u-author")
val avatarElement = elem.select("img.avatar")
val username = userElement.text()
val avatarUrl = avatarElement.attr("src")
return User(
username = username,
about = "",
invitedBy = null,
avatarUrl = avatarUrl,
createdAt = "",
)
}
object Factory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<out Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, List<LobstersPost>> {
return SearchConverter
}
}
}
@@ -1,42 +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.api.injection
import com.deliveryhero.whetstone.app.ApplicationScope
import com.slack.eithernet.ApiResultCallAdapterFactory
import com.slack.eithernet.ApiResultConverterFactory
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import dev.msfjarvis.claw.api.LobstersApi
import okhttp3.OkHttpClient
import retrofit2.Converter
import retrofit2.Retrofit
import retrofit2.create
@Module
@ContributesTo(ApplicationScope::class)
object ApiModule {
@Provides
fun provideRetrofit(
client: OkHttpClient,
converterFactories: Set<@JvmSuppressWildcards Converter.Factory>,
): Retrofit {
return Retrofit.Builder()
.client(client)
.baseUrl(LobstersApi.BASE_URL)
.addConverterFactory(ApiResultConverterFactory)
.addCallAdapterFactory(ApiResultCallAdapterFactory)
.apply { converterFactories.forEach(this::addConverterFactory) }
.build()
}
@Provides
fun provideApi(retrofit: Retrofit): LobstersApi {
return retrofit.create()
}
}
@@ -0,0 +1,104 @@
/*
* 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.api.injection
import com.deliveryhero.whetstone.app.ApplicationScope
import com.slack.eithernet.ApiResultCallAdapterFactory
import com.slack.eithernet.ApiResultConverterFactory
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import dagger.multibindings.IntKey
import dagger.multibindings.IntoMap
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.api.LobstersSearchApi
import dev.msfjarvis.claw.api.converters.CSRFTokenConverter
import dev.msfjarvis.claw.api.converters.SearchConverter
import javax.inject.Qualifier
import okhttp3.OkHttpClient
import retrofit2.CallAdapter
import retrofit2.Converter
import retrofit2.Retrofit
import retrofit2.create
/**
* Ideally the multibindings used here would only use [dagger.multibindings.IntoSet], but its lack
* of ordering guarantees means that we roll a die on each app launch that [Converter]s and
* [CallAdapter]s are in the correct order to be able to deserialize responses. Thus, the module
* uses [IntoMap] with [IntKey]s to fake the presence of a fixed order by sorting on the key of the
* injected [Map]s when injecting them into [Retrofit].
*/
@Module
@ContributesTo(ApplicationScope::class)
object RetrofitModule {
@Provides
fun provideRetrofit(
client: OkHttpClient,
converterFactories: Map<Int, @JvmSuppressWildcards Converter.Factory>,
callAdapterFactories: Map<Int, @JvmSuppressWildcards CallAdapter.Factory>,
@BaseUrl baseUrl: String,
): Retrofit {
return Retrofit.Builder()
.client(client)
.baseUrl(baseUrl)
.apply { converterFactories.toSortedMap().values.forEach(this::addConverterFactory) }
.apply { callAdapterFactories.toSortedMap().values.forEach(this::addCallAdapterFactory) }
.build()
}
@Provides
@SearchApi
fun provideSearchApiRetrofit(
client: OkHttpClient,
@SearchApi converterFactories: List<@JvmSuppressWildcards Converter.Factory>,
callAdapterFactories: Map<Int, @JvmSuppressWildcards CallAdapter.Factory>,
@BaseUrl baseUrl: String,
): Retrofit {
return Retrofit.Builder()
.client(client)
.baseUrl(baseUrl)
.apply { converterFactories.forEach(this::addConverterFactory) }
.apply { callAdapterFactories.toSortedMap().values.forEach(this::addCallAdapterFactory) }
.addConverterFactory(SearchConverter.Factory)
.build()
}
@Provides fun provideApi(retrofit: Retrofit): LobstersApi = retrofit.create()
@Provides
fun provideSearchApi(@SearchApi retrofit: Retrofit): LobstersSearchApi = retrofit.create()
@Provides
@IntKey(0)
@IntoMap
fun provideApiResultConverter(): Converter.Factory = ApiResultConverterFactory
@Provides
@IntKey(0)
@IntoMap
fun provideApiResultCallAdapter(): CallAdapter.Factory = ApiResultCallAdapterFactory
@Provides
@IntKey(Int.MAX_VALUE)
@IntoMap
fun provideCSRFTokenConverter(): Converter.Factory = CSRFTokenConverter.Factory
@Provides
@SearchApi
fun provideConverters(): List<@JvmSuppressWildcards Converter.Factory> =
listOf(
ApiResultConverterFactory,
SearchConverter.Factory,
)
@Provides @BaseUrl fun provideBaseUrl(): String = LobstersApi.BASE_URL
}
@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class BaseUrl
/** Internal Dagger [Qualifier] to identify dependencies exclusive to [LobstersSearchApi]. */
@Qualifier @Retention(AnnotationRetention.RUNTIME) private annotation class SearchApi
@@ -6,65 +6,57 @@
*/
package dev.msfjarvis.claw.api
import com.google.common.truth.Truth.assertThat
import com.slack.eithernet.ApiResult.Success
import com.slack.eithernet.test.newEitherNetController
import dev.msfjarvis.claw.model.LobstersPost
import dev.msfjarvis.claw.model.LobstersPostDetails
import dev.msfjarvis.claw.model.Tags
import dev.msfjarvis.claw.model.User
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeTypeOf
import dev.msfjarvis.claw.util.TestUtils.assertIs
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
class ApiTest : FunSpec() {
class ApiTest {
private val wrapper = ApiWrapper(newEitherNetController())
private val api
get() = wrapper.api
init {
test("api gets correct number of items") {
val posts = api.getHottestPosts(1)
posts.shouldBeTypeOf<Success<List<LobstersPost>>>()
posts.value shouldHaveSize 25
}
@Test
fun `api gets correct number of items`() = runTest {
val posts = api.getHottestPosts(1)
assertIs<Success<List<LobstersPost>>>(posts)
assertThat(posts.value).hasSize(25)
}
test("posts with no urls") {
val posts = api.getHottestPosts(1)
posts.shouldBeTypeOf<Success<List<LobstersPost>>>()
val commentsOnlyPosts = posts.value.asSequence().filter { it.url.isEmpty() }.toSet()
commentsOnlyPosts shouldHaveSize 2
}
@Test
fun `posts with no urls`() = runTest {
val posts = api.getHottestPosts(1)
assertIs<Success<List<LobstersPost>>>(posts)
val commentsOnlyPosts = posts.value.asSequence().filter { it.url.isEmpty() }.toSet()
assertThat(commentsOnlyPosts).hasSize(2)
}
test("post details with comments") {
val postDetails = api.getPostDetails("tdfoqh")
postDetails.shouldBeTypeOf<Success<LobstersPostDetails>>()
postDetails.value.comments shouldHaveSize 7
}
@Test
fun `post details with comments`() = runTest {
val postDetails = api.getPostDetails("tdfoqh")
assertIs<Success<LobstersPostDetails>>(postDetails)
assertThat(postDetails.value.comments).hasSize(10)
}
test("get user details") {
val user = api.getUser("msfjarvis")
user.shouldBeTypeOf<Success<User>>()
user.value.username shouldBe "msfjarvis"
}
@Test
fun `get user details`() = runTest {
val user = api.getUser("msfjarvis")
assertIs<Success<User>>(user)
assertThat(user.value.username).isEqualTo("msfjarvis")
}
test("get posts by single tag") {
var tags = Tags()
tags.addTag("meta")
val posts = api.getPostsByTags(tags, 1)
posts.shouldBeTypeOf<Success<List<LobstersPost>>>()
posts.value shouldHaveSize 25
posts.value[0].tags.contains("meta")
}
test("get posts by multiple tags") {
var tags = Tags()
tags.addTag("programming")
tags.addTag("rust")
val posts = api.getPostsByTags(tags, 1)
posts.shouldBeTypeOf<Success<List<LobstersPost>>>()
posts.value shouldHaveSize 25
posts.value[0].tags.contains("programming") or posts.value[0].tags.contains("rust")
}
@Test
fun `retrieve CSRF token`() = runTest {
val token = api.getCSRFToken()
assertIs<Success<CSRFToken>>(token)
assertThat(token.value.value)
.isEqualTo(
"OZWykgFemPVeOSNmB53-ccKXe458X7xCInO1-qzFU6nk_9RCSrSQqS9OPmA5_pyy8qD3IYAIZ7XfAM3gdhJpkQ"
)
}
}
@@ -9,14 +9,16 @@ package dev.msfjarvis.claw.api
import com.slack.eithernet.ApiResult.Companion.success
import com.slack.eithernet.test.EitherNetController
import com.slack.eithernet.test.enqueue
import dev.msfjarvis.claw.api.converters.CSRFTokenConverter
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 dev.msfjarvis.claw.util.TestUtils.getResource
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonNamingStrategy
import okhttp3.MediaType
import okhttp3.ResponseBody
@OptIn(ExperimentalSerializationApi::class)
class ApiWrapper(controller: EitherNetController<LobstersApi>) {
@@ -24,13 +26,10 @@ class ApiWrapper(controller: EitherNetController<LobstersApi>) {
ignoreUnknownKeys = true
namingStrategy = JsonNamingStrategy.SnakeCase
}
private val hottest: List<LobstersPost> = json.decodeFromString(getJson("hottest.json"))
private val hottest: List<LobstersPost> = json.decodeFromString(getResource("hottest.json"))
private val postDetails: LobstersPostDetails =
json.decodeFromString(getJson("post_details_tdfoqh.json"))
private val user: User = json.decodeFromString(getJson("msfjarvis.json"))
private val metaPosts: List<LobstersPost> = json.decodeFromString(getJson("meta.json"))
private val programmingRustPosts: List<LobstersPost> =
json.decodeFromString(getJson("programming_rust.json"))
json.decodeFromString(getResource("post_details_tdfoqh.json"))
private val user: User = json.decodeFromString(getResource("msfjarvis.json"))
val api = controller.api
@@ -39,7 +38,12 @@ class ApiWrapper(controller: EitherNetController<LobstersApi>) {
controller.enqueue(LobstersApi::getHottestPosts) { success(hottest) }
controller.enqueue(LobstersApi::getPostDetails) { success(postDetails) }
controller.enqueue(LobstersApi::getUser) { success(user) }
controller.enqueue(LobstersApi::getPostsByTags) { success(metaPosts) }
controller.enqueue(LobstersApi::getPostsByTags) { success(programmingRustPosts) }
controller.enqueue(LobstersApi::getCSRFToken) {
success(
CSRFTokenConverter.convert(
ResponseBody.create(MediaType.get("text/html"), getResource("csrf_page.html"))
)
)
}
}
}
@@ -0,0 +1,59 @@
/*
* 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.api
import com.google.common.truth.Truth.assertThat
import com.slack.eithernet.ApiResult
import com.slack.eithernet.test.newEitherNetController
import dev.msfjarvis.claw.model.LobstersPost
import dev.msfjarvis.claw.model.User
import dev.msfjarvis.claw.util.TestUtils.assertIs
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
class SearchApiTest {
private val wrapper = SearchApiWrapper(newEitherNetController())
private val api
get() = wrapper.api
@Test
fun `search is able to parse HTML`() = runTest {
val posts = api.searchPosts("ChatGPT", 1)
assertIs<ApiResult.Success<List<LobstersPost>>>(posts)
assertThat(posts.value).containsAtLeastElementsIn(results).inOrder()
assertThat(posts.value).hasSize(20)
}
private companion object {
private val results =
listOf(
LobstersPost(
shortId = "gjlsdg",
title = "ChatGPT visits the Emacs doctor",
url = "https://xenodium.com/chatgpt-visits-the-emacs-doctor/",
createdAt = "",
commentCount = 3,
commentsUrl = "https://lobste.rs/s/gjlsdg/chatgpt_visits_emacs_doctor",
submitter = User("xenodium", "", null, "/avatars/xenodium-16.png", ""),
tags = listOf("ai", "emacs"),
description = "",
),
LobstersPost(
shortId = "astcqf",
title =
"Implementing a question-answering system for PDF documents using ChatGPT and Redis",
url = "https://mstack.nl/blog/20230623-chatgpt-question-pdf-document/",
createdAt = "",
commentCount = 0,
commentsUrl = "https://lobste.rs/s/astcqf/implementing_question_answering_system",
submitter = User("asteroid", "", null, "/avatars/asteroid-16.png", ""),
tags = listOf("ai"),
description = "",
),
)
}
}
@@ -0,0 +1,29 @@
/*
* 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.api
import com.slack.eithernet.ApiResult.Companion.success
import com.slack.eithernet.test.EitherNetController
import com.slack.eithernet.test.enqueue
import dev.msfjarvis.claw.api.converters.SearchConverter
import dev.msfjarvis.claw.util.TestUtils.getResource
import okhttp3.MediaType
import okhttp3.ResponseBody
class SearchApiWrapper(controller: EitherNetController<LobstersSearchApi>) {
val api = controller.api
init {
controller.enqueue(LobstersSearchApi::searchPosts) {
success(
SearchConverter.convert(
ResponseBody.create(MediaType.get("text/html"), getResource("search_chatgpt_page.html"))
)
)
}
}
}
@@ -1,18 +1,27 @@
/*
* 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.util
import com.google.common.truth.Truth.assertThat
import java.io.File
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@OptIn(ExperimentalContracts::class)
object TestUtils {
fun getJson(path: String): String {
fun getResource(path: String): String {
// Load the JSON response
val uri = javaClass.classLoader.getResource(path)
val uri = javaClass.classLoader!!.getResource(path)
val file = File(uri.path)
return String(file.readBytes())
}
inline fun <reified T> assertIs(value: Any?) {
contract { returns() implies (value is T) }
assertThat(value).isInstanceOf(T::class.java)
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More