Mastodon now supports additional (optional) author information to show
as a byline on preview cards.
Use this (if included), to show the author's avatar, name, and link to
their profile. If tapped a click on a new `Target.BYLINE` target is
registered allowing fragments/activities to launch
`ViewProfileActivity`.
Include this as an action in `ListStatusAccessibilityDelegate`, and
provide `TrendingLinksAccessibilityDelegate` to provide accessibility
actions when viewing trending links.
Previous code did not provide whitespace between different media labels
when media is not loaded.
In addition, the icon for the media was centre-aligned vertically with
the text, making it difficult to scan and determine when one media label
ends and another one starts.
Fix this by adding an 8dp margin between the media labels, and using a
TextView subclass that vertically aligns the media icon with the first
line of text.
Set the compound drawables with relative alignment, so they behave
appropriately in RTL layouts.
Fixes#751.
Implement suggestions as a new `feature:suggestions` module, with
associated activity, fragment, etc.
Suggested accounts are shown with their normal information, as well as
information about the number of follows / followers, and a guide to
posting frequency, so the user can make a more informed decision about
whether to follow or not.
In the previous code `PachliError` could correctly chain errors and
generate error messages, `ApiError` didn't, which is why there was the
temporary `ApiError.fmt()` extension function.
Rewrite `ApiError` to implement `PachliError` so it gets these benefits
and to reduce the number of different error-handling mechanisms in the
code.
Main changes:
- `PachliError` is now an interface so it can be extended by other
error interfaces.
- All the `ApiError` subclasses implement `PachliError`, and can
specify the error string and interpolated variables at the point of
declaration.
- Update `ListsRepository` and `ServerRepository` to return
`PachliError` subclasses.
Previous code was inconsistent about using getServerErrorMessage() and
whether or not the case where getServerErrorMessage() returns null was
handled.
Switch to using getErrorString() which does handle the null case and
always returns a usable string.
Some string resources are rendered temporarily unused by this change.
They will be used again soon, so configure lint to ignore them at the
moment.
Use `unicodeWrap` when inserting placeholders in error messages so they
set the correct text direction.
Update some strings with formatting directives to (a) include `_fmt`
in the name, and (b) use `%1$s` instead of `%s`.
Previous code was inconsistent about how and when the FAB was hidden if
the user had set the relevant preference.
- Sometimes the FAB has hidden by setting the visibility to false, which
removed it with no animation.
- Sometimes the value of the preference was checked once, when the
fragment or activity was created.
- Some timelines didn't show the FAB (Hashtags, Favourites, Bookmarks,
TrendingLinks, TrendingStatuses).
- Logic for figuring out which `ComposeActivity` intent to use was
scattered across different files.
Improve this by:
- Expose changes to the `FAB_HIDE` preference in the relevant viewmodels
as a flow the UI component can collect.
- Centralise the show/hide logic in a new `ActionButtonScrollListener`
class, and always using `show()`/`hide()` to animate the transition.
- Centralise the logic for creating the `ComposeActivity` intent in
`TabViewData`.
Previous code would handle some expected exceptions (IO, HTTP) when
fetching a timeline, and show them to the user. Any other exception
would crash.
Now, surface all exceptions. Treat IO and HTTP exceptions as retryable
and show the "Retry" option, all others are considered non-retryable.
Provide a specific error string for exceptions caused by bad JSON.
Previous code used custom regular expressions to extract URLs, hashtags,
and mentions from text while the user was writing a post. These were
inconsistent with the ones that Mastodon uses so the derived character
count could be wrong.
As well as being visually incorrect this could prevent the user from
posting a status that was within the length limit, or allow them to
attempt to post a status that was over the length limit (which would
then fail).
Fix this by dropping the homegrown regular expressions and using the
same text parsing library that Mastodon users; twitter-text. This has
been converted to Kotlin and the functionality related to Twitter
specific features has been removed.
The hashtag handling has been adjusted, as Mastodon is more permissive
about the positions where hashtags can appear than Twitter is, in
particular, a hashtag does not need to be preceded with whitespace if
the tag appears after some scripts, such as Hirigana.
Previous code expected callers to typically provide the drawable and the
error message string resource, resulting in duplicate code at many
callsites.
Replace with three canned messages for empty containers, generic errors,
and network errors respectively. The images for these are fixed, the
caller may choose a different string resource for the error if there is
a more specific option.
Update and simplify the call sites.
Move `ListsActivity`, along with fragments and viewmodels, to a new
`feature:lists` module.
Previous code used the `item_follow_request` layout, which was not
ideal, so update it to use a dedicated layout, `item_account_in_list`.
The UI uses strings and views originally defined in the main app, so
move them elsewhere so they can be re-used.
- `BackgroundMessageView` moves to `core.ui`.
- `Lazy` moves to `core.common`.
- `ThrowableExtensions` split; the extensions specific to throwables
from network activity move to `core.network`, others move to `core.ui`.
- `BindingHolder` moves to `core.ui`
- Shared drawables and strings move to `core.ui`.
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
- 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
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.
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`.