New lint rules highlighted a potential crash; the use of named match
groups (used here when extracting server versions) requires API >= 26 or
throws an exception.
Use the group numbers instead of names when extracting the value, but
keep the group names in the regular expressions for readability.
The previous code used synchronous (i.e., non-suspending) functions to
call the /api/v2/search and /api/v2/accounts/search endpoints.
This is not necessary as the search was always performed in a separate
thread.
Remove, and replace their usage with the equivalent functions that
suspend.
Once desugaring is enabled it needs to be enabled for up/down the
dependency chain, so enable it in the shared configuration defined by
the build convention code.
Highlighted a failing test that wasn't being run, so fix that too.
A filter's context (previously referred to as its `kind`) controls where
the filter is applied.
This was implemented as an enum with a specific property to control how
it would serialise when @FormUrlEncoded, and with a @Json annotation for
Moshi.
In addition, the model objects kept the filter context in its string
form throughout Pachli, requiring periodic conversion to/from the enum
type, making the code more complicated.
Fix this, by:
1. Converting the incoming JSON value to the enum type immediately, so
the rest of the code uses the enum constants exclusively.
2. Implement a Retrofit converter that serialises the enum value when
@FormUrlEncoded to the same string used in JSON serialisation
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.
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.
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.
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
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.
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`.
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
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
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.
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`.
- 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
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
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.
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.