Currently translated at 100.0% (677 of 677 strings)
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (677 of 677 strings)
Co-authored-by: Hồ Nhất Duy <mastoduy@gmail.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/vi/
Translation: Tusky/Tusky
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"/>
- use `runTest` instead of `runBlocking`, where possible
- run all Robolectric tests on Api 34 (where we have most users)
- some new testcase for `TimestampUtilsTest`
- move our only instrumented Android Test, `MigrationsTest`, to unit
test so it runs in CI and expand it to test all migrations
- upgrade Robolectric
- removed truth and espresso as they are no longer needed
```
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)
```
Currently translated at 99.0% (646 of 652 strings)
Co-authored-by: Anna (cybertailor) Vyalkova <cyber@sysrq.in>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/ru/
Translation: Tusky/Tusky
Currently translated at 100.0% (652 of 652 strings)
Translated using Weblate (Welsh)
Currently translated at 100.0% (652 of 652 strings)
Co-authored-by: Rhoslyn Prys <post@meddal.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/cy/
Translation: Tusky/Tusky
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
Currently translated at 100.0% (652 of 652 strings)
Translated using Weblate (Vietnamese)
Currently translated at 100.0% (652 of 652 strings)
Co-authored-by: Hồ Nhất Duy <mastoduy@gmail.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/vi/
Translation: Tusky/Tusky
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>
Currently translated at 35.5% (232 of 652 strings)
Co-authored-by: ButterflyOfFire <butterflyoffire@protonmail.com>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/kab/
Translation: Tusky/Tusky
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>