* Fetch all outstanding Mastodon notifications when creating Android notifications
Previous code fetched the oldest page of unfetched Mastodon notifications.
If you had more than a page of Mastodon notifications you'd get Android notifications for that page, then ~ 15 minutes later Android notifications for the next page, and so on.
This code fetches all the outstanding notifications at once.
If this results in more than 40 total notifications the list is still trimmed so that a maximum of 40 Android notifications is displayed.
Fixes https://github.com/tuskyapp/Tusky/issues/3648
* Build the list using buildList
Don't use `accountManager.activeAccount` throughout the code.
Instead, get the active account once, and use that over the life of the viewmodel.
As shown in https://github.com/tuskyapp/Tusky/issues/3689#issuecomment-1567219338 the active account can change before the view model is destroyed, and if that happens account information for the account will be written to the wrong account.
Fix a bug where the active account can be overwritten.
1. Have two accounts logged in to Tusky, A and B
2. Open Tusky as account A
3. Send a DM to account B (doesn't have to be a DM, just anything that creates a notification for account B)
4. Restart Tusky so the Android notification for the DM is displayed immediately. You are still acting as account A.
5. Drag down the Android notification, you should see two options, "Quick reply" and "Compose"
6. Tap "Compose"
7. ComposeActivity will start. You are now acting as account B. Compose and send a reply
8. You'll be returned to the "Home" tab.
The UI will show you are still account A (i.e., it's account A's avatar at the top of the screen, if you have the "Show username in toolbars" option turned on it will be account A's username in the toolbar).
But you are now seeing the home timeline for account B.
Fix this.
ComposeViewModel
- Do not rely on the active account in sendStatus(), receive the account ID as a parameter
ComposeActivity
- Use either the account ID from the intent, or the current active account. **Do not** change the active account
- Pass the account ID to use in the sendStatus() call
The previous code gets the user's reading position *once*, when the
viewmodel is created, and uses that whenever it needs to be restored.
This is a problem. Suppose the user is a few days behind on their
notifications, and opens the app.
The reading position is restored, as expected. They scroll up to start
reading newer notifications.
Then they change their notification filters. This causes the
notifications list to change, and when it does their reading position
is set back to what it was when they first switched to the Notifications
tab.
Fix this by:
NotificationsFragment:
- Save the reading position whenever the user stops scrolling.
NotificationsViewModel:
- Use the saved reading position whenever the list of notifications
can change, not just when the view model is created.
Not all servers support the marker API. If they don't the user will
potentially get duplicate Android notifications.
To resolve this, store a copy of the notification marker ID locally as
well. Defer to the remote marker if it exists (and is newer than the
local marker).
Fixes https://github.com/tuskyapp/Tusky/issues/3671
When fetching:
- Maintain a marker with the position of the newest fetched notification
- Use the marker to determine which notifications to fetch
- Fetch notifications with min_id to ensure that none are lost
- Update the marker as necessary
- Perform a one-time immediate fetch of notifications on startup
When creating notifications:
- Identify each notification with tag=${MastodonNotificationId}, id=${account.id}
- Remove activeNotifications field, it's no longer necessary
- Use the tag/id tuple to reliably identify existing notifications and avoid creating duplicates
- Cancelling notifications for an account must iterate over all the notifications, and individually remove the notifications that exist for that account.
- Limit notifications to a maximum of 40 (excluding summary notifications)
- Remove notifications (oldest first) to get under this limit
- Rate limit notification creation to 1 per second, so the OS won't drop them
Adjust the summary notification:
- Ensure the summary notification and the child notifications have the same group key
- Dismiss the summary notification if there is only one child notification
NotificationClearBroadcastReceiver is no longer needed, so remove it, and the need for deletePendingIntent.
Fixes#3625, #3539
Currently translated at 98.0% (589 of 601 strings)
Translated using Weblate (Belarusian)
Currently translated at 95.0% (571 of 601 strings)
Co-authored-by: xzFantom <xzfantom@gmail.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/be/
Translation: Tusky/Tusky
Currently translated at 100.0% (601 of 601 strings)
Translated using Weblate (French)
Currently translated at 97.8% (588 of 601 strings)
Translated using Weblate (French)
Currently translated at 89.5% (538 of 601 strings)
Translated using Weblate (French)
Currently translated at 79.5% (478 of 601 strings)
Co-authored-by: codl <codl@codl.fr>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/fr/
Translation: Tusky/Tusky
- Add a field to AccountEntity to hold the reading position
- Provide a method to save in the viewmodel to save the position
- Save the position when TimelineFragment pauses
Does not restore the position yet.
Requesting a non-existent notification ID will cause the fall-back requests to succeed but return empty lists which stops pagination.
Check for this, and in the worst case, fall back to returning the most recent notifications.
On Account preferences > Filters
With the list hidden on an empty view the FAB is erroneouly placed on the top left of the screen.
(Introduced with #3430)
Add additional 6dp margin to the top of the username view, to provide more space after the "X <performed an action>" view, consistent with item_follow.xml.
The pageSize is large enough that there's no need for the default 3 x pageSize initialLoadSize value, and this improves performance.
Fixes https://github.com/tuskyapp/Tusky/issues/3578
This makes the notification view for a follow request contain more info about the new follower, and makes the layout (of their name / username) consistent with other notifications that show names/usernames.
Previous code would discard the image alt-text if the user finished writing the text before the image had finished uploading.
This code ensures the text is set after the image has completed uploading.
* Disable lint checks for unused resource IDs
The check doesn't catch some instances where resources are used through viewbinding, and has too many false positives to be useful.
* Regenerate lint baseline
Delete the existing file, then regenerated with `.\gradlew lintBlueDebug -Dlint.baselines.continue=true`
* 3503: SwipeRefreshLayout must be higher level
* 3503: Fix notifications view a bit
* 3503: Wrap recycler views and message views in the swipe-to-refresh if all are present
* 3416: Call the list activity when empty; show failure on loading
* 3416: Revert include grouping
* 3416: Remove faulty include after merge
* 3416: Added a list loading progress
* 3416: Add proper padding to progress
* 3416: Show a text if there are no lists, do not change dialog title
* 3416: Center things in layout
* 3416: Appease linter (?)
* 3416: Do not hide manage lists button
* 3416: Use ThemeUtils
Currently translated at 100.0% (600 of 600 strings)
Translated using Weblate (Galician)
Currently translated at 94.0% (564 of 600 strings)
Co-authored-by: XoseM <xosem@disroot.org>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/gl/
Translation: Tusky/Tusky
Currently translated at 95.5% (573 of 600 strings)
Translated using Weblate (Spanish)
Currently translated at 95.1% (571 of 600 strings)
Co-authored-by: Paul Sanz <registro@polkillas.net>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/es/
Translation: Tusky/Tusky
* 3434: Make description dialog (text field) more usable
* 3434: Close dialog on back button
* 3434: Use a TextInputLayout
* 3434: Adapt German plurals text
* 3434: Remove unused id
* 3434: Disable counter officially
Currently translated at 100.0% (598 of 598 strings)
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (598 of 598 strings)
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (597 of 597 strings)
Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/uk/
Translation: Tusky/Tusky
Currently translated at 100.0% (598 of 598 strings)
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (598 of 598 strings)
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (597 of 597 strings)
Co-authored-by: Hồ Nhất Duy <mastoduy@gmail.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/vi/
Translation: Tusky/Tusky
Currently translated at 100.0% (597 of 597 strings)
Translated using Weblate (Icelandic)
Currently translated at 95.8% (572 of 597 strings)
Co-authored-by: Sveinn í Felli <sv1@fellsnet.is>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/is/
Translation: Tusky/Tusky
Currently translated at 100.0% (598 of 598 strings)
Translated using Weblate (Persian)
Currently translated at 100.0% (597 of 597 strings)
Co-authored-by: Danial Behzadi <dani.behzi@ubuntu.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/fa/
Translation: Tusky/Tusky
* 3408: First draft of help message on empty home timeline
* 3408: Move image spanning to utils; tweak gui a bit (looks like status)
* 3408: Use proper R again; appease linter
* 3408: Add doc; remove narrow comment
* 3408: null is default
* 3408: Add German text
* 3408: Stack refresh animation on top of help message (reorder)
Currently translated at 100.0% (597 of 597 strings)
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (597 of 597 strings)
Co-authored-by: Eric <alchemillatruth@purelymail.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/zh_Hans/
Translation: Tusky/Tusky
Currently translated at 91.1% (543 of 596 strings)
Translated using Weblate (Latvian)
Currently translated at 90.7% (541 of 596 strings)
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/lv/
Translation: Tusky/Tusky
* Show better errors with notification loading fails
The errors are returned as a JSON object, parse it, and show the error
message it contains.
Handle the cases where there might be no error message, or the JSON may be
malformed.
Add tests.
Fixes#3445
* Lint
* Show reblog/favourite confirmations as menus not dialogs
The previous code used dialogs and displayed the text of the status when
reblogging or favouriting.
This didn't work when the post just contained images, and other material
from the status (content warning, polls) was not shown either.
Fix this by displaying a popup menu instead. The status remains visible so
the user can clearly see what they're acting on.
In addition, this lays the groundwork for supporting a long-press menu
in the future to allow the user to reblog/favourite from a different
account.
Fixes https://github.com/tuskyapp/Tusky/issues/3308
* Revert the change that puts the menu immediately over the icon
Although this behavious is consistent with how the option menu works, I
decided that the risk of someone inadvertently double-tapping in the same
location, and the first tap opens the menu and the second tap confirms the
action was too great.
So now the menu appears either above or below the icon depending on space,
and the user has to tap in two slightly different spaces.
This is also consistent with the previous behaviour, where it's highly
unlikely that the confirm button on the dialog would have been directly
under the user's finger if they double-tapped.
Clickable spans in textviews do not normally meet the Android accessibility
guidelines of a minimum 48dp square touch target.
This can't be fixed with a `TouchDelegate`, as the span is not a separate
view to which the delegate can be attached.
Add `ClickableSpanTextView`. If used instead of a `TextView`, any spans
from `ClickableSpan` will have their touchable area extended to meet the
48dp minimum.
The touchable area is still bounded by the size of the view.
If two spans are closer together than 48dp then the closest span to the
touch wins.
Co-authored-by: Konrad Pozniak <connyduck@users.noreply.github.com>
* Show toot stat inline
* Correct elements position
* Format stats and show it according to setting
* inline toot statistics setting
* Code formatting
* Use kotlin functions
* Change the statistics setting description
* Use capital letters for all variants
* increase the statistics margin
* Merge fixes
* Code review fixes
* move setReblogsCount and setFavouritedCount to StatusViewHolder
* code cleaning
* code cleaning
* import lexicographical order
---------
Co-authored-by: Grigorii Ioffe <zikasaks@gmail.com>
Co-authored-by: grigoriiioffe <zikasaks@icloud.com>
Currently translated at 93.2% (556 of 596 strings)
Co-authored-by: ButterflyOfFire <butterflyoffire@protonmail.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/ar/
Translation: Tusky/Tusky
Currently translated at 100.0% (596 of 596 strings)
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (579 of 579 strings)
Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/uk/
Translation: Tusky/Tusky
Currently translated at 96.1% (573 of 596 strings)
Translated using Weblate (Catalan)
Currently translated at 100.0% (567 of 567 strings)
Co-authored-by: Ricard Torres <ricard@ricard.dev>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/ca/
Translation: Tusky/Tusky
Currently translated at 100.0% (596 of 596 strings)
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (579 of 579 strings)
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (567 of 567 strings)
Co-authored-by: Hồ Nhất Duy <mastoduy@gmail.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/vi/
Translation: Tusky/Tusky
Currently translated at 100.0% (596 of 596 strings)
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (579 of 579 strings)
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (567 of 567 strings)
Co-authored-by: Eric <alchemillatruth@purelymail.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/zh_Hans/
Translation: Tusky/Tusky
Currently translated at 100.0% (596 of 596 strings)
Translated using Weblate (Persian)
Currently translated at 100.0% (579 of 579 strings)
Translated using Weblate (Persian)
Currently translated at 100.0% (567 of 567 strings)
Co-authored-by: Danial Behzadi <dani.behzi@ubuntu.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/fa/
Translation: Tusky/Tusky
* Enforce lint cleanliness when building
The volume of lintable issues is growing. To stem the tide:
1. Add `app/lint-baseline.xml`, which contains the current set of lint issues.
Any issue appearing here will not cause the build to fail.
2. Move lint configuration settings in to `lint.xml`.
3. Update the lint configuration so that any issue (i.e., any issue not
in lint-baseline.xml) causes a build failure.
4. Add the lint tasks as depedency when assembling an APK, to ensure the
lint checks are run.
* lint: Convert launcher images to webp
* Move lint.xml location
* Don't lint when assembling
* Update baseline
* Move compose.* tests to own namespace
* Ignore "@instance..." part of username when computing status length
In a status with a mention ("@foo@example.org") only the "@foo" part should
be included in the calculated status length. It wasn't, so the app was
prevening people from posting statuses that should have been allowed.
Fix this.
- Lift the length calculation code in to a separate static function (easier
and faster to test)
- Add a `MentionSpan` type, to reuse existing code for detecting mentions
- Fix a bug in `FakeSpannable.getSpans()` (it was returning the outer type,
not the wrapped inner span)
- Add additional fast tests
The tests made sense under the `components.compose.ComposeActivity` package,
so I also created that and moved the existing ComposeActivity tests there.
Fixes https://github.com/tuskyapp/Tusky/issues/3339
* Static import assertEquals