Commit Graph

357 Commits

Author SHA1 Message Date
Nik Clayton d943fa1aca
fix: Update InstanceV1/V2 related types based on real-world usage (#476)
Many servers that claim to be Mastodon-API compatible are not, as
evidenced by the content they include in the responses to
`/api/v1/instance` and `/api/v2/instance` requests.

Work around the worst of the breakage by providing defaults or marking
some fields as nullable (with a default null).

Bugs have been reported against the relevant projects.
2024-02-28 00:02:03 +01:00
Nik Clayton f5d90081ff
fix: Provide v2/instance configuration defaults (#474)
Some servers don't include a `urls` or `translation` block, which was
preventing parsing of the block, and falling back to the v1 instance
data.

Fix this by providing sensible defaults.
2024-02-26 17:21:33 +01:00
Martijn de Boer 6ca085089e fix(l10n): Update Dutch translations
Currently translated at 100.0% (4 of 4 strings)

Translation: Pachli/Core/Activity : Main
Translate-URL: https://hosted.weblate.org/projects/pachli/coreactivity-main/nl/
2024-02-25 15:53:32 +01:00
Martijn de Boer be245ab2c4 fix(l10n): Update Dutch translations
Currently translated at 100.0% (4 of 4 strings)

Translation: Pachli/Core/Network : Main
Translate-URL: https://hosted.weblate.org/projects/pachli/corenetwork-main/nl/
2024-02-25 15:53:32 +01:00
Nik Clayton 51c64a74dc
fix: Parse roles without a `highlighted` property (#467)
The `highlighted` property on a role may be absent. If it is this breaks
account parsing, including accounts in an /api/v2/instance response.
This, in turn, breaks determining server capabilities, including whether
or not translation is supported.

Set the default to `true`, which matches observed Mastodon behaviour.
2024-02-22 21:17:34 +01:00
Nik Clayton 2162e03e1f
fix: Handle JSON enums with unknown values (#462)
Previous code expected all incoming enums values to map directly to
Kotlin enum constants.

This is a problem for servers with additional features -- e.g.,
"reaction" as a notification type.

Fix this with a new Moshi adapter that will set the incoming value to a
given constant if it's not recognised.

Apply this to the enum constants in core.network to ensure they are
handled.

Clean up enum handling in Converters.kt, ComposeViewModel.kt, and
Status.kt by using the existing `.ordinal` property and some extension
functions for idiomatic code.

Fixes #461
2024-02-21 23:36:24 +01:00
Nik Clayton 941f4677eb
fix: Show previews for playable audio media from accounts (#460)
Previous code showed a generic placeholder for audio media on the
account's "Media" tab.

Fix this so the preview image is shown (if it's available).

- Move the "is this attachment previewable?" code to `Attachment` so it
can be reused here.

- Restructure the logic in `AccountMediaGridAdapter` to use the new
`isPreviewable()` method when deciding whether to show a preview.

- Attachments have dedicated placeholder drawables, use those when the
preview is not available.
2024-02-20 16:20:34 +01:00
Nik Clayton 8293e90b73
feat: Allow the user to trigger update checks (#458)
Add an additional preference entry that triggers an update when tapped.
It also displays the earliest time of the next automatic update check as
the preference summary.

Move the code that performs the update check (and the logic for whether
to perform the check) out of `MainActivity` and in to `UpdateCheck` so
it's available from `PreferencesFragment`.
2024-02-20 14:50:59 +01:00
Nik Clayton 13cfa1a15d
fix: Remove filters from Firefish capabilities (#459)
Firefish doesn't support the filters API, so remove filters from the
list of capabilities.

Fixes #248
2024-02-20 14:41:48 +01:00
Nik Clayton 73c947edfa
fix: Prevent crash when Friendica returns a null `voted_on` property (#456)
Friendica can return a null `voted_on` property, in violation of the API
spec.

Introduce a `BooleanIfNull` annotation that will convert the `null` to
`false` if encountered.

While I'm here update the other adapters as classes on their relevant
annotations instead of standalone classes to keep the code consistent.

Fixes #455
2024-02-19 19:04:29 +01:00
Nik Clayton 23e3cf1035
feat: Show information about notification fetches on "About" screen (#454)
Some users report that Pachli is not retrieving/displaying notifications
in a timely fashion.

To assist in diagnosing these errors, provide an additional set of tabs
on the "About" screen that contain information about how Pachli is
fetching notifications, and if not, why not.

Allow the user to save notification related logs and other details to a
file that can be attached to an e-mail or bug report.

Recording data:

- Provide a `NotificationConfig` singleton with properties to record
different aspects of the notification configuration. Update these
properties as different notification actions occur.

- Store logs in a `LogEntryEntity` table. Log events of interest with a
new `Timber` `LogEntryTree` that is planted in all cases.

- Add `PruneLogEntryEntityWorker` to trim saved logs to the last 48
hours.

Display:

- Add a `NotificationFragment` to `AboutActivity`. It hosts two other
fragments in tabs to show details from `NotificationConfig` and the
relevant logs, as well as controls for interacting with them.

Bug fixes:

- Filter out notifications with a null tag when processing active
notifications, prevents an NPE crash

Other changes:

- Log more details when errors occur so the bug reports are more helpful
2024-02-17 15:57:32 +01:00
JuanM 55ee447bdb fix(l10n): Update Spanish translations
Currently translated at 100.0% (3 of 3 strings)

Translation: Pachli/Core/Activity : Orange
Translate-URL: https://hosted.weblate.org/projects/pachli/coreactivity-orange/es/
2024-02-17 10:01:04 +01:00
JuanM 086d6bc85e fix(l10n): Update Spanish translations
Currently translated at 100.0% (4 of 4 strings)

Translation: Pachli/Core/Activity : Main
Translate-URL: https://hosted.weblate.org/projects/pachli/coreactivity-main/es/
2024-02-17 10:01:04 +01:00
JuanM 0f13db8fb2 fix(l10n): Update Spanish translations
Currently translated at 75.0% (3 of 4 strings)

Translation: Pachli/Core/Network : Main
Translate-URL: https://hosted.weblate.org/projects/pachli/corenetwork-main/es/
2024-02-17 10:01:04 +01:00
Nik Clayton b3978c4af7
change: Move CustomFragmentStateAdapter to core.activity (#452) 2024-02-16 20:56:00 +01:00
Nik Clayton 4dbf6065fd
change: Move RefreshableFragment to core.activity (#450) 2024-02-16 19:58:11 +01:00
Nik Clayton 11bf47e3b3
fix: Handle null properties in `Attachment.Focus` (#449)
The `x` and `y` properties in `Attachment.Focus` may be null (not
documented as such, but observed in the wild).

Provide a `DefaultIfNull` adapter that can be applied to these to
replace null values with a sensible default.
2024-02-15 20:32:22 +01:00
Nik Clayton b8ac1f3944
fix: Show correct account/timeline when composing from notifications (#445)
The previous code didn't clear the task stack or recreate `MainActivity`
when the active user was changed.

So if the user was logged in with account A and used "Compose" from a
notification sent to account B, the active account was switched to B but
the UI chrome wasn't. After exiting `ComposeActivity` they would be
looking at the timeline for account B but with a toolbar that showed
account A.

Fix this by clearing the task stack and explicitly recreating
`MainActivity` when forwarding intents to `ComposeActivity`.
2024-02-15 13:10:00 +01:00
Nik Clayton 6c33204569
fix: Prevent crashes with bugs in Friendica and Pleroma servers (#441)
Neither server type implements the Mastodon API correctly, see

- https://github.com/friendica/friendica/issues/13887
- https://git.pleroma.social/pleroma/pleroma/-/issues/3238

Prevent crashes when parsing their broken JSON by providing default
values for properties they omit.

Fixes #433
2024-02-14 12:36:06 +01:00
Nik Clayton 2d03e6cf7b
change: Move AlertDialogExtensions to core.ui (#438) 2024-02-14 11:26:28 +01:00
Nik Clayton 96474a9ac3
change: Improve logging calls to Timber (#430)
- Use format strings so any overhead of building the string is only
incurred if the message is actually logged

- Pass throwables as the first parameter so they are logged with the
stacktrace
2024-02-09 17:33:01 +01:00
Nik Clayton a3d45ca9ec
refactor: Convert from Gson to Moshi (#428)
Moshi is faster to decode JSON at runtime, is actively maintained, has a
smaller memory and method footprint, and a slightly smaller APK size.
Moshi also correctly creates default constructor arguments instead of
leaving them null, which was a source of `NullPointerExceptions` when
using Gson.

The conversion broadly consisted of:

- Adding `@JsonClass(generateAdapter = true)` to data classes that
marshall to/from JSON.

- Replacing `@SerializedName(value = ...)` with `@Json(name = ...)`.

- Replacing Gson instances with Moshi in Retrofit, Hilt, and tests.

- Using Moshi adapters to marshall to/from JSON instead of Gson `toJson`
/ `fromJson`.

- Deleting `Rfc3339DateJsonAdapter` and related code, and using the
equivalent adapter bundled with Moshi.

- Rewriting `GuardedBooleanAdapter` as a more generic `GuardedAdapter`.

- Deleting unused ProGuard rules; Moshi generates adapters using code
generation, not runtime reflection.

The conversion surfaced some bugs which have been fixed.

- Not all audio attachments have attachment size metadata. Don't show
the attachment preview if the metadata is missing.

- Some `throwable` were not being logged correctly.

- The wrong type was being used when parsing the response when sending a
scheduled status.

- Exceptions other than `HttpException` or `IoException` would also
cause a status to be resent. If there's a JSON error parsing a response
the status would be repeatedly sent.

- In tests strings containing error responses were not valid JSON.

- Workaround Mastodon a bug and ensure `filter.keywords` is populated,
https://github.com/mastodon/mastodon/issues/29142
2024-02-09 12:41:13 +01:00
Nik Clayton d01c72b7d7
change: Disable SyntheticAccessor lint rule (#424)
Does not appear to be adding value, and R8 optimises the code to remove
the generated accessors.
2024-02-06 19:51:37 +01:00
Nik Clayton 41c702fc1b
change: Display "About" information in tabs (#420)
Previously, `AboutActivity` had buttons and links to show the privacy
policy and licenses of dependencies.

Change this to a selection of fragments in tabs, one tab each for:

- General "About" information
- Licenses
- Privacy Policy

The information shown hasn't changed, but this lays the groundwork for
including additional tabs in the future for information like server
rules, detected capabilities, or troubleshooting information.
2024-02-06 00:43:26 +01:00
Kalle Kniivilä 29538576d6 fix(l10n): Update Finnish translations
Currently translated at 100.0% (4 of 4 strings)

Translation: Pachli/Core/Activity : Main
Translate-URL: https://hosted.weblate.org/projects/pachli/coreactivity-main/fi/
2024-02-05 14:18:34 +01:00
Nik Clayton 54d7888316
feat: Include extra logs in error reports from orange release builds (#414)
Release builds normally strip out all logging to reduce the number of
disk writes and reduce UI jank.

These logs would still be useful in user error reports from orange
builds. To preseve them:

- Implement a simple `RingBuffer`.

- Create `TreeRing`, a `Timber` `Tree` logger that logs to a
`RingBuffer` instance in orange release builds.

- Create `TreeRingCollector`, called when ACRA reports are generated,
which includes the contents of the ring buffer in the report.

- Enable desugaring to allow the use of java.time libraries on older
Android versions.

- Disable ProGuard obfuscation of class names as the obfuscation adds
additional de-obfuscation steps when handling error reports from users.
2024-02-04 15:17:46 +01:00
ButterflyOfFire 93595a04d3 fix(l10n): Update Arabic translations
Currently translated at 66.6% (2 of 3 strings)

Translation: Pachli/Core/Activity : Orange
Translate-URL: https://hosted.weblate.org/projects/pachli/coreactivity-orange/ar/
2024-02-03 15:26:43 +01:00
Languages add-on c0303fb76c feat(l10n): Added Chinese (Simplified) (zh_MO) translation 2024-02-03 15:26:43 +01:00
Languages add-on 91a615e767 feat(l10n): Added Chinese (Simplified, Singapore) translation 2024-02-03 15:26:43 +01:00
Languages add-on a27787422b feat(l10n): Added Berber translation 2024-02-03 15:26:43 +01:00
Languages add-on 1a239d22c7 feat(l10n): Added Norwegian Bokmål translation 2024-02-03 15:26:43 +01:00
Languages add-on 4f19ec0e22 feat(l10n): Added Bengali (Bangladesh) translation 2024-02-03 15:26:43 +01:00
Languages add-on fcefb700ad feat(l10n): Added Sanskrit translation 2024-02-03 15:26:43 +01:00
Languages add-on 82248a86d8 feat(l10n): Added Kabyle translation 2024-02-03 15:26:43 +01:00
Languages add-on 66a96256c8 feat(l10n): Added Chinese (Simplified) translation 2024-02-03 15:26:43 +01:00
Languages add-on 8d5ee0056c feat(l10n): Added Chinese (Traditional) translation 2024-02-03 15:26:43 +01:00
Languages add-on e318c47887 feat(l10n): Added Kurdish (Central) translation 2024-02-03 15:26:43 +01:00
Languages add-on 248df881da feat(l10n): Added Portuguese (Portugal) translation 2024-02-03 15:26:43 +01:00
Languages add-on dbddd0a1c3 feat(l10n): Added Slovenian translation 2024-02-03 15:26:43 +01:00
Languages add-on 5aba014fce feat(l10n): Added Sinhala translation 2024-02-03 15:26:43 +01:00
Languages add-on ddaa2ef853 feat(l10n): Added Slovak translation 2024-02-03 15:26:43 +01:00
Languages add-on 1f9471afdd feat(l10n): Added Korean translation 2024-02-03 15:26:43 +01:00
Languages add-on a96e050314 feat(l10n): Added Persian translation 2024-02-03 15:26:43 +01:00
Languages add-on 11874d157b feat(l10n): Added Frisian translation 2024-02-03 15:26:43 +01:00
Languages add-on 2badc4bfaf feat(l10n): Added French translation 2024-02-03 15:26:43 +01:00
Languages add-on 66f1f6e7c9 feat(l10n): Added Spanish translation 2024-02-03 15:26:43 +01:00
Languages add-on 20c102df33 feat(l10n): Added Bengali (India) translation 2024-02-03 15:26:43 +01:00
Languages add-on 5bdbfba751 feat(l10n): Added Indonesian translation 2024-02-03 15:26:43 +01:00
Languages add-on 6a3540cead feat(l10n): Added Italian translation 2024-02-03 15:26:43 +01:00
Languages add-on 4a5a8c3075 feat(l10n): Added Polish translation 2024-02-03 15:26:43 +01:00
Languages add-on 43814b2b29 feat(l10n): Added Malayalam translation 2024-02-03 15:26:43 +01:00
Languages add-on e8a6066328 feat(l10n): Added Hebrew translation 2024-02-03 15:26:43 +01:00
Languages add-on eaafe2e40e feat(l10n): Added Hindi translation 2024-02-03 15:26:43 +01:00
Languages add-on db0fc5f5a3 feat(l10n): Added Hungarian translation 2024-02-03 15:26:43 +01:00
Languages add-on b7e1f3d504 feat(l10n): Added English (United Kingdom) translation 2024-02-03 15:26:43 +01:00
Languages add-on 0581fd0dae feat(l10n): Added Icelandic translation 2024-02-03 15:26:43 +01:00
Languages add-on 81bcde2609 feat(l10n): Added Vietnamese translation 2024-02-03 15:26:43 +01:00
Languages add-on 57b1f63d8e feat(l10n): Added Czech translation 2024-02-03 15:26:43 +01:00
Languages add-on 9ce1e98742 feat(l10n): Added Welsh translation 2024-02-03 15:26:43 +01:00
Languages add-on ba25f9c5f3 feat(l10n): Added Catalan translation 2024-02-03 15:26:43 +01:00
Languages add-on 8b547b9323 feat(l10n): Added Odia translation 2024-02-03 15:26:43 +01:00
Languages add-on 53122e43ca feat(l10n): Added Occitan translation 2024-02-03 15:26:43 +01:00
Languages add-on 2c1eb7bd0d feat(l10n): Added Japanese translation 2024-02-03 15:26:43 +01:00
Languages add-on aebf894ee2 feat(l10n): Added Ukrainian translation 2024-02-03 15:26:43 +01:00
Languages add-on 3bf38d6038 feat(l10n): Added Bulgarian translation 2024-02-03 15:26:43 +01:00
Languages add-on 3059094ef0 feat(l10n): Added Belarusian translation 2024-02-03 15:26:43 +01:00
Languages add-on 53d8faa8f0 feat(l10n): Added Russian translation 2024-02-03 15:26:43 +01:00
Languages add-on f848921b97 feat(l10n): Added Basque translation 2024-02-03 15:26:43 +01:00
Languages add-on 0cedbefc2c feat(l10n): Added Esperanto translation 2024-02-03 15:26:43 +01:00
Languages add-on 1400983b17 feat(l10n): Added Greek translation 2024-02-03 15:26:43 +01:00
Languages add-on 541cef27cf feat(l10n): Added German translation 2024-02-03 15:26:43 +01:00
Languages add-on bbc61db586 feat(l10n): Added Chinese (Traditional, Hong Kong) translation 2024-02-03 15:26:43 +01:00
Languages add-on 6f53873fac feat(l10n): Added Tamil translation 2024-02-03 15:26:43 +01:00
Languages add-on ea5de3e0cc feat(l10n): Added Thai translation 2024-02-03 15:26:43 +01:00
Languages add-on a76897fd87 feat(l10n): Added Latvian translation 2024-02-03 15:26:43 +01:00
Languages add-on 164b9ccd39 feat(l10n): Added Turkish translation 2024-02-03 15:26:43 +01:00
Languages add-on b8a78bd7fa feat(l10n): Added Galician translation 2024-02-03 15:26:43 +01:00
Languages add-on 135bb3e729 feat(l10n): Added Irish translation 2024-02-03 15:26:43 +01:00
Languages add-on a4646de9e5 feat(l10n): Added Gaelic translation 2024-02-03 15:26:43 +01:00
bittin1ddc447d824349b2 2f32b6e0f3 fix(l10n): Update Swedish translations
Currently translated at 100.0% (4 of 4 strings)

Translation: Pachli/Core/Activity : Main
Translate-URL: https://hosted.weblate.org/projects/pachli/coreactivity-main/sv/
2024-02-03 15:26:43 +01:00
bittin1ddc447d824349b2 0c4d182b2b fix(l10n): Update Swedish translations
Currently translated at 100.0% (4 of 4 strings)

Translation: Pachli/Core/Network : Main
Translate-URL: https://hosted.weblate.org/projects/pachli/corenetwork-main/sv/
2024-02-03 15:26:43 +01:00
Nik Clayton 1488c13c42
feat: Allow the user to send an error report without a crash (#406)
Getting error reports with logs of strange behaviour is useful even if
the app doesn't crash.

Move crash reporting in to `core.activity`, and provide a menu option
(in orange builds) to trigger a non-fatal crash report that is handled
the same way (i.e., sent by e-mail) as a regular crash report.

`BaseActivity` has to be able to create and handle menus, so adjust
subclasses to call the superclass when necessary.

Update `tools/mvstring` to be able to move strings between different
flavour directories, not just `main`.
2024-02-02 15:34:31 +01:00
Nik Clayton 86d800b1c8
refactor: Modularise "about" activities (#405)
Continue modularisation by moving activities in the "About" feature to a
new `feature.about` module.

Implement `feature.about:
- Move `AboutActivity`, `LicenseActivity`, and `PrivacyPolicyActivity`
here.
- Update `markdown2resource` plugin to work with libraries

Implement `core.data`:
- Types and repositories used through the app
- Move `InstanceInfo` and `InstanceInfoRepository` here so they are
available to `feature.about`.

Implement `core.ui`:
- App-specific views, spans, and other UI content
- Move `ClickableSpanTextView` and `NoUnderlineURLSpan` here so they are
available to `feature.about`.
2024-02-02 15:14:31 +01:00
Nik Clayton 7bf015432d
refactor: Remove unnecesary parcelize plugin import (#407) 2024-02-02 15:12:55 +01:00
Nik Clayton 4750ad78a7
chore(deps): update dependency com.gaelmarhic.quadrant to v1.9 (#400)
1.9 no longer needs the hardcoded "app.pachli" in the class names.
2024-01-30 16:40:11 +01:00
Weblate (bot) 1925860731
fix(l10n): Translations update from Hosted Weblate (#397)
Translations update from [Hosted Weblate](https://hosted.weblate.org)
for [Pachli/Fastlane
Metadata](https://hosted.weblate.org/projects/pachli/fastlane-metadata/).


It also includes following components:

* [Pachli/App](https://hosted.weblate.org/projects/pachli/ui-strings/)

* [Pachli/Feature -
Login](https://hosted.weblate.org/projects/pachli/feature-login/)

* [Pachli/F-Droid](https://hosted.weblate.org/projects/pachli/f-droid/)

* [Pachli/Core -
Network](https://hosted.weblate.org/projects/pachli/core-network/)

* [Pachli/Core - Design
System](https://hosted.weblate.org/projects/pachli/core-design-system/)

* [Pachli/Core -
Activity](https://hosted.weblate.org/projects/pachli/core-activity/)

* [Pachli/Google](https://hosted.weblate.org/projects/pachli/google/)

* [Pachli/GitHub](https://hosted.weblate.org/projects/pachli/github/)



Current translation status:

![Weblate translation
status](https://hosted.weblate.org/widget/pachli/fastlane-metadata/horizontal-auto.svg)

---------

Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2024-01-30 16:39:45 +01:00
Nik Clayton 358af13dfb
chore: Remove obsolete LicenseCard code (#399)
Unnecessary since the use of `aboutlibraries`
2024-01-30 16:39:19 +01:00
Nik Clayton f0fc0fd530
refactor: Modularise core activity classes, (#393)
Continue modularisation by moving core activity classes that almost all
activities depende on to a `core.activity` module. This includes
core "helper" classes as well.

Implement core.activity:
- Contains BaseActivity, BottomSheetActivity
- Contains LinkHelper and other utility classes used by activities

Implement core.common.extensions:
- Move ViewBindingExtensions and ViewExtensions here

Implement core.common.util:
- Move BlurHashDecoder and VersionName here

Implement core.designsystem:
- Holds common resources (animations, colours, drawables, etc) used
  through the app
- Import "core.designsystem.R as DR" through the app to distinguish
  from the module's own resources

Implement feature.login:
- Move the LoginActivity and related code/resources to its own module

Implement tools/mvstring
- Moves string resources (and all translations) from one module to
  another
2024-01-30 11:37:00 +01:00
Nik Clayton 355244a8e2
refactor: Destructure maps for more idiomatic code (#388) 2024-01-26 12:32:45 +01:00
Nik Clayton fc81e8bad7
fix: Ensure actions happen against the correct status (#373)
Previously when the user interacted with a status the operation (reblog,
favourite, etc) travels through multiple layers of code, carrying with
it the position of the item in the list that the user operated on.

At some point the status is retrieved from the list using its position
so that the correct status ID can be used in the network operation.

If this happens while the list is also refreshing there's a possible
race condition, and the original status' position may have changed in
the list. Looking up the status by position to determine which status to
perform the action on may cause the action to happen on the wrong
status.

Fix this by passing the status' viewdata to any actions instead of its
position. This includes all the information necessary to make the API
call, so there is no chance of a race.

This is quite an involved change because there are three types of
viewdata:

- `StatusViewData`, used for regular timelines
- `NotificationViewData`, used for notifications, may wrap a status that
can be operated on
- `ConversationViewData`, used for conversations, does wrap a status

The previous code treated them all differently, which is probably why it
operated by position instead of type.

The high level fix is to:

1. Create an interface, `IStatusViewData`, that contains the data
exposed by any viewdata that contains a status.

2. Implement the interface in `StatusViewData`, `NotificationViewData`,
and `ConversationViewData`.

3. Change the code that operates on viewdata (`SFragment`,
`StatusActionListener`, etc) to be generic over anything that implements
`IStatusViewData`.

4. Change the code that handles actions to pass the viewdata instead of
the position.

Fixes #370
2024-01-26 12:15:27 +01:00
Nik Clayton 28afd2ed4d
feat: Add Firefish as a server with a Mastodon API (#381) 2024-01-25 00:58:15 +01:00
Nik Clayton 5cfe6d055b
fix: Improve parsing of Friendica (and other server) version formats (#376)
Previous code could return an error on Friendica version strings like
`2024.03-dev-1547`.

Fix this:

- Extend the list of explicitly supported servers to include Fedibird,
Friendica, Glitch, Hometown, Iceshrimp, Pixelfed, and Sharkey.

- Add version parsing routines for these servers.

- Test the version parsing routines fetching every server and version
seen by Fediverse Observer (~ 2,000 servers) and ensuring that the
server and version information can be parsed.

Improve the error message:

- Show the hostname with a `ServerRepository` error

Clean up the code:

- Remove the custom `resultOf` and `mapResult` functions, they have
equivalents in newer versions of the library (like `runSuspendCatching`)

Fixes #372
2024-01-23 20:27:25 +01:00
Nik Clayton fa2da5ae18
fix: Show display name in timelines, not the username (#377)
Commit 993b7469 inadvertently broke this by removing the @SerializedName
annotation, so the user's display name was always null and the UI fell
back to showing the username.

Fixes #371
2024-01-23 16:59:36 +01:00
Nik Clayton 42219875e9
fix: Disable filter functionality if unsupported by the server (#366)
The previous code unilaterally enabled filter functionality. Some
Mastodon-like servers -- like GoToSocial -- do not support filters, and
this resulted in user visible error messages when connecting to those
servers.

To fix this:

- Extend the set of supported server capabilities to include client and
server side filtering.

- Disable the filter preferences if the server does not support filters
and show a message explaining why it's disabled.

Extend the capabilities model to support this:

- Fetch server software name and version from the nodeinfo endpoints
(implementing the nodeinfo API and schema)

- Extend the use of kotlin-result to provide hierarchies of Error
classes and demonstrate how to chain errors and display more informative
messages without using exceptions.

Fixes #343
2024-01-18 21:44:30 +01:00
Nik Clayton 993b74691a
chore(deps): update plugin ktlint to v12.1.0 (#358) 2024-01-09 17:50:20 +01:00
Nik Clayton cc0be0318f
fix: Prevent crash if a trending tab is present (#330)
Old versions of the preference value could have been serialised without
the `_` in the name, so handle those specially.

Fixes #329
2023-12-17 07:01:56 +01:00
Nik Clayton fe8f84847b
fix: Prevent a crash if trending tags, links, or statuses are added to tabs (#323)
The previous code was serialising the `TabKind` enum without the `_`, so
when it was converted back to the enum name (which has a `_`) it failed
and immediately crashed.

Fixes #306
2023-12-14 12:25:03 +01:00
Nik Clayton 29f9273c01
fix: Show translated content when viewing a thread (#320)
If a status was part of a thread, and it was not the "detailed" status,
and it had been translated, then the view data was marked as "show the
translation". But the translation was not loaded, so the status content
appeared as empty.

Fix that by loading the translated content of all statuses in the thead
and ensure that the translated content is rendered.

Throw an `IllegalStateException` in debug builds to catch any future
occurrences of this.

Fixes #281
2023-12-13 17:18:07 +01:00
Nik Clayton e24ef0b52d
refactor: Use @MapColumn instead of @MapInfo (#319)
`@MapInfo` is deprecated, migrate to `@MapColumn`.
2023-12-13 16:44:50 +01:00
Nik Clayton 098983f401
fix: Calculate length of posts and polls with emojis correctly (#315)
Mastodon counts post lengths by considering emojis to be single
characters, no matter how many unicode code points they are composed of.
So "😜" has length 1.

Pachli was using `String.length`, which considers "😜" as length 2.

Correct the calculation by using a BreakIterator to count the characters
in the string, which treats multi-character emojis as a length 1.

Poll options had a similar problem, exacerbated by the Mastodon web UI
also having the same problem, see
https://github.com/mastodon/mastodon/issues/28336.

Fix that by creating `MastodonLengthFilter`, an `InputFilter` that does
the right thing for regular text that may contain emojis.

See also https://github.com/tuskyapp/Tusky/pull/4152, which has the fix
for status length but not polls.

---------

Co-authored-by: Konrad Pozniak <opensource@connyduck.at>
2023-12-12 16:53:09 +01:00
Nik Clayton cbecfa3117
feat: Show roles on profiles (#312)
Roles for the logged in user appeared in Mastodon 4.0.0 and can be
displayed on the user's profile screen.

Show them as chips, adjusting the display of the existing "Follows you"
and "Bot" indicators to make allowances for this.

Roles can have a custom colour assigned by the server admin. This is
blended with the app colour so it is not too jarring in the display.

See also https://github.com/tuskyapp/Tusky/pull/4029

Co-authored-by: Konrad Pozniak <opensource@connyduck.at>
2023-12-11 20:57:11 +01:00
Nik Clayton 60cfa99f17
refactor: Use AppTheme enum exclusively (#311)
Previous code treated the app theme as a mix of strings and enums.
Convert to exclusively use the `AppTheme` enum to improve type safety.
2023-12-11 14:41:36 +01:00
Nik Clayton 2a7eda667b fix: Prevent crash if a preview card does not have an author 2023-12-09 22:49:21 +01:00
Nik Clayton df45c0cd96 fix: Prevent crash showing profile if account has null `createdAt` field 2023-12-09 22:49:21 +01:00
Nik Clayton 1214cf7c8a
refactor: Break navigation dependency cycles with :core:navigation (#305)
The previous code generally started an activity by having the activity
provide a method in a companion object that returns the relevant intent,
possibly taking additional parameters that will be included in the
intent as extras.

E.g., if A wants to start B, B provides the method that returns the
intent that starts B.

This introduces a dependency between A and B.

This is worse if B also wants to start A.

For example, if A is `StatusListActivity` and B is`ViewThreadActivity`.
The user might click a status in `StatusListActivity` to view the
thread, starting `ViewThreadActivity`. But from the thread they might
click a hashtag to view the list of statuses with that hashtag. Now
`StatusListActivity` and `ViewThreadActivity` have a circular
dependency.

Even if that doesn't happen the dependency means that any changes to B
will trigger a rebuild of A, even if the changes to B are not relevant.

Break this dependency by adding a `:core:navigation` module with an
`app.pachli.core.navigation` package that contains `Intent` subclasses
that should be used instead. The `quadrant` plugin is used to generate
constants that can be used to launch activities by name instead of by
class, breaking the dependency chain.

The plugin uses the `Activity` names from the manifest, so when an
activity is moved in the future the constant will automatically update
to reflect the new package name.

If the activity's intent requires specific extras those are passed via
the constructor, with companion object methods to extract them from the
intent.

Using the intent classes from this package is enforced by a lint
`IntentDetector` which will warn if any intents are created using a
class literal.

See #291
2023-12-07 18:36:00 +01:00
Nik Clayton 2ce80c6a32
refactor: Use the correct package for TimelineKind (#303)
The package wasn't renamed when it was moved, so was still
`app.pachli.components.timeline`, instead of the new location,
`app.pachli.core.network.model`.
2023-12-06 12:20:36 +01:00
Nik Clayton e749b362ca
refactor: Start creating core modules (#286)
The existing code base is a single monolithic module. This is relatively
simple to configure, but many of the tasks to compile the module and
produce the final app have to run in series.

This is unnecessarily slow.

This change starts to split the code in to multiple modules, which are:

- :core:account - AccountManager, to break a dependency cycle
- :core:common - low level types or utilities used in many other modules
- :core:database - database types, DAOs, and DI infrastructure
- :core:network - network types, API definitions, and DI infrastructure
- :core:preferences - shared preferences definitions and DI
infrastructure
- :core:testing - fakes and rules used across different modules

Benchmarking with gradle-profiler shows a ~ 17% reduction in incremental
build times after an ABI change. That will improve further as more code
is moved to modules.

The rough mechanics of the changes are:

- Create the modules, and move existing files in to them. This causes a
  lot of churn in import arguments.

- Convert build.gradle files to build.gradle.kts

- Separate out the data required to display a tab (`TabViewData`) from
  the data required to configure a tab (`TabData`) to avoid circular
  dependencies.

- Abstract the repeated build logic shared between the modules in to
  a set of plugins under `build-logic/`, to simplify configuration of
  the application and library builds.

- Be explicit that some nullable types are non-null at time of use.
  Nullable properties in types imported from modules generally can't be
  smart cast to non-null. There's a detailed discussion of why this
restriction exists at
https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201.

The changes highlight design problems with the current code, including:

- The main application code is too tightly coupled to the network types
- Too many values are declared unnecessarily nullable
- Dependency cycles between code that make modularisation difficult

Future changes will add more modules.

See #291.
2023-12-04 16:58:36 +01:00