Previously media on the "Media" tab was displayed scaled and cropped to
a square aspect ratio, effectively forcing the user to tap every image
to see it.
Now, display the images scaled but not cropped, layed out with
`StaggeredGridLayoutManager`. This shows each image in full (still
scaled) providing a better experience when scrolling down.
Scrolling up can occasionally introduce gaps in the grid as images are
re-placed as viewholders are reused. When this happens images animate to
a better position when scrolling stops.
Previous code injected `ApplicationContext`, which is not themed, and
caused a crash if the "update" dialog was shown.
Fix by passing the necesssary context in explicitly when the check is
performed.
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`.
If the user increases the font size the labels for post statistics
(number of replies, etc) can crash in to each other.
To give more space for the text:
- Shrink the label font size
- Move the labels slightly left / tighter to the icon
- Allow the "bookmark" icon to move next to the "more" icon. There's
still 48dp of space for them, and this gives a little more space to the
other icons that have labels
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 previous code was using a bold version of the default font for
inserted text. So if the user had set a custom font it was being
ignored.
Fix this by creating a bold version of the user's typeface.
Fixes#435
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.
Content that doesn't start with a block element generates a parse error.
This isn't normally seen from Mastodon servers but is seen from content
from other servers (e.g,. Akkoma), which can generate:
```
<a href="..."> some text
```
instead of:
```
<p><a href="..."> some text</p>
```
Work around this by ensuring that content-to-be-diffed is wrapped in a
`div`.
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`.
Shortcuts were being updated using `MainActivity.this` as the `Context`
and leaking in `ShortcutManagerCompat`. Use the application context to
fix this.
When the `Notification.Type` enum was moved to a separate module it
resulted in exceptions trying to deserialize the enum:
```
java.lang.RuntimeException: Parcelable encountered ClassNotFoundException reading a Serializable object (name = app.pachli.core.network.model.Notification$Type)
```
This happened in debug builds without Proguard, so not a minification or
renaming issue.
Fix this by providing `putEnum`/`getEnum` extension functions on
`Bundle` that store the enum's ordinal value and restore it from that.
UnifiedPush broadcasts are used to trigger fetching new notifications.
Previously this was a normal one-time work request. Mark it as expedited
to increase the likelihood it will run soon.
- 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.
Previous code used `pull_request:` which meant
`secrets.GRADLE_ENCRYPTION_KEY` was not available, so the configuration
cache was not restored.
Use `pull_request_target` to give the workflow access to `secrets`, and
explicitly downscope the permissions of `GITHUB_TOKEN` to read only.