Currently translated at 100.0% (639 of 639 strings)
Co-authored-by: fin-w <puf@users.noreply.weblate.tusky.app>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/cy/
Translation: Tusky/Tusky
Currently, ExoPlayer is initialized explicitly in `ViewMediaFragment`
with all its dependencies, including many that are not useful for
viewing Mastodon media attachments.
This pull request moves most ExoPlayer initialization and configuration
to a new Dagger module, and instead a `Provider<ExoPlayer>` factory is
injected in the Fragment so it can create new instances when needed.
The following ExoPlayer components will be configured:
- **Renderers**: all of them (audio, video, metadata, subtitles) except
for the `CameraMotionRenderer`.
- **Extractors**: FLAC, Wav, Mp4, Ogg, Matroska/WebM and MP3 containers,
to provide the same support as Firefox or Chrome browsers. Other
container formats that are either image formats (already covered by
Glide), not web-friendly or reserved for live streaming are skipped.
- **MediaSource**: only progressive download (through OkHttp) is
provided. Live streaming support using protocols like RTSP, MPEG/Dash or
HLS is skipped, because Mastodon servers don't use these protocols to
download attachments.
The Mastodon documentation mentions the [supported media formats for
attachments](https://docs.joinmastodon.org/user/posting/#media) and this
covers them and even more. The docs also mentions that the video and
audio files are transcoded to MP4 and MP3 upon upload but that was not
the case in the past (for example WebM was used) and it could change
again in the future.
Specifying these components manually allows reducing the APK size by
about 200 KB thanks to R8 shrinking.
There are also a few extra code changes:
- Remove the code specific to API < 24 since the min SDK of the app is
now 24.
- Add support for pausing a video when unplugging headphones.
- Specify the audio attributes according to content type to help the
Android audio mixer.
Regression from #4291 // cc @cbeyls
<details>
<summary>Stacktrace</summary>
```
Process: com.keylesspalace.tusky, PID: 31230
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.keylesspalace.tusky/com.keylesspalace.tusky.components.accountlist.AccountListActivity}:
java.lang.RuntimeException: java.lang.NoSuchMethodException: h4.a.values
[]
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3635)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)
at
android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at
android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at
android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
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:1003)
Caused by: java.lang.RuntimeException: java.lang.NoSuchMethodException:
h4.a.values []
at java.lang.Enum.enumValues(Enum.java:270)
at java.lang.Enum.access$000(Enum.java:61)
at java.lang.Enum$1.create(Enum.java:277)
at java.lang.Enum$1.create(Enum.java:275)
at libcore.util.BasicLruCache.get(BasicLruCache.java:63)
at java.lang.Enum.getSharedConstants(Enum.java:289)
at java.lang.Enum.valueOf(Enum.java:243)
at java.io.ObjectInputStream.readEnum(ObjectInputStream.java:1841)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1409)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
at android.os.Parcel.readSerializable(Parcel.java:3507)
at android.os.Parcel.readValue(Parcel.java:3277)
at android.os.Parcel.readArrayMapInternal(Parcel.java:3623)
at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292)
at android.os.BaseBundle.unparcel(BaseBundle.java:236)
at android.os.BaseBundle.getSerializable(BaseBundle.java:1268)
at android.os.Bundle.getSerializable(Bundle.java:1104)
at android.content.Intent.getSerializableExtra(Intent.java:8575)
at
com.keylesspalace.tusky.components.accountlist.AccountListActivity.onCreate(SourceFile:23)
at android.app.Activity.performCreate(Activity.java:8051)
at android.app.Activity.performCreate(Activity.java:8031)
at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)
at
android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at
android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at
android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
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:1003)
Caused by: java.lang.NoSuchMethodException: h4.a.values []
at java.lang.Class.getMethod(Class.java:2103)
at java.lang.Class.getDeclaredMethod(Class.java:2081)
at java.lang.Enum.enumValues(Enum.java:267)
at java.lang.Enum.access$000(Enum.java:61)
at java.lang.Enum$1.create(Enum.java:277)
at java.lang.Enum$1.create(Enum.java:275)
at libcore.util.BasicLruCache.get(BasicLruCache.java:63)
at java.lang.Enum.getSharedConstants(Enum.java:289)
at java.lang.Enum.valueOf(Enum.java:243)
at java.io.ObjectInputStream.readEnum(ObjectInputStream.java:1841)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1409)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
at android.os.Parcel.readSerializable(Parcel.java:3507)
at android.os.Parcel.readValue(Parcel.java:3277)
at android.os.Parcel.readArrayMapInternal(Parcel.java:3623)
at
android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292)
at android.os.BaseBundle.unparcel(BaseBundle.java:236)
at android.os.BaseBundle.getSerializable(BaseBundle.java:1268)
at android.os.Bundle.getSerializable(Bundle.java:1104)
at android.content.Intent.getSerializableExtra(Intent.java:8575)
at
com.keylesspalace.tusky.components.accountlist.AccountListActivity.onCreate(SourceFile:23)
at android.app.Activity.performCreate(Activity.java:8051)
at android.app.Activity.performCreate(Activity.java:8031)
at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)
at
android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at
android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at
android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
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:1003)
```
</details>
closes#4297
Currently translated at 100.0% (634 of 634 strings)
Co-authored-by: fin-w <puf@users.noreply.weblate.tusky.app>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/cy/
Translation: Tusky/Tusky
Using saner defaults for R8 while reducing the app size even further.
- Add Kotlin compiler options to skip adding assertions in release
builds
- Remove `optimizations`, `optimizationpasses` and `dontpreverify` rules
that are ignored by R8
- Only keep runtime annotations by default. If other attributes are
needed by a specific library, these will already be provided by the
library rules (for example Retrofit or coroutines)
- Remove the obsolete rule allowing a View to reflectively call any
arbitrary public Activity method accepting a View as argument. This has
always been a bad practice and is not used in this project anyway
- Remove the rules related to enums. R8 already optimizes enums properly
out-of-the-box and keeping these rules may prevent some of these
optimizations
- Add support for the `@Keep` annotation. Even if it's not currently
used in the code base, it can be handy in the future
- Add a missing rule to prevent generic signature of `NetworkResult`
class from being removed in `MastodonApi` so Retrofit works
- Allow obfuscation and shrinking of `kotlin.coroutines.Continuation`,
matching the rule defined in the next release of Retrofit
- Remove the rule forcing the removal of `String.format()`. This method
is actually used in the code (and in third-party libraries) for other
things than logging so forcing its removal can do more harm than good.
This pull request removes the remaining RxJava code and replaces it with
coroutine-equivalent implementations.
- Remove all duplicate methods in `MastodonApi`:
- Methods returning a RxJava `Single` have been replaced by suspending
methods returning a `NetworkResult` in order to be consistent with the
new code.
- _sync_/_async_ method variants are replaced with the _async_ version
only (suspending method), and `runBlocking{}` is used to make the async
variant synchronous.
- Create a custom coroutine-based implementation of `Single` for usage
in Java code where launching a coroutine is not possible. This class can
be deleted after remaining Java code has been converted to Kotlin.
- `NotificationsFragment.java` can subscribe to `EventHub` events by
calling the new lifecycle-aware `EventHub.subscribe()` method. This
allows using the `SharedFlow` as single source of truth for all events.
- Rx Autodispose is replaced by `lifecycleScope.launch()` which will
automatically cancel the coroutine when the Fragment view/Activity is
destroyed.
- Background work is launched in the existing injectable
`externalScope`, since using `GlobalScope` is discouraged.
`externalScope` has been changed to be a `@Singleton` and to use the
main dispatcher by default.
- Transform `ShareShortcutHelper` to an injectable utility class so it
can use the application `Context` and `externalScope` as provided
dependencies to launch a background coroutine.
- Implement a custom Glide extension method
`RequestBuilder.submitAsync()` to do the same thing as
`RequestBuilder.submit().get()` in a non-blocking way. This way there is
no need to switch to a background dispatcher and block a background
thread, and cancellation is supported out-of-the-box.
- An utility method `Fragment.updateRelativeTimePeriodically()` has been
added to remove duplicate logic in `TimelineFragment` and
`NotificationsFragment`, and the logic is now implemented using a simple
coroutine instead of `Observable.interval()`. Note that the periodic
update now happens between onStart and onStop instead of between
onResume and onPause, since the Fragment is not interactive but is still
visible in the started state.
- Rewrite `BottomSheetActivityTest` using coroutines tests.
- Remove all RxJava library dependencies.
This way the `FOREGROUND_SERVICE_REMOTE_MESSAGING` permission is not
needed and we should be able to publish on Google Play again. Drawback:
The service can get killed after a while (usually 3 mins) on Android 14.
I also tried using [user initiated data transfer
jobs](https://developer.android.com/about/versions/14/changes/user-initiated-data-transfers),
but that is not available on all api levels, and `WorkManager`, but that
is a huge refactoring and sending would probably work differently than
before.
```
java.lang.RuntimeException: Unable to start service com.keylesspalace.tusky.service.SendStatusService@1eb9198 with Intent { cmp=com.keylesspalace.tusky.test/com.keylesspalace.tusky.service.SendStatusService (has extras) }: android.app.MissingForegroundServiceTypeException: Starting FGS without a type callerApp=ProcessRecord{18608f7 22134:com.keylesspalace.tusky.test/u0a193} targetSDK=34
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4839)
at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2289)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: android.app.MissingForegroundServiceTypeException: Starting FGS without a type callerApp=ProcessRecord{18608f7 22134:com.keylesspalace.tusky.test/u0a193} targetSDK=34
at android.app.MissingForegroundServiceTypeException$1.createFromParcel(MissingForegroundServiceTypeException.java:53)
at android.app.MissingForegroundServiceTypeException$1.createFromParcel(MissingForegroundServiceTypeException.java:49)
at android.os.Parcel.readParcelableInternal(Parcel.java:4870)
at android.os.Parcel.readParcelable(Parcel.java:4852)
at android.os.Parcel.createExceptionOrNull(Parcel.java:3052)
at android.os.Parcel.createException(Parcel.java:3041)
at android.os.Parcel.readException(Parcel.java:3024)
at android.os.Parcel.readException(Parcel.java:2966)
at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:6761)
at android.app.Service.startForeground(Service.java:775)
at com.keylesspalace.tusky.service.SendStatusService.onStartCommand(SendStatusService.kt:137)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4821)
at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2289)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
```
builds upon work from #4082
Additionally fixes some deprecations and adds support for [predictive
back](https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture).
I also refactored how the activity transitions work because they are
closely related to predictive back. The awkward
`finishWithoutSlideOutAnimation` is gone, activities that have been
started with slide in will now automatically close with slide out.
To test predictive back you need an emulator or device with Sdk 34
(Android 14) and then enable it in the developer settings.
Predictive back requires the back action to be determined before it
actually occurs so the system can play the right predictive animation,
which made a few reorganisations necessary.
closes#4082closes#4005
unlocks a bunch of dependency upgrades that require sdk 34
---------
Co-authored-by: Goooler <wangzongler@gmail.com>
While working on #4249 I noticed that quick replies also don't work as
expected. The notification just stays in the sending state forever.
There are actually 2 problems:
- Notifications are sent in `NotificationFetcher` with the id of the
Mastodon notification as tag and the current account id as id. The wrong
notification id was forwarded to `SendStatusBroadcastReceiver` so it
never had a chance of updating the notification.
- Notifications containing an active remote input can't be cancelled
(they just stop their animation when doing so). So instead I update the
notification with info that the reply is being sent and have it dismiss
automatically.
I also tried replacing the original notification with the "sending"
notification of `SendStatusService`, but that doesn't work because
`Service.startForeground` doesn't have a tag parameter, only an id.
---------
Co-authored-by: Willow <charlag@tuta.io>
#4205 did change how the counters for the detailed posts behave and for
a good reason I believe.
However I find the changed order very confusing and not aesthetically
pleasing.
I have tried a few options, including reserving space for it but it was
confusing (when counters are not displayed there would be a danging
separator or if we show separator together with it it would be confusing
as well).
I propose we simply show the counters independent on the counts. I know
we try to de-emphasize the counters but I believe this is fine to do in
detailed view.
One disadvantage is that we need translators to update the translations.
Additionally I've done two spacing changes: I removed a separator
between the counters and the buttons, removed padding around the
counters and increased the space between the counters and the buttons
instead. I believe it's better to use space than separators. This also
makes the space above/below the media/counters separator balanced.
In the second commit I've also made the metadata/counters separators
thinner, I think it looks better.
here's the combined version:
![proposal_final](https://github.com/tuskyapp/Tusky/assets/3099142/ea9d4c0c-fe6a-4f2e-8427-673b2a833e6b)
Rationale: In the current layout, when performing multiple interactions
(e.g. fav+boost, fav+reply) on a post that hasn't been interacted with
before, the statistics bar appears and pushes the buttons down, so the
second tap goes to the statistics bar instead
I had it happen multiple times recently that I was testing green Tusky
but Android Studio actually put blue Tusky on my device and I wasted a
lot of time until I found out 😣
This change should tell it that greenDebug is the preferred flavor for
developing.
Currently translated at 100.0% (634 of 634 strings)
Co-authored-by: fin-w <puf@users.noreply.weblate.tusky.app>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/cy/
Translation: Tusky/Tusky
according to crash logs there are seem to be some instances that don't
always return the expected json, so lets be extra safe here
```
Exception java.lang.NullPointerException:
at com.keylesspalace.tusky.components.instanceinfo.InstanceInfoRepository$getInstanceInfo$2.invokeSuspend (InstanceInfoRepository.kt:67)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:108)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run (LimitedDispatcher.java:115)
at kotlinx.coroutines.scheduling.TaskImpl.run (Tasks.kt:103)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely (CoroutineScheduler.java:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask (CoroutineScheduler.kt:793)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker (CoroutineScheduler.kt:697)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run (CoroutineScheduler.kt:684)
```
The sensitive flag indicates sensitive media, but we want to check if
there is a contentwarning on the post. I think statuses that have a
contentwarning but no sensitive flag are rare so we never noticed this
bug.
closes#4201
Currently translated at 98.7% (625 of 633 strings)
Co-authored-by: fin-w <puf@users.noreply.weblate.tusky.app>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/cy/
Translation: Tusky/Tusky
Chrome defaults to showing it anyways, but Firefox doesn't. By enabling
this feature, users across both browsers will now have the same
experience.
closes tuskyapp/Tusky/issues/4137
There are some new rules, I think they mostly make sense, except for the
max line length which I had to disable because we are over it in a lot
of places.
---------
Co-authored-by: Goooler <wangzongler@gmail.com>
Currently translated at 100.0% (633 of 633 strings)
Translated using Weblate (Welsh)
Currently translated at 100.0% (634 of 634 strings)
Translated using Weblate (Welsh)
Currently translated at 100.0% (634 of 634 strings)
Co-authored-by: fin-w <puf@users.noreply.weblate.tusky.app>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/cy/
Translation: Tusky/Tusky
Posted this as issue #3999 before. The reasoning is personal experiments
and forks may add database fields and must bump the database number to
do so, but this causes massive merge difficulties when Tusky then
inevitably itself bumps the number. To alleviate this, Tusky official
should use only even database numbers, so odd versions are available for
third party scribbling.
There was little discussion positive or negative in #3999 (one proposal
we switch to a date-based number system, which would work but also could
be unnecessarily complicated). With PR #4115 we now have to make a
decision because that's the first post-proposal PR to bump the database
number odd. So, since I see no outright objections, I'd like to
implement this.
@connyduck suggested the best way to implement the proposal would be to
add a comment to the version number's home in AppDatabase.java.
Co-authored-by: Konrad Pozniak <connyduck@users.noreply.github.com>
# Overview
In the previous code, when you open preferences, there is a section
headed "Filters" with a section called "Tabs"
This is confusing.
# Changes
- Change the section title from "Filters" to "Per-timeline preferences."
- Change the current "Tabs" section to "Home timeline" since it is only
for home timelines
# Screenshots
account preference screen | detail screen
:--: | :--:
|<image
src="https://github.com/tuskyapp/Tusky/assets/62137820/12694f24-b7e3-4ba3-90f5-53740e9c4269"
width="250" />|<image
src="https://github.com/tuskyapp/Tusky/assets/62137820/796e9ac1-76d6-43ef-a087-a1cd2d899ef8"
width="250" />
# Note
- Maybe string resources should have a new property? (for translation)
# Related link
Fixes#3536
---------
Co-authored-by: mcc <andi.m.mcclure@gmail.com>
Currently translated at 100.0% (634 of 634 strings)
Co-authored-by: fin-w <puf@users.noreply.weblate.tusky.app>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/cy/
Translation: Tusky/Tusky
Turns out that the crash I thought will not occur with #4153 did occur
again. 😒
But this time I managed to reproduce it (faking a slow network for that
one request only and then quickly switching activities to get it
destroyed) so I'm sure it is fixed, and I did a check for possible side
effects but it seems Glide is clever enough to cancel all requests by
itself.
<details>
<summary>stacktrace</summary>
```
Exception java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity
at com.bumptech.glide.manager.RequestManagerRetriever.assertNotDestroyed (RequestManagerRetriever.java:236)
at com.bumptech.glide.manager.RequestManagerRetriever.get (RequestManagerRetriever.java:110)
at com.bumptech.glide.manager.RequestManagerRetriever.get (RequestManagerRetriever.java:176)
at com.bumptech.glide.Glide.with (Glide.java:634)
at com.keylesspalace.tusky.MainActivity$setupDrawer$2.cancel (MainActivity.kt:573)
at com.mikepenz.materialdrawer.util.DrawerImageLoader.cancelImage (DrawerImageLoader.java:56)
at com.mikepenz.materialdrawer.model.BaseDescribeableDrawerItem.unbindView (BaseDescribeableDrawerItem.kt:95)
at com.mikepenz.materialdrawer.model.BaseDescribeableDrawerItem.unbindView (BaseDescribeableDrawerItem.kt:20)
at com.mikepenz.fastadapter.listeners.OnBindViewHolderListenerImpl.unBindViewHolder (OnBindViewHolderListenerImpl.java:36)
at com.mikepenz.fastadapter.FastAdapter.onViewRecycled (FastAdapter.kt:410)
at androidx.recyclerview.widget.RecyclerView$Recycler.dispatchViewRecycled (RecyclerView.java:7346)
at androidx.recyclerview.widget.RecyclerView$Recycler.addViewHolderToRecycledViewPool (RecyclerView.java:7108)
at androidx.recyclerview.widget.RecyclerView$Recycler.recycleViewHolderInternal (RecyclerView.java:7059)
at androidx.recyclerview.widget.RecyclerView.removeAnimatingView (RecyclerView.java:1556)
at androidx.recyclerview.widget.RecyclerView$ItemAnimatorRestoreListener.onAnimationFinished (RecyclerView.java:13564)
at androidx.recyclerview.widget.RecyclerView$ItemAnimator.dispatchAnimationFinished (RecyclerView.java:14066)
at androidx.recyclerview.widget.SimpleItemAnimator.dispatchChangeFinished (SimpleItemAnimator.java:328)
at androidx.recyclerview.widget.DefaultItemAnimator.endChangeAnimationIfNecessary (DefaultItemAnimator.java:437)
at androidx.recyclerview.widget.DefaultItemAnimator.endChangeAnimationIfNecessary (DefaultItemAnimator.java:418)
at androidx.recyclerview.widget.DefaultItemAnimator.endAnimations (DefaultItemAnimator.java:588)
at androidx.recyclerview.widget.RecyclerView.onDetachedFromWindow (RecyclerView.java:3383)
at android.view.View.dispatchDetachedFromWindow (View.java:20898)
at android.view.ViewGroup.dispatchDetachedFromWindow (ViewGroup.java:3956)
at android.view.ViewGroup.dispatchDetachedFromWindow (ViewGroup.java:3948)
at android.view.ViewGroup.dispatchDetachedFromWindow (ViewGroup.java:3948)
at android.view.ViewGroup.dispatchDetachedFromWindow (ViewGroup.java:3948)
at android.view.ViewGroup.dispatchDetachedFromWindow (ViewGroup.java:3948)
at android.view.ViewGroup.dispatchDetachedFromWindow (ViewGroup.java:3948)
at android.view.ViewGroup.dispatchDetachedFromWindow (ViewGroup.java:3948)
at android.view.ViewGroup.dispatchDetachedFromWindow (ViewGroup.java:3948)
at android.view.ViewRootImpl.dispatchDetachedFromWindow (ViewRootImpl.java:5114)
at android.view.ViewRootImpl.doDie (ViewRootImpl.java:8309)
at android.view.ViewRootImpl.die (ViewRootImpl.java:8286)
at android.view.WindowManagerGlobal.removeViewLocked (WindowManagerGlobal.java:538)
at android.view.WindowManagerGlobal.removeView (WindowManagerGlobal.java:479)
at android.view.WindowManagerImpl.removeViewImmediate (WindowManagerImpl.java:162)
at android.app.ActivityThread.handleDestroyActivity (ActivityThread.java:5564)
at android.app.ActivityThread.handleRelaunchActivityInner (ActivityThread.java:5842)
at android.app.ActivityThread.handleRelaunchActivity (ActivityThread.java:5758)
at android.app.servertransaction.ActivityRelaunchItem.execute (ActivityRelaunchItem.java:71)
at android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2293)
at android.os.Handler.dispatchMessage (Handler.java:106)
at android.os.Looper.loopOnce (Looper.java:226)
at android.os.Looper.loop (Looper.java:329)
at android.app.ActivityThread.main (ActivityThread.java:8058)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1026)
```
</details>
<details>
<summary>Stacktrace</summary>
```
java.lang.ClassCastException: java.lang.String cannot be cast to
android.text.Spannable
at
com.keylesspalace.tusky.view.ClickableSpanTextView.dispatchTouchEvent(ClickableSpanTextView.kt:208)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2600)
at
com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:448)
at
com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1829)
at android.app.Activity.dispatchTouchEvent(Activity.java:3307)
at
androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:70)
at
com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:410)
at android.view.View.dispatchPointerEvent(View.java:12015)
at
android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4795)
at
android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4609)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
at
android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4200)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4166)
at
android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4293)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4174)
at
android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4350)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
at
android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4200)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4166)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4174)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6661)
```
</details>
Could not reproduce with a regular build because I couldn't find the
place where we set a string into a ClickableSpanTextView, so I created
that scenario manually. It crashed instantly when trying to select text,
and with this fix it behaved as expected.
Saw an ANR (app not responding) error being reported in the Play console
and then found this. Sorry but `runBlocking` in production code is an
absolute no go.
Currently translated at 100.0% (634 of 634 strings)
Translated using Weblate (Russian)
Currently translated at 100.0% (634 of 634 strings)
Co-authored-by: Vladyslav Stepanov <mittwerk@users.noreply.weblate.tusky.app>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/ru/
Translation: Tusky/Tusky
```
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.keylesspalace.tusky.test/com.keylesspalace.tusky.ViewMediaActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.NullPointerException
at com.keylesspalace.tusky.ViewMediaActivity.adjustScreenWakefulness(ViewMediaActivity.kt:351)
at com.keylesspalace.tusky.ViewMediaActivity.onCreate(ViewMediaActivity.kt:161)
at android.app.Activity.performCreate(Activity.java:7009)
at android.app.Activity.performCreate(Activity.java:7000)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
```
For reasons not totally clear to me, Github marked #4160 as "merged" and
will not let me reopen it.
I believe this should be included for 24.1 because it fixes a 24.0
regression in the media player.
I have tested this newest commit in a number of ways, and in my testing
I find (1) when viewing an image, it sleeps after about a minute (2)
when viewing video, it stays awake indefinitely (3) this is true whether
the image/video was opened directly, or reached by swiping from another
attachment. I have not tested swiping to/from audio but I am confident
it will work the same.
I hate these workarounds for Android bugs, I'm always afraid the will
introduce other problems. I tested this on multiple Android versions, it
definitely fixes the problem and otherwise seems fine though.
closes#4164
Currently translated at 100.0% (634 of 634 strings)
Co-authored-by: fin-w <puf@users.noreply.weblate.tusky.app>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/cy/
Translation: Tusky/Tusky
Another fix for a memory leak. This one is not as big as #4150, but
still worth fixing for memory constrained devices imo.
The `DrawerImageLoader` implementation (a global singleton) references a
member of the `MainActivity`, causing the whole activity to leak.
This weird construct was introduced in #1989 to fix a crash, but I think
since we migrated to coroutines it is no longer necessary because all
calls get correctly cancelled. I tried reproducing the crash but could
not, so I'm pretty sure it is fine. I would appreciate it if someone
else could try it as well though.
(The crash could be reproduced on slow internet, when
`onFetchUserInfoSuccess` was called while the activity was being
destroyed, causing Glide to crash the app because it can't use destroyed
activities. `onFetchUserInfoSuccess` is now no longer called in this
case because it is inside a `lifecycleScope.launch` block.)
Found with Leak canary: The transformation ends up in Glide's memory
cache and leaks whole Activities through the view -> context reference.
This fixes the problem by removing the background detection logic (so
the view reference is no longer needed) and setting the background
directly instead. Looks exactly as before.
Currently translated at 100.0% (634 of 634 strings)
Co-authored-by: fin-w <puf@users.noreply.weblate.tusky.app>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/cy/
Translation: Tusky/Tusky
Currently translated at 100.0% (634 of 634 strings)
Translated using Weblate (Icelandic)
Currently translated at 100.0% (634 of 634 strings)
Co-authored-by: Sveinn í Felli <sv1@fellsnet.is>
Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/is/
Translation: Tusky/Tusky