Mastodon "normalizes" tag text for latin characters when storing tag
names, so the hashtag object it sends for `#Über` has the name `uber`.
With the new trailing hashtag bar, this was causing nonascii hashtags
from the post content to be duplicated with their normalized versions,
e.g. `#Über #uber`.
This change ensures that we're always comparing normalized tag names.
We do this in other ViewHolders as well
Seen in this crash report on Google Play:
```
Exception java.lang.IndexOutOfBoundsException: Index: -1, Size: 0
at androidx.paging.PageStore.checkIndex (PageStore.kt:56)
at androidx.paging.PageStore.get (PageStore.kt:66)
at androidx.paging.PagingDataPresenter.peek (PagingDataPresenter.java:290)
at androidx.paging.AsyncPagingDataDiffer.peek (AsyncPagingDataDiffer.java:476)
at androidx.paging.PagingDataAdapter.peek (PagingDataAdapter.kt:312)
at com.keylesspalace.tusky.components.notifications.NotificationsFragment.onViewThread (NotificationsFragment.kt:409)
at com.keylesspalace.tusky.components.notifications.StatusNotificationViewHolder.bind$lambda$0 (StatusNotificationViewHolder.java:104)
at android.view.View.performClick (View.java:7684)
at android.view.View.performClickInternal (View.java:7661)
at android.view.View.-$$Nest$mperformClickInternal (Unknown Source)
at android.view.View$PerformClick.run (View.java:30344)
at android.os.Handler.handleCallback (Handler.java:1000)
at android.os.Handler.dispatchMessage (Handler.java:104)
at android.os.Looper.loopOnce (Looper.java:242)
at android.os.Looper.loop (Looper.java:362)
at android.app.ActivityThread.main (ActivityThread.java:8393)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:992)
```
This fixes two issues, but I tested them together to make sure this time
everything works as expected.
1) The fix in #4813 went into the right direction, but the condition was
a bit too broad. When sharing something to Tusky so that Tusky switches
accounts, sometimes nothing would happen.
2) fixes#4766. There are two possibilities here (I think it depends
mostly on API level):
2a) Sharing starts a new task. `android:maxRecents="1"` makes sure old
tasks disappear and are not left in the weird in-between state.
3a) Sharing starts a new `MainActivity` in an existing task.
`Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK` makes
sure old `MainActivity` instances are removed. On newer Android versions
this has the sideeffect of changing the switch animation, but whatever.
Basically this gives us the behavior I wanted to achieve with the
`android:launchMode="singleTask"` without the unintended side effects.
closes#4789 this time for real, hopefully, maybe
also set `alwaysRetainTaskState` for good measure
> `android:alwaysRetainTaskState`
Whether the state of the task that the activity is in is always
maintained by the system. `"true"` if it is, and `"false"` if the system
can reset the task to its initial state in certain situations. The
default value is `"false"`. This attribute is meaningful only for the
root activity of a task. It's ignored for all other activities.
> Normally, the system clears a task, removing all activities from the
stack above the root activity, in certain situations when the user
re-selects that task from the home screen. Typically, this is done if
the user hasn't visited the task for a certain amount of time, such as
30 minutes.
> However, when this attribute is `"true"`, users always return to the
task in its last state, regardless of how they get there. This is useful
in an application like a web browser where there is a lot of state, such
as multiple open tabs, that users don't want to lose.
https://developer.android.com/guide/topics/manifest/activity-element#always
This was so much work wow. I think it works pretty well and is the best
compromise between all the alternative we considered. Yes the
pull-to-refreh on the notifications works slightly different now when
the new bar is visible, but I don't think there is a way around that.
Things I plan to do later, i.e. not as part of this PR or release:
- Cache the notification policy summary for better offline behavior and
less view shifting when it loads
- try to reduce some of the code duplications that are now in there
- if there is user demand, add a "legacy mode" setting where this
feature is disabled even if the server would support it
closes#4331closes#4550 as won't do
closes#4712 as won't do
<img
src="https://github.com/user-attachments/assets/de322d3c-3775-41e7-be57-28ab7fbaecdf"
width="240"/> <img
src="https://github.com/user-attachments/assets/1ce958a4-4f15-484c-a337-5ad93f36046c"
width="240"/> <img
src="https://github.com/user-attachments/assets/98b0482b-1c05-4c99-a371-f7f4d8a69abd"
width="240"/>
```
java.lang.StringIndexOutOfBoundsException
at android.text.SpannableStringBuilder.<init>(SpannableStringBuilder.java:63)
at android.text.SpannableStringBuilder.subSequence(SpannableStringBuilder.java:1198)
at com.keylesspalace.tusky.util.LinkHelper.setClickableText(LinkHelper.kt:99)
at com.keylesspalace.tusky.adapter.StatusBaseViewHolder.setTextVisible(StatusBaseViewHolder.java:289)
at com.keylesspalace.tusky.adapter.StatusBaseViewHolder.setSpoilerAndContent(StatusBaseViewHolder.java:244)
at com.keylesspalace.tusky.adapter.StatusBaseViewHolder.setupWithStatus(StatusBaseViewHolder.java:820)
at com.keylesspalace.tusky.adapter.StatusViewHolder.setupWithStatus(StatusViewHolder.java:91)
at com.keylesspalace.tusky.components.timeline.TimelinePagingAdapter.bindViewHolder(TimelinePagingAdapter.kt:100)
at com.keylesspalace.tusky.components.timeline.TimelinePagingAdapter.onBindViewHolder(TimelinePagingAdapter.kt:82)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7847)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6646)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6917)
at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:288)
at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:345)
at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:361)
at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:368)
at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:399)
at android.os.Handler.handleCallback(Handler.java:959)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8705)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886)
```
Before we would not send `expires_in` when "indefinite" was selected.
But that left the expiration at the value it was before. To actually set
it to indefinite we need to send `expires_in`, but leave it empty.
With a value class this was actually really nice to fix, the code now
self-documents what the special values mean.
Also fixes a regression from the Material 3 redesign where the filter
duration drop down would not get populated when creating a filter.
Found while working on https://github.com/tuskyapp/Tusky/pull/4742
This is to match Mastodon web behavior.
Also, make revealing filtered boosts in non-cached timelines work (can
only happen on user profiles, other timelines don't have boosts).
found thanks to this: https://tech.lgbt/@darkfox/113378644538792719
closes https://github.com/tuskyapp/Tusky/issues/4725
I checked with examples from https://github.com/tuskyapp/Tusky/pull/2743
and looks like nothing broke. Not sure why the `.dontTransform()` was
there. It prevents Glide from correctly sizing the image, leading to a
crash.
<details>
<summary>Stacktrace</summary>
```
java.lang.RuntimeException: Canvas: trying to draw too large(401361624bytes) bitmap.
at android.graphics.RecordingCanvas.throwIfCannotDraw(RecordingCanvas.java:266)
at android.graphics.BaseRecordingCanvas.drawBitmap(BaseRecordingCanvas.java:94)
at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:549)
at android.widget.ImageView.onDraw(ImageView.java:1446)
at com.google.android.material.imageview.ShapeableImageView.onDraw(ShapeableImageView.java:188)
at android.view.View.draw(View.java:23266)
at android.view.View.updateDisplayListIfDirty(View.java:22133)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.draw(View.java:23269)
at android.view.View.updateDisplayListIfDirty(View.java:22133)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1994)
at android.view.View.updateDisplayListIfDirty(View.java:22124)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at androidx.recyclerview.widget.RecyclerView.drawChild(RecyclerView.java:5545)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.draw(View.java:23269)
at androidx.recyclerview.widget.RecyclerView.draw(RecyclerView.java:4944)
at android.view.View.updateDisplayListIfDirty(View.java:22133)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.updateDisplayListIfDirty(View.java:22124)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.draw(View.java:23269)
at android.view.View.updateDisplayListIfDirty(View.java:22133)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.updateDisplayListIfDirty(View.java:22124)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at androidx.coordinatorlayout.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1277)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.updateDisplayListIfDirty(View.java:22124)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at androidx.fragment.app.FragmentContainerView.drawChild(FragmentContainerView.kt:232)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at androidx.fragment.app.FragmentContainerView.dispatchDraw(FragmentContainerView.kt:222)
at android.view.View.updateDisplayListIfDirty(View.java:22124)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at androidx.coordinatorlayout.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1277)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.updateDisplayListIfDirty(View.java:22124)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.updateDisplayListIfDirty(View.java:22124)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.updateDisplayListIfDirty(View.java:22124)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.updateDisplayListIfDirty(View.java:22124)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.updateDisplayListIfDirty(View.java:22124)
at android.view.View.draw(View.java:22997)
at android.view.ViewGroup.drawChild(ViewGroup.java:4529)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4290)
at android.view.View.draw(View.java:23269)
at com.android.internal.policy.DecorView.draw(DecorView.java:821)
at android.view.View.updateDisplayListIfDirty(View.java:22133)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:689)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:695)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:793)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:4789)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4500)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3687)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2371)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9297)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1231)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
at android.view.Choreographer.doCallbacks(Choreographer.java:899)
at android.view.Choreographer.doFrame(Choreographer.java:832)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7924)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
```
</details>
https://docs.joinmastodon.org/entities/Announcement/
The statuses in this model are not full statuses but we expect them, so
parsing a response that contains one fails.
`com.squareup.moshi.JsonDataException: Required value 'account' missing
at $[0].statuses[1]`
Since we don't even use the attribute, we can just remove it to fix the
bug.
Closes#4696
From Play console crash logs. Well, let's put another band aid on this
code....
```
Exception java.lang.IllegalStateException:
at androidx.fragment.app.Fragment.requireActivity (Fragment.java:1005)
at com.keylesspalace.tusky.fragment.ViewImageFragment.getPhotoActionsListener (ViewImageFragment.java:59)
at com.keylesspalace.tusky.fragment.ViewImageFragment.access$getPhotoActionsListener (ViewImageFragment.java:49)
at com.keylesspalace.tusky.fragment.ViewImageFragment$onViewCreated$singleTapDetector$1.onSingleTapConfirmed (ViewImageFragment.kt:116)
at android.view.GestureDetector$GestureHandler.handleMessage (GestureDetector.java:379)
at android.os.Handler.dispatchMessage (Handler.java:106)
at android.os.Looper.loopOnce (Looper.java:230)
at android.os.Looper.loop (Looper.java:319)
at android.app.ActivityThread.main (ActivityThread.java:8919)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:578)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1103)
```
This fixes
- The problem where Tusky drops your draft when you switch apps while
composing
- The problem where MainActivity does not restart when switching theme
in preferences
This adds back a bug where one can have multiple instances of
MainActivity which can behave weirdly when the active account was
switched after they were created. This bug is (unlike the timeline mixup
one) transient though, it will go away when restarting the app. As a
small mitigation MainActivity is finished when forwarding to
ComposeActivity (Tusky 25 behavior).
Closes#4353 by addressing the last edge case: The swipe to refresh
won't be enabled before something is loaded, preventing multiple loads
at the same time. After the first load, the swipe to refresh itself
prevents multiple loads: It can be swiped only once.
---------
Co-authored-by: Goooler <wangzongler@gmail.com>
Adds auto keyboard popup to ListsActivity, FollowedTagsActivity,
EditFilterActivity, CaptionDialog, and AddPollDialog.kt, and
AddHashtagDialog in TabPreferenceActivity. These are all dialog screens
which editing texts are the main purposes
---------
Co-authored-by: Weblate <42475313+nailyk-weblate@users.noreply.github.com>
Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Danial Behzadi <dani.behzi@ubuntu.com>
Co-authored-by: Manuel <mannivuwiki@gmail.com>
Co-authored-by: Eric <ekhfcxwuvxqfdb@hldrive.com>
Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com>
regression from https://github.com/tuskyapp/Tusky/pull/4599https://pug.ninja/@motoridersd/113102603349423738
The problem is, `MediaUploader` is no longer a singleton, so the state
is not correctly shared between `ComposeActivity` and
`SendStatusService.` But it can't be a singleton, since `MediaUploadApi`
(injected into `MediaUploader`) needs to be recreated on account change.
Let's share the state in the companion object instead.
This one is odd.
I find that if I
- Add an image to a post
- Set a caption on the image
- Tap the caption dialog to bring up the keyboard
- Tap the navbar (very easy to do by accident while typing, just tap
under the spacebar)
The caption dialog disappears and you lose your caption.
(This doesn't happen in ANY other dialog in the app, and in the caption
dialog it ONLY happens when the keyboard is up.)
I got a tablet and on the tablet this happens ALL THE TIME.
I was considering adding a "really cancel?" dialog to the caption
dialog. But then I discovered (thank you @memorion@mastodon.social) by
setting getCanceledOnTouchOutside(false), I could make the bad behavior
go ahead completely. In my tests now I can only make the dialog go away
by tapping the actual back button.
I believe the potential negative impact of this is low because the
caption dialog is full screen, so it was already impossible to trigger
the touch outside behavior on *purpose*.
I might attempt a "really cancel caption?" dialog later because it sucks
to lose a long caption you have typed, but I think this fixes my
personal problem by itself.
---------
Co-authored-by: Konrad Pozniak <connyduck@users.noreply.github.com>
```
android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:961)
at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:790)
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:89)
at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.kt:42)
at androidx.room.EntityInsertionAdapter.insertAndReturnId(EntityInsertionAdapter.kt:101)
at com.keylesspalace.tusky.db.dao.TimelineStatusDao_Impl$insert$2.call(TimelineStatusDao_Impl.kt:345)
at com.keylesspalace.tusky.db.dao.TimelineStatusDao_Impl$insert$2.call(TimelineStatusDao_Impl.kt:340)
at androidx.room.CoroutinesRoom$Companion.execute(CoroutinesRoom.kt:56)
at com.keylesspalace.tusky.db.dao.TimelineStatusDao_Impl.insert(TimelineStatusDao_Impl.kt:340)
at com.keylesspalace.tusky.components.notifications.NotificationsRemoteMediator.replaceNotificationRange(NotificationsRemoteMediator.kt:169)
at com.keylesspalace.tusky.components.notifications.NotificationsRemoteMediator.access$replaceNotificationRange(NotificationsRemoteMediator.kt:36)
at com.keylesspalace.tusky.components.notifications.NotificationsRemoteMediator$load$3.invokeSuspend(NotificationsRemoteMediator.kt:109)
at com.keylesspalace.tusky.components.notifications.NotificationsRemoteMediator$load$3.invoke(Unknown Source:8)
at com.keylesspalace.tusky.components.notifications.NotificationsRemoteMediator$load$3.invoke(Unknown Source:2)
at androidx.room.RoomDatabaseKt$withTransaction$transactionBlock$1.invokeSuspend(RoomDatabaseExt.kt:62)
at androidx.room.RoomDatabaseKt$withTransaction$transactionBlock$1.invoke(Unknown Source:8)
at androidx.room.RoomDatabaseKt$withTransaction$transactionBlock$1.invoke(Unknown Source:4)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:61)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:163)
at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
at androidx.room.RoomDatabaseKt$startTransactionCoroutine$2$1$1.invokeSuspend(RoomDatabaseExt.kt:103)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:277)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:95)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:69)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1)
at androidx.room.RoomDatabaseKt$startTransactionCoroutine$2$1.run(RoomDatabaseExt.kt:99)
at androidx.room.TransactionExecutor.execute$lambda$1$lambda$0(TransactionExecutor.kt:36)
at androidx.room.TransactionExecutor.$r8$lambda$FZWr2PGmP3sgXLCiri-DCcePXSs(Unknown Source:0)
at androidx.room.TransactionExecutor$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at java.lang.Thread.run(Thread.java:1012)
```
It looks kinda weird because "x just posted" has a different user than
the actual post, but it works for groups I guess? And definitely better
than crashing.
<img
src="https://github.com/user-attachments/assets/8110ff17-674d-4f36-8df0-453a666856a6"
width="320"/>
closes#4563
closes#4631closes#4629
and other weirdness introduced in Tusky 26.1.
I did a lot of testing on 2 physical devices and multiple emulators. It
definitely is better than before, but probably still not perfect.
Adds feature if user clicks on toolbar, on the pages box, or on the tabs
buttons that the keyboard will minimize and focus will be taken off of
search bar.
Further addresses issue #4573
This fixes a bug where the timeline would jump to the position of a
previously clicked "load more" when new post are inserted at the top
after swiping to refresh.
This only happens when "Reading order" is set to "Oldest first".
The problem is that updateReadingPositionForOldestFirst (which consumes
the marker to which it should jump) is called from onItemRangeInserted.
But onItemRangeInserted is not called everytime a "load more" is
clicked, leaving the marker active, causing a jump the next time
onItemRangeInserted is called.
I am not sure this fixes all cases of the various jumping bugs that have
been reported recently as this was the only one I could reliably
reproduce.
Related to https://github.com/tuskyapp/Tusky/issues/4493
This does 2 things:
- Removes `AccountSwitchInterceptor`, the main culprit for the bug. APIs
can no longer change their base url after they have been created. As a
result they are not Singletons anymore.
- Additionally, I refactored how MainActivity handles Intents to make it
less likely to have multiple instances of it active.
Here is how I could reliably reproduce the bug:
- Be logged in with account A and B
- Write a post with account A, cancel it before it sends (go into flight
mode for that)
- Switch to account B
- Open the "this post failed to send" notification from account A,
drafts will open
- Go back. You are in the MainActivity of account A, everything seems
fine.
- Go back again. You are in the old, now broken MainActivity of account
B. It uses the database of account B but the network of account A.
Refreshing will show posts from A.
closes#4567closes#4554closes#4402closes#4148closes#2663
and possibly #4588
This will make it less likely that data from different accounts will get
mixed up.
I checked the codepaths and we shouldn't hit viewModel if account is not
there but this is still a bit of risk to assume that so I'll investigate
if we can pass in more things and use DI to make it more secure
---------
Co-authored-by: Conny Duck <git@connyduck.at>