Chooser dialog could start before any accounts have loaded. Fix by
collecting the account flow and waiting for the first emission (convert
the flow to shared instead of state so there's no initial empty list).
Guard against the potential for a similar issue when fetching
notifications.
Order the list of accounts with active account first so that code that
skips it by ignoring the first item works correctly.
Continue the work to remove the "activeAccount" idiom.
- Uses a new PachliAccount type through most of the app. This holds
information that was previously accessed separately (e.g., content
filters, lists) in one place. The information is loaded when the app
launches or the active account switches.
- Fetching data when the account is switched / loaded simplifies error
handling, as more code can now assume the data has already been loaded.
If it hasn't the code path is simply unreachable.
- This opens up the possibility of "acting as one account while logged
in as another". E.g., have two accounts, and be logged in to one account
and boost a post you've seen from your other account.
- Add a database migration to populate existing accounts with default
data when the user updates the app.
- Refactor code that used those list and filter repositories to get the
data from the PachliAccount instead. New local and remote data sources
are implemented, and the list and filter repositories mediate between
those sources.
- Start a ViewModel for MainActivity, which includes:
- Sending user actions as UiAction objects
- Providing a flow of uiState for MainActivity to react to
- Remove most uses of SharedPreferencesRepository from MainActivity
- Show messages about errors that occur when logging in
- Refactor intent routing in MainActivity to make the logic clearer.
- Add new `core.data` types to push more `core.network` types out of the
UI code
- `core.data.model.MastodonList` for `core.network.model.MastoList`
- `core.data.model.Server` for `core.network.model.Server`
- Continue the work to send the Pachli account ID to the code that uses
it.
- Most view models now get the account ID via assisted injection.
- QueuedMedia now includes the AccountEntity so it can operate with any
account. Modify the `uploadMedia` API call to include explicit
authentication details.
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Previous code assumed the active account could always be determined from
the account manager.
This causes a few problems.
1. The account manager has to handle the case where there is no active
account (e.g., the user is logging out of the last account). This meant
the `activeAccount` property had to be nullable, so every consumer of
that property either used it with a `let` or `!!` expression.
2. The active account can change over the life of the UI component, for
example, when the user is switching accounts. There's a theoretical race
condition where the UI component has started an operation for one
account, then the account changes and the network authentication code
uses the new account.
3. All operations assume they operate on whatever the active account is,
making it difficult to provide any features that allow the user to
temporarily operate as another account ("Boost as...", etc).
This "ambient account" was effectively global mutable state, with all
the problems that can cause.
Start to fix this. The changes in this commit do not fix the problem
completely, but they are some progress.
Each activity (except LoginActivity) is expected to be launched with an
intent that includes the ID of the Pachli account it defaults to
operating with. This is `pachliAccountId`, and is the *database ID*
(not the server ID) of the account. This is non-null, which removes one
class of bugs.
This account is passed to each fragment and any piece of code that has
to perform an operation on behalf of this account. It's not used in
most of those places yet, that will be done over a number of followup
PRs as part of modernising each module.
Provde an `appTheme` property in `SharedPreferenceRepository` to manage
read access, simplifying calling code.
Update `PreferenceEnum.from` to check the `value` property of the enum
first.
Fixes#950
Previous code depended on, but did not initialise, the androidx
splashscreen library.
Fix that, using the library on API < 31, or the platform implementation
otherwise.
`SplashActivity` is no longer needed, launching goes straight in to
`MainActivity`.
Version 1.2.0-alpha01 is needed to fix some theme corruption bugs in
earlier versions of the library.
Previous code always included the transitionKind enum as an extra, and
could cause a crash if the activity launched by the intent was not a
Pachli activity.
Fixes#700.
Previous code used a single animation type (slide) when transitioning,
the transition was quite slow, and didn't behave appropriately if the
device was set to a RTL writing system.
In addition, handling the back affordance didn't work well with the new
"Predictive Back" feature in Android 14
(https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture).
Fix this.
## Transitions
To update the transitions the `startActivityWithSlideInAnimation()`
implementation (and associated `finishWithoutSlideOutAnimation()`) have
been replaced.
There are three transitions; `default`, `slide`, and `explode`,
represented as an enum passed to the activity intent.
The `default` transition is the activity transition from Android 14,
from the Android open source project
(https://cs.android.com/android/platform/superproject/+/android-14.0.0_r18:frameworks/base/core/res/res/anim/;bpv=1).
This is used for most transitions.
The `slide` transition is the pre-existing slide transition, with a
shorter transition time so it feels more responsive, and an RTL
implementation. This is used when there is a strong spatial component to
the navigation, for example, when going from:
- a status to its thread
- a preference menu item to its subscreen
- a filter in a list to the "edit filter" screen
- viewing your profile to editing your profile
The `explode` transition is used when the state of the app changes
significantly, such as when switching accounts.
Activities are now started with `startActivityWithTransition()` which
sets the intent and prepares the transition. `BaseActivity` checks the
intent for the transition type and makes further changes to the
transition as necessary.
## Predictive back
"Predictive back" needs to know what the back button would do before the
user interacts with it with an `onBackPressedCallback` that is either
enabled or disabled. This required refactoring some code (particularly
in `ComposeActivity`) to gather data ahead of time and enable/disable
the callback appropriately.
## Fixed bugs
- Back button wasn't stepping back through the tabs in AccountActivity
- Modifying a filter and pressing back without saving wasn't prompting
the user to save the changes
- Writing a content warning and then hiding it would still count the
text of the content warning toward's the post's length
## Other cleanups
- Use `ViewCompat.setTransitionName()` instead of setting the
`transitionName` property
- Delete the unused `fade_in` and `fade_out` animations.
- Use androidx-activity 1.9.0 to get the latest predictive back support
library code
- Show validation errors when creating / editing filters
Previous code showed a small icon for account media that the user has
hidden.
Now determine the correct size / aspect ratio for the media and use that
to compute the placeholder (either a blurhash, or the link colour for
consistency with the view on a timeline).
Fixes#513
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.
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
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.