Merge branch 'develop' into min_api_24
# Conflicts: # app/lint-baseline.xml
This commit is contained in:
commit
b08be1e1b0
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -6,6 +6,25 @@
|
|||
|
||||
### Significant bug fixes
|
||||
|
||||
## v23.0 beta 1
|
||||
|
||||
### New features and other improvements
|
||||
|
||||
- **New preference to scale UI text**, [PR#3248](https://github.com/tuskyapp/Tusky/pull/3248) by [@nikclayton](https://mastodon.social/@nikclayton)
|
||||
|
||||
### Significant bug fixes
|
||||
|
||||
- **Save account information correctly**, [PR#3720](https://github.com/tuskyapp/Tusky/pull/3720) by [@connyduck](https://chaos.social/@ConnyDuck)
|
||||
- If you were logged in with multiple accounts it was possible to switch accounts in a way that the UI showed the new account, but database operations were happening using the old account.
|
||||
- **"pull" notifications on devices running Android versions <= 11**, [PR#3649](https://github.com/tuskyapp/Tusky/pull/3649) by [@nikclayton](https://mastodon.social/@nikclayton)
|
||||
- Pull notifications (i.e., not using ntfy.sh) could silently fail on devices running Android 11 and below
|
||||
- **Work around Android bug where text fields could "forget" they can copy/paste**, [PR#3707](https://github.com/tuskyapp/Tusky/pull/3707) by [@nikclayton](https://mastodon.social/@nikclayton)
|
||||
- **Viewing "diffs" in edit history will not extend off screen edge**, [PR#3431](https://github.com/tuskyapp/Tusky/pull/3431) by [@nikclayton](https://mastodon.social/@nikclayton)
|
||||
- **Don't crash if your server has no post edit history**, [PR#3747](https://github.com/tuskyapp/Tusky/pull/3747) by [@nikclayton](https://mastodon.social/@nikclayton)
|
||||
- Your Mastodon server might know that a post has been edited, but not know the details of those edits. Trying to view the history of those statuses no longer crashes.
|
||||
- **Add a "Delete" button when editing a filter**, [PR#3553](https://github.com/tuskyapp/Tusky/pull/3553) by [@Tak](https://mastodon.gamedev.place/@Tak)
|
||||
- **Show non-square emoji correctly**, [PR#3711](https://github.com/tuskyapp/Tusky/pull/3711) by [@connyduck](https://chaos.social/@ConnyDuck)
|
||||
|
||||
## v22.0
|
||||
|
||||
### New features and other improvements
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.google.ksp)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.kapt)
|
||||
alias(libs.plugins.kotlin.parcelize)
|
||||
|
@ -28,8 +29,8 @@ android {
|
|||
namespace "com.keylesspalace.tusky"
|
||||
minSdk 24
|
||||
targetSdk 33
|
||||
versionCode 110
|
||||
versionName "22.0"
|
||||
versionCode 111
|
||||
versionName "23.0 beta 1"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
|
@ -113,11 +114,9 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
kapt {
|
||||
arguments {
|
||||
arg("room.schemaLocation", "$projectDir/schemas")
|
||||
arg("room.incremental", "true")
|
||||
}
|
||||
ksp {
|
||||
arg("room.schemaLocation", "$projectDir/schemas")
|
||||
arg("room.incremental", "true")
|
||||
}
|
||||
|
||||
configurations {
|
||||
|
@ -134,7 +133,7 @@ dependencies {
|
|||
|
||||
implementation libs.bundles.androidx
|
||||
implementation libs.bundles.room
|
||||
kapt libs.androidx.room.compiler
|
||||
ksp libs.androidx.room.compiler
|
||||
|
||||
implementation libs.android.material
|
||||
|
||||
|
|
|
@ -828,7 +828,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="376"
|
||||
line="379"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -839,7 +839,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="553"
|
||||
line="558"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -850,7 +850,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="774"
|
||||
line="778"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2009,17 +2009,6 @@
|
|||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Overdraw"
|
||||
message="Possible overdraw: Root element paints background `?attr/windowBackgroundColor` with a theme that also paints a background (inferred theme is `@style/TuskyTheme`)"
|
||||
errorLine1=" android:background="?attr/windowBackgroundColor">"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout-sw640dp/fragment_timeline.xml"
|
||||
line="7"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Overdraw"
|
||||
message="Possible overdraw: Root element paints background `?android:attr/colorBackground` with a theme that also paints a background (inferred theme is `@style/TuskyTheme`)"
|
||||
|
@ -2031,17 +2020,6 @@
|
|||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Overdraw"
|
||||
message="Possible overdraw: Root element paints background `?attr/windowBackgroundColor` with a theme that also paints a background (inferred theme is `@style/TuskyTheme`)"
|
||||
errorLine1=" android:background="?attr/windowBackgroundColor">"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout-sw640dp/fragment_timeline_notifications.xml"
|
||||
line="24"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Overdraw"
|
||||
message="Possible overdraw: Root element paints background `?android:attr/colorBackground` with a theme that also paints a background (inferred theme is `@style/TuskyTheme`)"
|
||||
|
@ -2104,51 +2082,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_hashtag.xml"
|
||||
line="6"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Overdraw"
|
||||
message="Possible overdraw: Root element paints background `?android:colorBackground` with a theme that also paints a background (inferred theme is `@style/TuskyTheme`)"
|
||||
errorLine1=" android:background="?android:colorBackground""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_status_bottom_sheet.xml"
|
||||
line="8"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Overdraw"
|
||||
message="Possible overdraw: Root element paints background `@color/dividerColorOther` with a theme that also paints a background (inferred theme is `@style/TuskyTheme`)"
|
||||
errorLine1=" android:background="@color/dividerColorOther""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_status_placeholder.xml"
|
||||
line="34"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Overdraw"
|
||||
message="Possible overdraw: Root element paints background `?android:colorBackground` with a theme that also paints a background (inferred theme is `@style/TuskyTheme`)"
|
||||
errorLine1=" android:background="?android:colorBackground""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_tab_preference.xml"
|
||||
line="7"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Overdraw"
|
||||
message="Possible overdraw: Root element paints background `?attr/selectableItemBackground` with a theme that also paints a background (inferred theme is `@style/TuskyTheme`)"
|
||||
errorLine1=" android:background="?attr/selectableItemBackground""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_tab_preference_small.xml"
|
||||
line="7"
|
||||
line="16"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2456,7 +2390,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="387"
|
||||
line="392"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2467,7 +2401,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="446"
|
||||
line="451"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2478,7 +2412,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="498"
|
||||
line="503"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2489,7 +2423,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="502"
|
||||
line="507"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2500,7 +2434,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="503"
|
||||
line="508"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2511,7 +2445,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="504"
|
||||
line="509"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2522,7 +2456,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="505"
|
||||
line="510"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2533,7 +2467,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="506"
|
||||
line="511"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2544,7 +2478,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="507"
|
||||
line="512"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2555,7 +2489,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="508"
|
||||
line="513"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2566,7 +2500,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="509"
|
||||
line="514"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2577,7 +2511,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="511"
|
||||
line="516"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2588,7 +2522,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="596"
|
||||
line="601"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2599,7 +2533,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="597"
|
||||
line="602"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2610,7 +2544,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="611"
|
||||
line="616"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2621,7 +2555,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="613"
|
||||
line="618"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2632,7 +2566,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="614"
|
||||
line="619"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2643,7 +2577,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="617"
|
||||
line="622"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2654,7 +2588,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="662"
|
||||
line="667"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2665,7 +2599,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="711"
|
||||
line="716"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2676,7 +2610,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="717"
|
||||
line="722"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2687,7 +2621,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="758"
|
||||
line="763"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2698,7 +2632,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="795"
|
||||
line="799"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2918,7 +2852,7 @@
|
|||
errorLine2=" ~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="117"
|
||||
line="116"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2929,7 +2863,7 @@
|
|||
errorLine2=" ~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="124"
|
||||
line="123"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2940,7 +2874,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="195"
|
||||
line="181"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2951,7 +2885,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="205"
|
||||
line="191"
|
||||
column="128"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2962,7 +2896,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="205"
|
||||
line="191"
|
||||
column="128"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2973,7 +2907,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="207"
|
||||
line="193"
|
||||
column="71"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2984,7 +2918,7 @@
|
|||
errorLine2=" ~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="207"
|
||||
line="193"
|
||||
column="63"/>
|
||||
</issue>
|
||||
|
||||
|
@ -2995,7 +2929,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="232"
|
||||
line="218"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3006,7 +2940,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="234"
|
||||
line="220"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3017,7 +2951,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="244"
|
||||
line="230"
|
||||
column="128"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3028,7 +2962,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="244"
|
||||
line="230"
|
||||
column="128"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3039,7 +2973,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="246"
|
||||
line="232"
|
||||
column="71"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3050,7 +2984,7 @@
|
|||
errorLine2=" ~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt"
|
||||
line="246"
|
||||
line="232"
|
||||
column="63"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3160,7 +3094,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt"
|
||||
line="163"
|
||||
line="153"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3171,7 +3105,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt"
|
||||
line="165"
|
||||
line="155"
|
||||
column="29"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3226,7 +3160,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt"
|
||||
line="92"
|
||||
line="91"
|
||||
column="35"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3237,7 +3171,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt"
|
||||
line="93"
|
||||
line="92"
|
||||
column="25"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3248,7 +3182,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt"
|
||||
line="94"
|
||||
line="93"
|
||||
column="43"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3259,7 +3193,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt"
|
||||
line="95"
|
||||
line="94"
|
||||
column="25"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3270,7 +3204,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt"
|
||||
line="207"
|
||||
line="202"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3281,7 +3215,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/instancemute/fragment/InstanceListFragment.kt"
|
||||
line="57"
|
||||
line="56"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3545,7 +3479,7 @@
|
|||
errorLine2=" ~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/account/list/ListsForAccountFragment.kt"
|
||||
line="188"
|
||||
line="178"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
|
@ -3556,7 +3490,7 @@
|
|||
errorLine2=" ~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/account/list/ListsForAccountFragment.kt"
|
||||
line="194"
|
||||
line="184"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
|
@ -4447,7 +4381,7 @@
|
|||
errorLine2=" ~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt"
|
||||
line="89"
|
||||
line="90"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -4458,7 +4392,7 @@
|
|||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt"
|
||||
line="135"
|
||||
line="136"
|
||||
column="17"/>
|
||||
</issue>
|
||||
|
||||
|
@ -4469,7 +4403,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt"
|
||||
line="145"
|
||||
line="146"
|
||||
column="55"/>
|
||||
</issue>
|
||||
|
||||
|
@ -4480,7 +4414,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt"
|
||||
line="145"
|
||||
line="146"
|
||||
column="55"/>
|
||||
</issue>
|
||||
|
||||
|
@ -4491,7 +4425,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt"
|
||||
line="266"
|
||||
line="256"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
|
@ -4502,7 +4436,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt"
|
||||
line="269"
|
||||
line="259"
|
||||
column="33"/>
|
||||
</issue>
|
||||
|
||||
|
@ -4513,7 +4447,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt"
|
||||
line="271"
|
||||
line="261"
|
||||
column="33"/>
|
||||
</issue>
|
||||
|
||||
|
@ -4524,7 +4458,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt"
|
||||
line="277"
|
||||
line="267"
|
||||
column="21"/>
|
||||
</issue>
|
||||
|
||||
|
@ -5052,7 +4986,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="744"
|
||||
line="749"
|
||||
column="55"/>
|
||||
</issue>
|
||||
|
||||
|
@ -5569,7 +5503,7 @@
|
|||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_followed_hashtag.xml"
|
||||
line="27"
|
||||
line="14"
|
||||
column="6"/>
|
||||
</issue>
|
||||
|
||||
|
@ -5580,7 +5514,7 @@
|
|||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_list.xml"
|
||||
line="9"
|
||||
line="14"
|
||||
column="6"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6086,7 +6020,7 @@
|
|||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_tab_preference.xml"
|
||||
line="24"
|
||||
line="26"
|
||||
column="6"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6174,7 +6108,7 @@
|
|||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout-land/item_trending_cell.xml"
|
||||
line="95"
|
||||
line="94"
|
||||
column="10"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6185,7 +6119,7 @@
|
|||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_trending_cell.xml"
|
||||
line="95"
|
||||
line="94"
|
||||
column="10"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6196,7 +6130,7 @@
|
|||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout-land/item_trending_cell.xml"
|
||||
line="126"
|
||||
line="125"
|
||||
column="10"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6207,7 +6141,7 @@
|
|||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_trending_cell.xml"
|
||||
line="127"
|
||||
line="126"
|
||||
column="10"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6394,7 +6328,7 @@
|
|||
errorLine2=" ~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/activity_account.xml"
|
||||
line="469"
|
||||
line="468"
|
||||
column="10"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6449,7 +6383,7 @@
|
|||
errorLine2=" ~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/item_tab_preference.xml"
|
||||
line="13"
|
||||
line="14"
|
||||
column="6"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6768,7 +6702,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/BaseActivity.java"
|
||||
line="59"
|
||||
line="63"
|
||||
column="12"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6779,7 +6713,7 @@
|
|||
errorLine2=" ~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/BaseActivity.java"
|
||||
line="123"
|
||||
line="165"
|
||||
column="51"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6790,7 +6724,7 @@
|
|||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/BaseActivity.java"
|
||||
line="129"
|
||||
line="171"
|
||||
column="42"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6801,7 +6735,7 @@
|
|||
errorLine2=" ~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/BaseActivity.java"
|
||||
line="157"
|
||||
line="199"
|
||||
column="36"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6812,7 +6746,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/BaseActivity.java"
|
||||
line="157"
|
||||
line="199"
|
||||
column="105"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6823,7 +6757,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/BaseActivity.java"
|
||||
line="165"
|
||||
line="207"
|
||||
column="42"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6834,7 +6768,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/BaseActivity.java"
|
||||
line="165"
|
||||
line="207"
|
||||
column="95"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6845,7 +6779,7 @@
|
|||
errorLine2=" ~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/BaseActivity.java"
|
||||
line="233"
|
||||
line="275"
|
||||
column="36"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6856,7 +6790,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/BaseActivity.java"
|
||||
line="233"
|
||||
line="275"
|
||||
column="58"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6867,7 +6801,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="152"
|
||||
line="159"
|
||||
column="55"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6878,7 +6812,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="152"
|
||||
line="159"
|
||||
column="72"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6889,7 +6823,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="152"
|
||||
line="159"
|
||||
column="113"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6900,7 +6834,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="152"
|
||||
line="159"
|
||||
column="132"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6911,7 +6845,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="273"
|
||||
line="280"
|
||||
column="51"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6922,7 +6856,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="273"
|
||||
line="280"
|
||||
column="68"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6933,7 +6867,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="273"
|
||||
line="280"
|
||||
column="109"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6944,7 +6878,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="576"
|
||||
line="626"
|
||||
column="48"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6955,7 +6889,7 @@
|
|||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="604"
|
||||
line="654"
|
||||
column="49"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6966,7 +6900,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="620"
|
||||
line="670"
|
||||
column="46"/>
|
||||
</issue>
|
||||
|
||||
|
@ -6977,7 +6911,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/keylesspalace/tusky/components/notifications/NotificationHelper.java"
|
||||
line="620"
|
||||
line="670"
|
||||
column="87"/>
|
||||
</issue>
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@ import com.keylesspalace.tusky.util.viewBinding
|
|||
import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel
|
||||
import com.keylesspalace.tusky.viewmodel.State
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
private typealias AccountInfo = Pair<TimelineAccount, Boolean>
|
||||
|
@ -146,23 +145,10 @@ class AccountsInListFragment : DialogFragment(), Injectable {
|
|||
|
||||
private fun handleError(error: Throwable) {
|
||||
binding.messageView.show()
|
||||
val retryAction = { _: View ->
|
||||
binding.messageView.setup(error) { _: View ->
|
||||
binding.messageView.hide()
|
||||
viewModel.load(listId)
|
||||
}
|
||||
if (error is IOException) {
|
||||
binding.messageView.setup(
|
||||
R.drawable.elephant_offline,
|
||||
R.string.error_network,
|
||||
retryAction
|
||||
)
|
||||
} else {
|
||||
binding.messageView.setup(
|
||||
R.drawable.elephant_error,
|
||||
R.string.error_generic,
|
||||
retryAction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onRemoveFromList(accountId: String) {
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
package com.keylesspalace.tusky;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
|
@ -45,6 +47,7 @@ import com.keylesspalace.tusky.db.AccountManager;
|
|||
import com.keylesspalace.tusky.di.Injectable;
|
||||
import com.keylesspalace.tusky.interfaces.AccountSelectionListener;
|
||||
import com.keylesspalace.tusky.interfaces.PermissionRequester;
|
||||
import com.keylesspalace.tusky.settings.PrefKeys;
|
||||
import com.keylesspalace.tusky.util.ThemeUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -54,6 +57,7 @@ import java.util.List;
|
|||
import javax.inject.Inject;
|
||||
|
||||
public abstract class BaseActivity extends AppCompatActivity implements Injectable {
|
||||
private static final String TAG = "BaseActivity";
|
||||
|
||||
@Inject
|
||||
public AccountManager accountManager;
|
||||
|
@ -93,6 +97,44 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab
|
|||
requesters = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(newBase);
|
||||
|
||||
// Scale text in the UI from PrefKeys.UI_TEXT_SCALE_RATIO
|
||||
float uiScaleRatio = preferences.getFloat(PrefKeys.UI_TEXT_SCALE_RATIO, 100F);
|
||||
|
||||
Configuration configuration = newBase.getResources().getConfiguration();
|
||||
|
||||
// Adjust `fontScale` in the configuration.
|
||||
//
|
||||
// You can't repeatedly adjust the `fontScale` in `newBase` because that will contain the
|
||||
// result of previous adjustments. E.g., going from 100% to 80% to 100% does not return
|
||||
// you to the original 100%, it leaves it at 80%.
|
||||
//
|
||||
// Instead, calculate the new scale from the application context. This is unaffected by
|
||||
// changes to the base context. It does contain contain any changes to the font scale from
|
||||
// "Settings > Display > Font size" in the device settings, so scaling performed here
|
||||
// is in addition to any scaling in the device settings.
|
||||
Configuration appConfiguration = newBase.getApplicationContext().getResources().getConfiguration();
|
||||
|
||||
// This only adjusts the fonts, anything measured in `dp` is unaffected by this.
|
||||
// You can try to adjust `densityDpi` as shown in the commented out code below. This
|
||||
// works, to a point. However, dialogs do not react well to this. Beyond a certain
|
||||
// scale (~ 120%) the right hand edge of the dialog will clip off the right of the
|
||||
// screen.
|
||||
//
|
||||
// So for now, just adjust the font scale
|
||||
//
|
||||
// val displayMetrics = appContext.resources.displayMetrics
|
||||
// configuration.densityDpi = ((displayMetrics.densityDpi * uiScaleRatio).toInt())
|
||||
configuration.fontScale = appConfiguration.fontScale * uiScaleRatio / 100F;
|
||||
|
||||
Context fontScaleContext = newBase.createConfigurationContext(configuration);
|
||||
|
||||
super.attachBaseContext(fontScaleContext);
|
||||
}
|
||||
|
||||
protected boolean requiresLogin() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import android.os.Bundle
|
|||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
|
@ -42,12 +43,12 @@ import com.google.android.material.snackbar.Snackbar
|
|||
import com.google.android.material.transition.MaterialArcMotion
|
||||
import com.google.android.material.transition.MaterialContainerTransform
|
||||
import com.keylesspalace.tusky.adapter.ItemInteractionListener
|
||||
import com.keylesspalace.tusky.adapter.ListSelectionAdapter
|
||||
import com.keylesspalace.tusky.adapter.TabAdapter
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.MainTabsChangedEvent
|
||||
import com.keylesspalace.tusky.databinding.ActivityTabPreferenceBinding
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.entity.MastoList
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.util.getDimension
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
|
@ -272,7 +273,7 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene
|
|||
}
|
||||
|
||||
private fun showSelectListDialog() {
|
||||
val adapter = ListSelectionAdapter(this)
|
||||
val adapter = ArrayAdapter<MastoList>(this, android.R.layout.simple_list_item_1)
|
||||
|
||||
val statusLayout = LinearLayout(this)
|
||||
statusLayout.gravity = Gravity.CENTER
|
||||
|
@ -298,12 +299,13 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene
|
|||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setView(statusLayout)
|
||||
.setAdapter(adapter) { _, position ->
|
||||
val list = adapter.getItem(position)
|
||||
val newTab = createTabDataFromId(LIST, listOf(list!!.id, list.title))
|
||||
currentTabs.add(newTab)
|
||||
currentTabsAdapter.notifyItemInserted(currentTabs.size - 1)
|
||||
updateAvailableTabs()
|
||||
saveTabs()
|
||||
adapter.getItem(position)?.let { item ->
|
||||
val newTab = createTabDataFromId(LIST, listOf(item.id, item.title))
|
||||
currentTabs.add(newTab)
|
||||
currentTabsAdapter.notifyItemInserted(currentTabs.size - 1)
|
||||
updateAvailableTabs()
|
||||
saveTabs()
|
||||
}
|
||||
}
|
||||
|
||||
val showProgressBarJob = getProgressBarJob(progress, 500)
|
||||
|
|
|
@ -23,6 +23,7 @@ import androidx.work.ExistingPeriodicWorkPolicy
|
|||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import autodispose2.AutoDisposePlugins
|
||||
import com.keylesspalace.tusky.components.notifications.NotificationHelper
|
||||
import com.keylesspalace.tusky.di.AppInjector
|
||||
import com.keylesspalace.tusky.settings.PrefKeys
|
||||
import com.keylesspalace.tusky.settings.SCHEMA_VERSION
|
||||
|
@ -95,6 +96,8 @@ class TuskyApplication : Application(), HasAndroidInjector {
|
|||
Log.w("RxJava", "undeliverable exception", it)
|
||||
}
|
||||
|
||||
NotificationHelper.createWorkerNotificationChannel(this)
|
||||
|
||||
WorkManager.initialize(
|
||||
this,
|
||||
androidx.work.Configuration.Builder()
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/* Copyright 2019 kyori19
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemPickerListBinding
|
||||
import com.keylesspalace.tusky.entity.MastoList
|
||||
|
||||
class ListSelectionAdapter(context: Context) : ArrayAdapter<MastoList>(context, R.layout.item_picker_list) {
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
val binding = if (convertView == null) {
|
||||
ItemPickerListBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
} else {
|
||||
ItemPickerListBinding.bind(convertView)
|
||||
}
|
||||
|
||||
getItem(position)?.let { list ->
|
||||
binding.root.text = list.title
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
}
|
|
@ -40,7 +40,6 @@ import com.keylesspalace.tusky.util.viewBinding
|
|||
import com.keylesspalace.tusky.util.visible
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
class ListsForAccountFragment : DialogFragment(), Injectable {
|
||||
|
@ -103,16 +102,7 @@ class ListsForAccountFragment : DialogFragment(), Injectable {
|
|||
binding.listsView.hide()
|
||||
binding.messageView.apply {
|
||||
show()
|
||||
|
||||
if (error is IOException) {
|
||||
setup(R.drawable.elephant_offline, R.string.error_network) {
|
||||
load()
|
||||
}
|
||||
} else {
|
||||
setup(R.drawable.elephant_error, R.string.error_generic) {
|
||||
load()
|
||||
}
|
||||
}
|
||||
setup(error) { load() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,6 @@ import com.mikepenz.iconics.utils.colorInt
|
|||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
@ -133,12 +132,7 @@ class AccountMediaFragment :
|
|||
}
|
||||
is LoadState.Error -> {
|
||||
binding.statusView.show()
|
||||
|
||||
if ((loadState.refresh as LoadState.Error).error is IOException) {
|
||||
binding.statusView.setup(R.drawable.elephant_offline, R.string.error_network, null)
|
||||
} else {
|
||||
binding.statusView.setup(R.drawable.elephant_error, R.string.error_generic, null)
|
||||
}
|
||||
binding.statusView.setup((loadState.refresh as LoadState.Error).error)
|
||||
}
|
||||
is LoadState.Loading -> {
|
||||
binding.progressBar.show()
|
||||
|
|
|
@ -393,16 +393,9 @@ class AccountListFragment :
|
|||
|
||||
if (adapter.itemCount == 0) {
|
||||
binding.messageView.show()
|
||||
if (throwable is IOException) {
|
||||
binding.messageView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
||||
binding.messageView.hide()
|
||||
this.fetchAccounts(null)
|
||||
}
|
||||
} else {
|
||||
binding.messageView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
||||
binding.messageView.hide()
|
||||
this.fetchAccounts(null)
|
||||
}
|
||||
binding.messageView.setup(throwable) {
|
||||
binding.messageView.hide()
|
||||
this.fetchAccounts(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ data class ConversationStatusEntity(
|
|||
val bookmarked: Boolean,
|
||||
val sensitive: Boolean,
|
||||
val spoilerText: String,
|
||||
val attachments: ArrayList<Attachment>,
|
||||
val attachments: List<Attachment>,
|
||||
val mentions: List<Status.Mention>,
|
||||
val tags: List<HashTag>?,
|
||||
val showingHiddenContent: Boolean,
|
||||
|
|
|
@ -64,7 +64,6 @@ import com.mikepenz.iconics.utils.sizeDp
|
|||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.DurationUnit
|
||||
import kotlin.time.toDuration
|
||||
|
@ -139,16 +138,7 @@ class ConversationsFragment :
|
|||
}
|
||||
is LoadState.Error -> {
|
||||
binding.statusView.show()
|
||||
|
||||
if ((loadState.refresh as LoadState.Error).error is IOException) {
|
||||
binding.statusView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
||||
refreshContent()
|
||||
}
|
||||
} else {
|
||||
binding.statusView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
||||
refreshContent()
|
||||
}
|
||||
}
|
||||
binding.statusView.setup((loadState.refresh as LoadState.Error).error) { refreshContent() }
|
||||
}
|
||||
is LoadState.Loading -> {
|
||||
binding.progressBar.show()
|
||||
|
|
|
@ -31,7 +31,6 @@ import com.keylesspalace.tusky.util.viewBinding
|
|||
import com.keylesspalace.tusky.util.visible
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
class FollowedTagsActivity :
|
||||
|
@ -108,11 +107,7 @@ class FollowedTagsActivity :
|
|||
binding.followedTagsView.hide()
|
||||
binding.followedTagsMessageView.show()
|
||||
val errorState = loadState.refresh as LoadState.Error
|
||||
if (errorState.error is IOException) {
|
||||
binding.followedTagsMessageView.setup(R.drawable.elephant_offline, R.string.error_network) { retry() }
|
||||
} else {
|
||||
binding.followedTagsMessageView.setup(R.drawable.elephant_error, R.string.error_generic) { retry() }
|
||||
}
|
||||
binding.followedTagsMessageView.setup(errorState.error) { retry() }
|
||||
Log.w(TAG, "error loading followed hashtags", errorState.error)
|
||||
} else {
|
||||
binding.followedTagsView.show()
|
||||
|
|
|
@ -26,7 +26,6 @@ import com.keylesspalace.tusky.util.viewBinding
|
|||
import com.keylesspalace.tusky.view.EndlessOnScrollListener
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectable, InstanceActionListener {
|
||||
|
@ -146,16 +145,9 @@ class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectab
|
|||
|
||||
if (adapter.itemCount == 0) {
|
||||
binding.messageView.show()
|
||||
if (throwable is IOException) {
|
||||
binding.messageView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
||||
binding.messageView.hide()
|
||||
this.fetchInstances(null)
|
||||
}
|
||||
} else {
|
||||
binding.messageView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
||||
binding.messageView.hide()
|
||||
this.fetchInstances(null)
|
||||
}
|
||||
binding.messageView.setup(throwable) {
|
||||
binding.messageView.hide()
|
||||
this.fetchInstances(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@ import com.keylesspalace.tusky.entity.Marker
|
|||
import com.keylesspalace.tusky.entity.Notification
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.util.isLessThan
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.delay
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.min
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
/**
|
||||
* Fetch Mastodon notifications and show Android notifications, with summaries, for them.
|
||||
|
@ -29,19 +30,17 @@ class NotificationFetcher @Inject constructor(
|
|||
private val accountManager: AccountManager,
|
||||
private val context: Context
|
||||
) {
|
||||
fun fetchAndShow() {
|
||||
suspend fun fetchAndShow() {
|
||||
for (account in accountManager.getAllAccountsOrderedByActive()) {
|
||||
if (account.notificationsEnabled) {
|
||||
try {
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
// Create sorted list of new notifications
|
||||
val notifications = runBlocking { // OK, because in a worker thread
|
||||
fetchNewNotifications(account)
|
||||
.filter { filterNotification(notificationManager, account, it) }
|
||||
.sortedWith(compareBy({ it.id.length }, { it.id })) // oldest notifications first
|
||||
.toMutableList()
|
||||
}
|
||||
val notifications = fetchNewNotifications(account)
|
||||
.filter { filterNotification(notificationManager, account, it) }
|
||||
.sortedWith(compareBy({ it.id.length }, { it.id })) // oldest notifications first
|
||||
.toMutableList()
|
||||
|
||||
// There's a maximum limit on the number of notifications an Android app
|
||||
// can display. If the total number of notifications (current notifications,
|
||||
|
@ -82,7 +81,7 @@ class NotificationFetcher @Inject constructor(
|
|||
// Android will rate limit / drop notifications if they're posted too
|
||||
// quickly. There is no indication to the user that this happened.
|
||||
// See https://github.com/tuskyapp/Tusky/pull/3626#discussion_r1192963664
|
||||
Thread.sleep(1000)
|
||||
delay(1000.milliseconds)
|
||||
}
|
||||
|
||||
NotificationHelper.updateSummaryNotifications(
|
||||
|
|
|
@ -37,6 +37,7 @@ import android.util.Log;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.RemoteInput;
|
||||
import androidx.core.app.TaskStackBuilder;
|
||||
|
@ -77,7 +78,12 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
public class NotificationHelper {
|
||||
|
||||
private static int notificationId = 0;
|
||||
/** ID of notification shown when fetching notifications */
|
||||
public static final int NOTIFICATION_ID_FETCH_NOTIFICATION = 0;
|
||||
/** ID of notification shown when pruning the cache */
|
||||
public static final int NOTIFICATION_ID_PRUNE_CACHE = 1;
|
||||
/** Dynamic notification IDs start here */
|
||||
private static int notificationId = NOTIFICATION_ID_PRUNE_CACHE + 1;
|
||||
|
||||
/**
|
||||
* constants used in Intents
|
||||
|
@ -121,6 +127,7 @@ public class NotificationHelper {
|
|||
public static final String CHANNEL_SIGN_UP = "CHANNEL_SIGN_UP";
|
||||
public static final String CHANNEL_UPDATES = "CHANNEL_UPDATES";
|
||||
public static final String CHANNEL_REPORT = "CHANNEL_REPORT";
|
||||
public static final String CHANNEL_BACKGROUND_TASKS = "CHANNEL_BACKGROUND_TASKS";
|
||||
|
||||
/**
|
||||
* WorkManager Tag
|
||||
|
@ -471,6 +478,49 @@ public class NotificationHelper {
|
|||
pendingIntentFlags(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a notification channel for notifications for background work that should not
|
||||
* disturb the user.
|
||||
*
|
||||
* @param context context
|
||||
*/
|
||||
public static void createWorkerNotificationChannel(@NonNull Context context) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
|
||||
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
NotificationChannel channel = new NotificationChannel(
|
||||
CHANNEL_BACKGROUND_TASKS,
|
||||
context.getString(R.string.notification_listenable_worker_name),
|
||||
NotificationManager.IMPORTANCE_NONE
|
||||
);
|
||||
|
||||
channel.setDescription(context.getString(R.string.notification_listenable_worker_description));
|
||||
channel.enableLights(false);
|
||||
channel.enableVibration(false);
|
||||
channel.setShowBadge(false);
|
||||
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a notification for a background worker.
|
||||
*
|
||||
* @param context context
|
||||
* @param titleResource String resource to use as the notification's title
|
||||
* @return the notification
|
||||
*/
|
||||
@NonNull
|
||||
public static android.app.Notification createWorkerNotification(@NonNull Context context, @StringRes int titleResource) {
|
||||
String title = context.getString(titleResource);
|
||||
return new NotificationCompat.Builder(context, CHANNEL_BACKGROUND_TASKS)
|
||||
.setContentTitle(title)
|
||||
.setTicker(title)
|
||||
.setSmallIcon(R.drawable.ic_notify)
|
||||
.setOngoing(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static void createNotificationChannelsForAccount(@NonNull AccountEntity account, @NonNull Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
|
||||
|
|
|
@ -95,7 +95,9 @@ class PreferencesActivity :
|
|||
}
|
||||
|
||||
onBackPressedDispatcher.addCallback(this, restartActivitiesOnBackPressedCallback)
|
||||
restartActivitiesOnBackPressedCallback.isEnabled = savedInstanceState?.getBoolean(EXTRA_RESTART_ON_BACK, false) ?: false
|
||||
restartActivitiesOnBackPressedCallback.isEnabled = intent.extras?.getBoolean(
|
||||
EXTRA_RESTART_ON_BACK
|
||||
) ?: savedInstanceState?.getBoolean(EXTRA_RESTART_ON_BACK, false) ?: false
|
||||
}
|
||||
|
||||
override fun onPreferenceStartFragment(
|
||||
|
@ -151,6 +153,10 @@ class PreferencesActivity :
|
|||
restartActivitiesOnBackPressedCallback.isEnabled = true
|
||||
this.restartCurrentActivity()
|
||||
}
|
||||
PrefKeys.UI_TEXT_SCALE_RATIO -> {
|
||||
restartActivitiesOnBackPressedCallback.isEnabled = true
|
||||
this.restartCurrentActivity()
|
||||
}
|
||||
"statusTextSize", "absoluteTimeView", "showBotOverlay", "animateGifAvatars", "useBlurhash",
|
||||
"showSelfUsername", "showCardsInTimelines", "confirmReblogs", "confirmFavourites",
|
||||
"enableSwipeForTabs", "mainNavPosition", PrefKeys.HIDE_TOP_TOOLBAR, PrefKeys.SHOW_STATS_INLINE -> {
|
||||
|
@ -175,7 +181,8 @@ class PreferencesActivity :
|
|||
override fun androidInjector() = androidInjector
|
||||
|
||||
companion object {
|
||||
|
||||
@Suppress("unused")
|
||||
private const val TAG = "PreferencesActivity"
|
||||
const val GENERAL_PREFERENCES = 0
|
||||
const val ACCOUNT_PREFERENCES = 1
|
||||
const val NOTIFICATION_PREFERENCES = 2
|
||||
|
|
|
@ -29,6 +29,7 @@ import com.keylesspalace.tusky.settings.listPreference
|
|||
import com.keylesspalace.tusky.settings.makePreferenceScreen
|
||||
import com.keylesspalace.tusky.settings.preference
|
||||
import com.keylesspalace.tusky.settings.preferenceCategory
|
||||
import com.keylesspalace.tusky.settings.sliderPreference
|
||||
import com.keylesspalace.tusky.settings.switchPreference
|
||||
import com.keylesspalace.tusky.util.LocaleManager
|
||||
import com.keylesspalace.tusky.util.deserialize
|
||||
|
@ -99,6 +100,19 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
|||
preferenceDataStore = localeManager
|
||||
}
|
||||
|
||||
sliderPreference {
|
||||
key = PrefKeys.UI_TEXT_SCALE_RATIO
|
||||
setDefaultValue(100F)
|
||||
valueTo = 150F
|
||||
valueFrom = 50F
|
||||
stepSize = 5F
|
||||
setTitle(R.string.pref_ui_text_size)
|
||||
format = "%.0f%%"
|
||||
decrementIcon = makeIcon(GoogleMaterial.Icon.gmd_zoom_out)
|
||||
incrementIcon = makeIcon(GoogleMaterial.Icon.gmd_zoom_in)
|
||||
icon = makeIcon(GoogleMaterial.Icon.gmd_format_size)
|
||||
}
|
||||
|
||||
listPreference {
|
||||
setDefaultValue("medium")
|
||||
setEntries(R.array.post_text_size_names)
|
||||
|
|
|
@ -47,7 +47,6 @@ import com.mikepenz.iconics.utils.colorInt
|
|||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
class ScheduledStatusActivity :
|
||||
|
@ -102,15 +101,7 @@ class ScheduledStatusActivity :
|
|||
binding.errorMessageView.show()
|
||||
|
||||
val errorState = loadState.refresh as LoadState.Error
|
||||
if (errorState.error is IOException) {
|
||||
binding.errorMessageView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
||||
refreshStatuses()
|
||||
}
|
||||
} else {
|
||||
binding.errorMessageView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
||||
refreshStatuses()
|
||||
}
|
||||
}
|
||||
binding.errorMessageView.setup(errorState.error) { refreshStatuses() }
|
||||
}
|
||||
if (loadState.refresh != LoadState.Loading) {
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
|
|
|
@ -15,15 +15,28 @@
|
|||
|
||||
package com.keylesspalace.tusky.components.search.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import com.keylesspalace.tusky.components.search.adapter.SearchAccountsAdapter
|
||||
import com.keylesspalace.tusky.entity.TimelineAccount
|
||||
import com.keylesspalace.tusky.settings.PrefKeys
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class SearchAccountsFragment : SearchFragment<TimelineAccount>() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.searchRecyclerView.addItemDecoration(
|
||||
DividerItemDecoration(
|
||||
binding.searchRecyclerView.context,
|
||||
DividerItemDecoration.VERTICAL
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun createAdapter(): PagingDataAdapter<TimelineAccount, *> {
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(binding.searchRecyclerView.context)
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.paging.LoadState
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
|
@ -129,7 +128,6 @@ abstract class SearchFragment<T : Any> :
|
|||
}
|
||||
|
||||
private fun initAdapter() {
|
||||
binding.searchRecyclerView.addItemDecoration(DividerItemDecoration(binding.searchRecyclerView.context, DividerItemDecoration.VERTICAL))
|
||||
binding.searchRecyclerView.layoutManager = LinearLayoutManager(binding.searchRecyclerView.context)
|
||||
adapter = createAdapter()
|
||||
binding.searchRecyclerView.adapter = adapter
|
||||
|
|
|
@ -15,8 +15,11 @@
|
|||
|
||||
package com.keylesspalace.tusky.components.search.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import com.keylesspalace.tusky.components.search.adapter.SearchHashtagsAdapter
|
||||
import com.keylesspalace.tusky.entity.HashTag
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
@ -26,6 +29,16 @@ class SearchHashtagsFragment : SearchFragment<HashTag>() {
|
|||
override val data: Flow<PagingData<HashTag>>
|
||||
get() = viewModel.hashtagsFlow
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.searchRecyclerView.addItemDecoration(
|
||||
DividerItemDecoration(
|
||||
binding.searchRecyclerView.context,
|
||||
DividerItemDecoration.VERTICAL
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun createAdapter(): PagingDataAdapter<HashTag, *> = SearchHashtagsAdapter(this)
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -79,7 +79,6 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
|||
import io.reactivex.rxjava3.core.Observable
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -242,16 +241,7 @@ class TimelineFragment :
|
|||
}
|
||||
is LoadState.Error -> {
|
||||
binding.statusView.show()
|
||||
|
||||
if ((loadState.refresh as LoadState.Error).error is IOException) {
|
||||
binding.statusView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
||||
onRefresh()
|
||||
}
|
||||
} else {
|
||||
binding.statusView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
||||
onRefresh()
|
||||
}
|
||||
}
|
||||
binding.statusView.setup((loadState.refresh as LoadState.Error).error) { onRefresh() }
|
||||
}
|
||||
is LoadState.Loading -> {
|
||||
binding.progressBar.show()
|
||||
|
|
|
@ -60,7 +60,6 @@ import kotlinx.coroutines.CoroutineStart
|
|||
import kotlinx.coroutines.awaitCancellation
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
class ViewThreadFragment :
|
||||
|
@ -201,21 +200,7 @@ class ViewThreadFragment :
|
|||
binding.recyclerView.hide()
|
||||
binding.statusView.show()
|
||||
|
||||
if (uiState.throwable is IOException) {
|
||||
binding.statusView.setup(
|
||||
R.drawable.elephant_offline,
|
||||
R.string.error_network
|
||||
) {
|
||||
viewModel.retry(thisThreadsStatusId)
|
||||
}
|
||||
} else {
|
||||
binding.statusView.setup(
|
||||
R.drawable.elephant_error,
|
||||
R.string.error_generic
|
||||
) {
|
||||
viewModel.retry(thisThreadsStatusId)
|
||||
}
|
||||
}
|
||||
binding.statusView.setup(uiState.throwable) { viewModel.retry(thisThreadsStatusId) }
|
||||
}
|
||||
is ThreadUiState.Success -> {
|
||||
if (uiState.statusViewData.none { viewData -> viewData.isDetailed }) {
|
||||
|
|
|
@ -53,7 +53,6 @@ import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
|
|||
import com.mikepenz.iconics.utils.colorInt
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
class ViewEditsFragment :
|
||||
|
@ -111,13 +110,17 @@ class ViewEditsFragment :
|
|||
binding.statusView.show()
|
||||
binding.initialProgressBar.hide()
|
||||
|
||||
if (uiState.throwable is IOException) {
|
||||
binding.statusView.setup(R.drawable.elephant_offline, R.string.error_network) {
|
||||
viewModel.loadEdits(statusId, force = true)
|
||||
when (uiState.throwable) {
|
||||
is ViewEditsViewModel.MissingEditsException -> {
|
||||
binding.statusView.setup(
|
||||
R.drawable.elephant_friend_empty,
|
||||
R.string.error_missing_edits
|
||||
)
|
||||
}
|
||||
} else {
|
||||
binding.statusView.setup(R.drawable.elephant_error, R.string.error_generic) {
|
||||
viewModel.loadEdits(statusId, force = true)
|
||||
else -> {
|
||||
binding.statusView.setup(uiState.throwable) {
|
||||
viewModel.loadEdits(statusId, force = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ package com.keylesspalace.tusky.components.viewthread.edits
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import at.connyduck.calladapter.networkresult.fold
|
||||
import at.connyduck.calladapter.networkresult.getOrElse
|
||||
import com.keylesspalace.tusky.components.viewthread.edits.TuskyTagHandler.Companion.DELETED_TEXT_EL
|
||||
import com.keylesspalace.tusky.components.viewthread.edits.TuskyTagHandler.Companion.INSERTED_TEXT_EL
|
||||
import com.keylesspalace.tusky.entity.StatusEdit
|
||||
|
@ -48,6 +48,9 @@ class ViewEditsViewModel @Inject constructor(private val api: MastodonApi) : Vie
|
|||
private val _uiState: MutableStateFlow<EditsUiState> = MutableStateFlow(EditsUiState.Initial)
|
||||
val uiState: StateFlow<EditsUiState> = _uiState.asStateFlow()
|
||||
|
||||
/** The API call to fetch edit history returned less than two items */
|
||||
object MissingEditsException : Exception()
|
||||
|
||||
fun loadEdits(statusId: String, force: Boolean = false, refreshing: Boolean = false) {
|
||||
if (!force && _uiState.value !is EditsUiState.Initial) return
|
||||
|
||||
|
@ -58,63 +61,68 @@ class ViewEditsViewModel @Inject constructor(private val api: MastodonApi) : Vie
|
|||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
api.statusEdits(statusId).fold(
|
||||
{ edits ->
|
||||
// Diff each status' content against the previous version, producing new
|
||||
// content with additional `ins` or `del` elements marking inserted or
|
||||
// deleted content.
|
||||
//
|
||||
// This can be CPU intensive depending on the number of edits and the size
|
||||
// of each, so don't run this on Dispatchers.Main.
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
val sortedEdits = edits.sortedBy { it.createdAt }
|
||||
.reversed()
|
||||
.toMutableList()
|
||||
val edits = api.statusEdits(statusId).getOrElse {
|
||||
_uiState.value = EditsUiState.Error(it)
|
||||
return@launch
|
||||
}
|
||||
|
||||
SAXLoader.setXMLReaderClass("org.xmlpull.v1.sax2.Driver")
|
||||
val loader = SAXLoader()
|
||||
loader.config = DiffConfig(
|
||||
false,
|
||||
WhiteSpaceProcessing.PRESERVE,
|
||||
TextGranularity.SPACE_WORD
|
||||
// `edits` might have fewer than the minimum number of entries because of
|
||||
// https://github.com/mastodon/mastodon/issues/25398.
|
||||
if (edits.size < 2) {
|
||||
_uiState.value = EditsUiState.Error(MissingEditsException)
|
||||
return@launch
|
||||
}
|
||||
|
||||
// Diff each status' content against the previous version, producing new
|
||||
// content with additional `ins` or `del` elements marking inserted or
|
||||
// deleted content.
|
||||
//
|
||||
// This can be CPU intensive depending on the number of edits and the size
|
||||
// of each, so don't run this on Dispatchers.Main.
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
val sortedEdits = edits.sortedBy { it.createdAt }
|
||||
.reversed()
|
||||
.toMutableList()
|
||||
|
||||
SAXLoader.setXMLReaderClass("org.xmlpull.v1.sax2.Driver")
|
||||
val loader = SAXLoader()
|
||||
loader.config = DiffConfig(
|
||||
false,
|
||||
WhiteSpaceProcessing.PRESERVE,
|
||||
TextGranularity.SPACE_WORD
|
||||
)
|
||||
val processor = OptimisticXMLProcessor()
|
||||
processor.setCoalesce(true)
|
||||
val output = HtmlDiffOutput()
|
||||
|
||||
try {
|
||||
// The XML processor expects `br` to be closed
|
||||
var currentContent =
|
||||
loader.load(sortedEdits[0].content.replace("<br>", "<br/>"))
|
||||
var previousContent =
|
||||
loader.load(sortedEdits[1].content.replace("<br>", "<br/>"))
|
||||
|
||||
for (i in 1 until sortedEdits.size) {
|
||||
processor.diff(previousContent, currentContent, output)
|
||||
sortedEdits[i - 1] = sortedEdits[i - 1].copy(
|
||||
content = output.xml.toString()
|
||||
)
|
||||
val processor = OptimisticXMLProcessor()
|
||||
processor.setCoalesce(true)
|
||||
val output = HtmlDiffOutput()
|
||||
|
||||
try {
|
||||
// The XML processor expects `br` to be closed
|
||||
var currentContent =
|
||||
loader.load(sortedEdits[0].content.replace("<br>", "<br/>"))
|
||||
var previousContent =
|
||||
loader.load(sortedEdits[1].content.replace("<br>", "<br/>"))
|
||||
|
||||
for (i in 1 until sortedEdits.size) {
|
||||
processor.diff(previousContent, currentContent, output)
|
||||
sortedEdits[i - 1] = sortedEdits[i - 1].copy(
|
||||
content = output.xml.toString()
|
||||
)
|
||||
|
||||
if (i < sortedEdits.size - 1) {
|
||||
currentContent = previousContent
|
||||
previousContent = loader.load(
|
||||
sortedEdits[i + 1].content.replace("<br>", "<br/>")
|
||||
)
|
||||
}
|
||||
}
|
||||
_uiState.value = EditsUiState.Success(sortedEdits)
|
||||
} catch (_: LoadingException) {
|
||||
// Something failed parsing the XML from the server. Rather than
|
||||
// show an error just return the sorted edits so the user can at
|
||||
// least visually scan the differences.
|
||||
_uiState.value = EditsUiState.Success(sortedEdits)
|
||||
if (i < sortedEdits.size - 1) {
|
||||
currentContent = previousContent
|
||||
previousContent = loader.load(
|
||||
sortedEdits[i + 1].content.replace("<br>", "<br/>")
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{ throwable ->
|
||||
_uiState.value = EditsUiState.Error(throwable)
|
||||
_uiState.value = EditsUiState.Success(sortedEdits)
|
||||
} catch (_: LoadingException) {
|
||||
// Something failed parsing the XML from the server. Rather than
|
||||
// show an error just return the sorted edits so the user can at
|
||||
// least visually scan the differences.
|
||||
_uiState.value = EditsUiState.Success(sortedEdits)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -102,8 +102,8 @@ class Converters @Inject constructor(
|
|||
}
|
||||
|
||||
@TypeConverter
|
||||
fun jsonToAttachmentList(attachmentListJson: String?): ArrayList<Attachment>? {
|
||||
return gson.fromJson(attachmentListJson, object : TypeToken<ArrayList<Attachment>>() {}.type)
|
||||
fun jsonToAttachmentList(attachmentListJson: String?): List<Attachment>? {
|
||||
return gson.fromJson(attachmentListJson, object : TypeToken<List<Attachment>>() {}.type)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package com.keylesspalace.tusky.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.util.ArrayList
|
||||
import java.util.Date
|
||||
|
||||
data class DeletedStatus(
|
||||
|
@ -25,7 +24,7 @@ data class DeletedStatus(
|
|||
@SerializedName("spoiler_text") val spoilerText: String,
|
||||
val visibility: Status.Visibility,
|
||||
val sensitive: Boolean,
|
||||
@SerializedName("media_attachments") val attachments: ArrayList<Attachment>?,
|
||||
@SerializedName("media_attachments") val attachments: List<Attachment>?,
|
||||
val poll: Poll?,
|
||||
@SerializedName("created_at") val createdAt: Date,
|
||||
val language: String?
|
||||
|
|
|
@ -19,7 +19,6 @@ import android.text.SpannableStringBuilder
|
|||
import android.text.style.URLSpan
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.keylesspalace.tusky.util.parseAsMastodonHtml
|
||||
import java.util.ArrayList
|
||||
import java.util.Date
|
||||
|
||||
data class Status(
|
||||
|
@ -42,7 +41,7 @@ data class Status(
|
|||
val sensitive: Boolean,
|
||||
@SerializedName("spoiler_text") val spoilerText: String,
|
||||
val visibility: Visibility,
|
||||
@SerializedName("media_attachments") val attachments: ArrayList<Attachment>,
|
||||
@SerializedName("media_attachments") val attachments: List<Attachment>,
|
||||
val mentions: List<Mention>,
|
||||
val tags: List<HashTag>?,
|
||||
val application: Application?,
|
||||
|
|
|
@ -101,4 +101,7 @@ object PrefKeys {
|
|||
|
||||
const val TAB_FILTER_HOME_REPLIES = "tabFilterHomeReplies_v2" // This was changed once to reset an unintentionally set default.
|
||||
const val TAB_FILTER_HOME_BOOSTS = "tabFilterHomeBoosts"
|
||||
|
||||
/** UI text scaling factor, stored as float, 100 = 100% = no scaling */
|
||||
const val UI_TEXT_SCALE_RATIO = "uiTextScaleRatio"
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.preference.PreferenceCategory
|
|||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreference
|
||||
import com.keylesspalace.tusky.view.SliderPreference
|
||||
import de.c1710.filemojicompat_ui.views.picker.preference.EmojiPickerPreference
|
||||
|
||||
class PreferenceParent(
|
||||
|
@ -43,6 +44,15 @@ inline fun <A> PreferenceParent.emojiPreference(activity: A, builder: EmojiPicke
|
|||
return pref
|
||||
}
|
||||
|
||||
inline fun PreferenceParent.sliderPreference(
|
||||
builder: SliderPreference.() -> Unit
|
||||
): SliderPreference {
|
||||
val pref = SliderPreference(context)
|
||||
builder(pref)
|
||||
addPref(pref)
|
||||
return pref
|
||||
}
|
||||
|
||||
inline fun PreferenceParent.switchPreference(
|
||||
builder: SwitchPreference.() -> Unit
|
||||
): SwitchPreference {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package com.keylesspalace.tusky.util
|
||||
|
||||
import android.content.Context
|
||||
import com.keylesspalace.tusky.R
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* checks if this throwable indicates an error causes by a 4xx/5xx server response and
|
||||
|
@ -24,3 +27,16 @@ fun Throwable.getServerErrorMessage(): String? {
|
|||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/** @return A drawable resource to accompany the error message for this throwable */
|
||||
fun Throwable.getDrawableRes(): Int = when (this) {
|
||||
is IOException -> R.drawable.elephant_offline
|
||||
is HttpException -> R.drawable.elephant_offline
|
||||
else -> R.drawable.elephant_error
|
||||
}
|
||||
|
||||
/** @return A string error message for this throwable */
|
||||
fun Throwable.getErrorString(context: Context): String = getServerErrorMessage() ?: when (this) {
|
||||
is IOException -> context.getString(R.string.error_network)
|
||||
else -> context.getString(R.string.error_generic)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.keylesspalace.tusky.view
|
||||
|
||||
import android.content.Context
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
|
@ -12,6 +13,8 @@ import androidx.annotation.StringRes
|
|||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ViewBackgroundMessageBinding
|
||||
import com.keylesspalace.tusky.util.addDrawables
|
||||
import com.keylesspalace.tusky.util.getDrawableRes
|
||||
import com.keylesspalace.tusky.util.getErrorString
|
||||
import com.keylesspalace.tusky.util.visible
|
||||
|
||||
/**
|
||||
|
@ -34,16 +37,27 @@ class BackgroundMessageView @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun setup(throwable: Throwable, listener: ((v: View) -> Unit)? = null) {
|
||||
setup(throwable.getDrawableRes(), throwable.getErrorString(context), listener)
|
||||
}
|
||||
|
||||
fun setup(
|
||||
@DrawableRes imageRes: Int,
|
||||
@StringRes messageRes: Int,
|
||||
clickListener: ((v: View) -> Unit)? = null
|
||||
) = setup(imageRes, context.getString(messageRes), clickListener)
|
||||
|
||||
/**
|
||||
* Setup image, message and button.
|
||||
* If [clickListener] is `null` then the button will be hidden.
|
||||
*/
|
||||
fun setup(
|
||||
@DrawableRes imageRes: Int,
|
||||
@StringRes messageRes: Int,
|
||||
message: String,
|
||||
clickListener: ((v: View) -> Unit)? = null
|
||||
) {
|
||||
binding.messageTextView.setText(messageRes)
|
||||
binding.messageTextView.text = message
|
||||
binding.messageTextView.movementMethod = LinkMovementMethod.getInstance()
|
||||
binding.imageView.setImageResource(imageRes)
|
||||
binding.button.setOnClickListener(clickListener)
|
||||
binding.button.visible(clickListener != null)
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
package com.keylesspalace.tusky.view
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.TypedArray
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.View.VISIBLE
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import com.google.android.material.slider.LabelFormatter.LABEL_GONE
|
||||
import com.google.android.material.slider.Slider
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.PrefSliderBinding
|
||||
import java.lang.Float.max
|
||||
import java.lang.Float.min
|
||||
|
||||
/**
|
||||
* Slider preference
|
||||
*
|
||||
* Similar to [androidx.preference.SeekBarPreference], but better because:
|
||||
*
|
||||
* - Uses a [Slider] instead of a [android.widget.SeekBar]. Slider supports float values, and step sizes
|
||||
* other than 1.
|
||||
* - Displays the currently selected value in the Preference's summary, for consistency
|
||||
* with platform norms.
|
||||
* - Icon buttons can be displayed at the start/end of the slider. Pressing them will
|
||||
* increment/decrement the slider by `stepSize`.
|
||||
* - User can supply a custom formatter to format the summary value
|
||||
*/
|
||||
class SliderPreference @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = androidx.preference.R.attr.preferenceStyle,
|
||||
defStyleRes: Int = 0
|
||||
) : Preference(context, attrs, defStyleAttr, defStyleRes),
|
||||
Slider.OnChangeListener,
|
||||
Slider.OnSliderTouchListener {
|
||||
|
||||
/** Backing property for `value` */
|
||||
private var _value = 0F
|
||||
|
||||
/**
|
||||
* @see Slider.getValue
|
||||
* @see Slider.setValue
|
||||
*/
|
||||
var value: Float = defaultValue
|
||||
get() = _value
|
||||
set(v) {
|
||||
val clamped = max(max(v, valueFrom), min(v, valueTo))
|
||||
if (clamped == field) return
|
||||
_value = clamped
|
||||
persistFloat(v)
|
||||
notifyChanged()
|
||||
}
|
||||
|
||||
/** @see Slider.setValueFrom */
|
||||
var valueFrom: Float
|
||||
|
||||
/** @see Slider.setValueTo */
|
||||
var valueTo: Float
|
||||
|
||||
/** @see Slider.setStepSize */
|
||||
var stepSize: Float
|
||||
|
||||
/**
|
||||
* Format string to be applied to values before setting the summary. For more control set
|
||||
* [SliderPreference.formatter]
|
||||
*/
|
||||
var format: String = defaultFormat
|
||||
|
||||
/**
|
||||
* Function that will be used to format the summary. The default formatter formats using the
|
||||
* value of the [SliderPreference.format] property.
|
||||
*/
|
||||
var formatter: (Float) -> String = { format.format(it) }
|
||||
|
||||
/**
|
||||
* Optional icon to show in a button at the start of the slide. If non-null the button is
|
||||
* shown. Clicking the button decrements the value by one step.
|
||||
*/
|
||||
var decrementIcon: Drawable? = null
|
||||
|
||||
/**
|
||||
* Optional icon to show in a button at the end of the slider. If non-null the button is
|
||||
* shown. Clicking the button increments the value by one step.
|
||||
*/
|
||||
var incrementIcon: Drawable? = null
|
||||
|
||||
/** View binding */
|
||||
private lateinit var binding: PrefSliderBinding
|
||||
|
||||
init {
|
||||
// Using `widgetLayoutResource` here would be incorrect, as that tries to put the entire
|
||||
// preference layout to the right of the title and summary.
|
||||
layoutResource = R.layout.pref_slider
|
||||
|
||||
val a = context.obtainStyledAttributes(attrs, R.styleable.SliderPreference, defStyleAttr, defStyleRes)
|
||||
|
||||
value = a.getFloat(R.styleable.SliderPreference_android_value, defaultValue)
|
||||
valueFrom = a.getFloat(R.styleable.SliderPreference_android_valueFrom, defaultValueFrom)
|
||||
valueTo = a.getFloat(R.styleable.SliderPreference_android_valueTo, defaultValueTo)
|
||||
stepSize = a.getFloat(R.styleable.SliderPreference_android_stepSize, defaultStepSize)
|
||||
format = a.getString(R.styleable.SliderPreference_format) ?: defaultFormat
|
||||
|
||||
val decrementIconResource = a.getResourceId(R.styleable.SliderPreference_iconStart, -1)
|
||||
if (decrementIconResource != -1) {
|
||||
decrementIcon = AppCompatResources.getDrawable(context, decrementIconResource)
|
||||
}
|
||||
|
||||
val incrementIconResource = a.getResourceId(R.styleable.SliderPreference_iconEnd, -1)
|
||||
if (incrementIconResource != -1) {
|
||||
incrementIcon = AppCompatResources.getDrawable(context, incrementIconResource)
|
||||
}
|
||||
|
||||
a.recycle()
|
||||
}
|
||||
|
||||
override fun onGetDefaultValue(a: TypedArray, i: Int): Any {
|
||||
return a.getFloat(i, defaultValue)
|
||||
}
|
||||
|
||||
override fun onSetInitialValue(defaultValue: Any?) {
|
||||
value = getPersistedFloat((defaultValue ?: Companion.defaultValue) as Float)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
super.onBindViewHolder(holder)
|
||||
binding = PrefSliderBinding.bind(holder.itemView)
|
||||
|
||||
binding.root.isClickable = false
|
||||
|
||||
binding.slider.addOnChangeListener(this)
|
||||
binding.slider.addOnSliderTouchListener(this)
|
||||
binding.slider.value = value // sliderValue
|
||||
binding.slider.valueTo = valueTo
|
||||
binding.slider.valueFrom = valueFrom
|
||||
binding.slider.stepSize = stepSize
|
||||
|
||||
// Disable the label, the value is shown in the preference summary
|
||||
binding.slider.labelBehavior = LABEL_GONE
|
||||
binding.slider.isEnabled = isEnabled
|
||||
|
||||
binding.summary.visibility = VISIBLE
|
||||
binding.summary.text = formatter(value)
|
||||
|
||||
decrementIcon?.let { icon ->
|
||||
binding.decrement.icon = icon
|
||||
binding.decrement.visibility = VISIBLE
|
||||
binding.decrement.setOnClickListener {
|
||||
value -= stepSize
|
||||
}
|
||||
}
|
||||
|
||||
incrementIcon?.let { icon ->
|
||||
binding.increment.icon = icon
|
||||
binding.increment.visibility = VISIBLE
|
||||
binding.increment.setOnClickListener {
|
||||
value += stepSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
|
||||
if (!fromUser) return
|
||||
binding.summary.text = formatter(value)
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(slider: Slider) {
|
||||
// Deliberately empty
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(slider: Slider) {
|
||||
value = slider.value
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "SliderPreference"
|
||||
private const val defaultValueFrom = 0F
|
||||
private const val defaultValueTo = 1F
|
||||
private const val defaultValue = 0.5F
|
||||
private const val defaultStepSize = 0.1F
|
||||
private const val defaultFormat = "%3.1f"
|
||||
}
|
||||
}
|
|
@ -17,10 +17,15 @@
|
|||
|
||||
package com.keylesspalace.tusky.worker
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.Context
|
||||
import androidx.work.Worker
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.WorkerParameters
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.components.notifications.NotificationFetcher
|
||||
import com.keylesspalace.tusky.components.notifications.NotificationHelper
|
||||
import com.keylesspalace.tusky.components.notifications.NotificationHelper.NOTIFICATION_ID_FETCH_NOTIFICATION
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Fetch and show new notifications. */
|
||||
|
@ -28,16 +33,20 @@ class NotificationWorker(
|
|||
appContext: Context,
|
||||
params: WorkerParameters,
|
||||
private val notificationsFetcher: NotificationFetcher
|
||||
) : Worker(appContext, params) {
|
||||
override fun doWork(): Result {
|
||||
) : CoroutineWorker(appContext, params) {
|
||||
val notification: Notification = NotificationHelper.createWorkerNotification(applicationContext, R.string.notification_notification_worker)
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
notificationsFetcher.fetchAndShow()
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
override suspend fun getForegroundInfo() = ForegroundInfo(NOTIFICATION_ID_FETCH_NOTIFICATION, notification)
|
||||
|
||||
class Factory @Inject constructor(
|
||||
private val notificationsFetcher: NotificationFetcher
|
||||
) : ChildWorkerFactory {
|
||||
override fun createWorker(appContext: Context, params: WorkerParameters): Worker {
|
||||
override fun createWorker(appContext: Context, params: WorkerParameters): CoroutineWorker {
|
||||
return NotificationWorker(appContext, params, notificationsFetcher)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,11 +17,16 @@
|
|||
|
||||
package com.keylesspalace.tusky.worker
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.ListenableWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.components.notifications.NotificationHelper
|
||||
import com.keylesspalace.tusky.components.notifications.NotificationHelper.NOTIFICATION_ID_PRUNE_CACHE
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.db.AppDatabase
|
||||
import javax.inject.Inject
|
||||
|
@ -33,6 +38,8 @@ class PruneCacheWorker(
|
|||
private val appDatabase: AppDatabase,
|
||||
private val accountManager: AccountManager
|
||||
) : CoroutineWorker(appContext, workerParams) {
|
||||
val notification: Notification = NotificationHelper.createWorkerNotification(applicationContext, R.string.notification_prune_cache)
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
for (account in accountManager.accounts) {
|
||||
Log.d(TAG, "Pruning database using account ID: ${account.id}")
|
||||
|
@ -41,6 +48,8 @@ class PruneCacheWorker(
|
|||
return Result.success()
|
||||
}
|
||||
|
||||
override suspend fun getForegroundInfo() = ForegroundInfo(NOTIFICATION_ID_PRUNE_CACHE, notification)
|
||||
|
||||
companion object {
|
||||
private const val TAG = "PruneCacheWorker"
|
||||
private const val MAX_STATUSES_IN_CACHE = 1000
|
||||
|
|
|
@ -80,14 +80,13 @@
|
|||
android:id="@+id/tag"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="none"
|
||||
android:ellipsize="end"
|
||||
android:importantForAccessibility="no"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="textStart"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="normal"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="#itishashtagtuesdayitishashtagtuesday" />
|
||||
|
|
|
@ -443,8 +443,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface"
|
||||
app:tabGravity="center"
|
||||
app:tabMode="scrollable"
|
||||
app:tabTextAppearance="@style/TuskyTabAppearance" />
|
||||
app:tabMode="scrollable" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:visibility="gone"
|
||||
/>
|
||||
|
||||
<ProgressBar
|
||||
|
@ -33,6 +34,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:visibility="gone"
|
||||
/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
|
|
|
@ -28,8 +28,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
app:tabGravity="fill"
|
||||
app:tabMaxWidth="0dp"
|
||||
app:tabMode="fixed"
|
||||
app:tabTextAppearance="@style/TuskyTabAppearance" />
|
||||
app:tabMode="fixed" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
|
|
@ -1,41 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="72dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/followed_tag"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
tools:text="hashtag" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/followed_tag_unfollow"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/action_unfollow"
|
||||
android:padding="4dp"
|
||||
app:srcCompat="@drawable/ic_person_remove_24dp"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/followed_tag"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:gravity="center_vertical"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
tools:text="#hashtag" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
|
@ -1,7 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- Copied from android.R.layout.simple_list_item_1, because view binding does not work with
|
||||
android.R.layout.* -->
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:textSize="?attr/status_text_medium" />
|
||||
tools:ignore="SelectableText" />
|
||||
|
|
|
@ -4,30 +4,29 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
tools:ignore="Overdraw">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/list_name_textview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="?selectableItemBackground"
|
||||
android:drawablePadding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
tools:text="Example list" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/editListButton"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/action_more"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:src="@drawable/ic_more_horiz_24dp" />
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:textColor="@color/textColorSecondary"
|
||||
android:textSize="?attr/status_text_medium" />
|
|
@ -6,9 +6,10 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:background="?android:colorBackground"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="16dp">
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
|
@ -19,7 +20,8 @@
|
|||
android:paddingBottom="8dp"
|
||||
android:src="@drawable/ic_drag_indicator_24dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/textView"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
|
@ -30,8 +32,7 @@
|
|||
android:drawablePadding="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="?attr/status_text_large"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
app:drawableTint="?android:attr/textColorSecondary"
|
||||
app:layout_constraintBottom_toTopOf="@id/chipGroup"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
android:lines="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="?attr/status_text_large"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
app:drawableStartCompat="@drawable/ic_home_24dp"
|
||||
app:drawableTint="?android:attr/textColorSecondary" />
|
||||
|
||||
|
|
|
@ -80,14 +80,13 @@
|
|||
android:id="@+id/tag"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="none"
|
||||
android:ellipsize="end"
|
||||
android:importantForAccessibility="no"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="textStart"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="normal"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="#itishashtagtuesdayitishashtagtuesday" />
|
||||
|
@ -107,7 +106,7 @@
|
|||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tag"
|
||||
tools:text="12 345" />
|
||||
tools:text="12 34" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/usageLabel"
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2018 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- Layout used by SeekBarPreference for the seekbar widget style. Minimally adapted for use
|
||||
with Slider instead of SeekBar. -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<include layout="@layout/image_frame"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:labelFor="@id/slider"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:ellipsize="marquee"
|
||||
tools:ignore="LabelFor,SelectableText" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@android:id/title"
|
||||
android:layout_alignStart="@android:id/title"
|
||||
android:layout_gravity="start"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:maxLines="4"
|
||||
style="@style/PreferenceSummaryTextStyle"
|
||||
tools:ignore="SelectableText" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<!-- Using UnPressableLinearLayout as a workaround to disable the pressed state propagation
|
||||
to the children of this container layout. Otherwise, the animated pressed state will also
|
||||
play for the thumb in the AbsSeekBar in addition to the preference's ripple background.
|
||||
The background of the SeekBar is also set to null to disable the ripple background -->
|
||||
<androidx.preference.UnPressableLinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingRight="0dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/decrement"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
style="@style/Widget.Material3.Button.IconButton" />
|
||||
|
||||
<!-- The total height of the Seekbar widget's area should be 48dp - this allows for an
|
||||
increased touch area so you do not need to exactly tap the thumb to move it. However,
|
||||
setting the Seekbar height directly causes the thumb and seekbar to be misaligned on
|
||||
API 22 and 23 - so instead we just set 15dp padding above and below, to account for the
|
||||
18dp default height of the Seekbar thumb for a total of 48dp.
|
||||
Note: we set 0dp padding at the start and end of this seekbar to allow it to properly
|
||||
fit into the layout, but this means that there's no leeway on either side for touch
|
||||
input - this might be something we should reconsider down the line. -->
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/slider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="@dimen/preference_seekbar_padding_horizontal"
|
||||
android:paddingStart="@dimen/preference_seekbar_padding_horizontal"
|
||||
android:paddingRight="@dimen/preference_seekbar_padding_horizontal"
|
||||
android:paddingEnd="@dimen/preference_seekbar_padding_horizontal"
|
||||
android:paddingTop="@dimen/preference_seekbar_padding_vertical"
|
||||
android:paddingBottom="@dimen/preference_seekbar_padding_vertical"
|
||||
android:background="@null"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/increment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
style="@style/Widget.Material3.Button.IconButton" />
|
||||
</androidx.preference.UnPressableLinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
|
@ -35,7 +35,7 @@
|
|||
android:scaleType="centerInside"
|
||||
android:src="@drawable/elephant_offline" />
|
||||
|
||||
<TextView
|
||||
<com.keylesspalace.tusky.view.ClickableSpanTextView
|
||||
android:id="@+id/messageTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -665,4 +665,8 @@
|
|||
<string name="select_list_manage">مدیریت سیاههها</string>
|
||||
<string name="error_list_load">خطا در بار کردن سیاههها</string>
|
||||
<string name="load_newest_notifications">بار کردن جدیدترین آگاهیها</string>
|
||||
<string name="compose_delete_draft">حذف پیشنویس؟</string>
|
||||
<string name="error_missing_edits">کارسازتان میداند که این فرسته ویرایش شده؛ ولی رونوشتی از ویرایشها ندارد. پس نمیتوانند نشانتان داده شوند.
|
||||
\n
|
||||
\nاین <a href="https://github.com/mastodon/mastodon/issues/25398">نکتهٔ ماستودون</a> را ببینید.</string>
|
||||
</resources>
|
|
@ -681,4 +681,9 @@
|
|||
<string name="help_empty_home">Seo <b>loidhne-ama do dhachaigh</b>. Seallaidh i na postaichean o chionn goirid aig na cunntasan a leanas tu.
|
||||
\n
|
||||
\nAirson cunntasan a rùrachadh, lorg iad air tè dhe na loidhnichean-ama eile; mar eisimpleir, loidhne-ama ionadail an ionstans agad [iconics gmd_group]. Air neo lorg cunntasan a-rèir ainm [iconics gmd_search]; mar eisimpleir, lorg “Tusky” ach am faigh thu grèim air a’ chunntas againne air Mastodon.</string>
|
||||
</resources>
|
||||
<string name="compose_delete_draft">A bheil thu airson an dreachd a sguabadh às\?</string>
|
||||
<string name="load_newest_notifications">Luchdaich na brathan as ùire</string>
|
||||
<string name="error_missing_edits">Tha fios aig an fhrithealaiche gun deach am post seo a dheasachadh ach chan eil lethbhreac dhen deasachadh aige-san is chan urrainn dhuinn a shealltainn dhut.
|
||||
\n
|
||||
\nSeo <a href="https://github.com/mastodon/mastodon/issues/25398">duilgheadas Mastodon #25398</a>.</string>
|
||||
</resources>
|
|
@ -584,7 +584,7 @@
|
|||
<string name="a11y_label_loading_thread">Cargando fío</string>
|
||||
<string name="mute_notifications_switch">Acalar notificacións</string>
|
||||
<string name="title_edits">Edicións</string>
|
||||
<string name="status_edit_info">Editado por %1$s</string>
|
||||
<string name="status_edit_info">Editada: %1$s</string>
|
||||
<string name="status_created_info">Creado por %1$s</string>
|
||||
<string name="action_discard">Desbotar cambios</string>
|
||||
<string name="action_continue_edit">Continuar a edición</string>
|
||||
|
@ -657,4 +657,9 @@
|
|||
<string name="select_list_empty">Aínda non tes listas</string>
|
||||
<string name="select_list_manage">Xestionar listas</string>
|
||||
<string name="error_list_load">Erro ao cargar as listas</string>
|
||||
</resources>
|
||||
<string name="error_missing_edits">O teu servidor sabe que a publicación foi editada, pero non ten unha copia das edición, polo que non pode mostrarchas.
|
||||
\n
|
||||
\nÉ un <a href="https://github.com/mastodon/mastodon/issues/25398">problema coñecido</a> en Mastodon.</string>
|
||||
<string name="load_newest_notifications">Cargar as notificacións máis recentes</string>
|
||||
<string name="compose_delete_draft">Eliminar borrador\?</string>
|
||||
</resources>
|
|
@ -401,4 +401,9 @@
|
|||
</plurals>
|
||||
<string name="error_compose_character_limit">पोस्ट बहुत लंबा है!</string>
|
||||
<string name="error_failed_app_registration">उस सर्वर से प्रमाणित करने में विफल।</string>
|
||||
</resources>
|
||||
<string name="error_multimedia_size_limit">वीडियो और ऑडियो फ़ाइलों का आकार %s एमबी से अधिक नहीं हो सकता है।</string>
|
||||
<string name="error_image_edit_failed">फोटो संपादित नहीं किया जा सका।</string>
|
||||
<string name="error_media_upload_image_or_video">फोटो और वीडियो दोनों को एक ही पोस्ट से अटैच नहीं किया जा सकता है।</string>
|
||||
<string name="error_loading_account_details">खाता विवरण लोड करने में विफल रहा</string>
|
||||
<string name="error_could_not_load_login_page">लॉगिन पेज लोड नहीं किया जा सका।</string>
|
||||
</resources>
|
|
@ -621,6 +621,6 @@
|
|||
<string name="select_list_empty">リストはまだありません</string>
|
||||
<string name="status_filtered_show_anyway">とにかく表示する</string>
|
||||
<string name="pref_title_account_filter_keywords">プロフィール</string>
|
||||
<string name="title_public_trending_hashtags">トレンドノハッシュタグ</string>
|
||||
<string name="title_public_trending_hashtags">トレンドのハッシュタグ</string>
|
||||
<string name="pref_title_show_stat_inline">タイムラインに投稿の統計情報を表示する</string>
|
||||
</resources>
|
||||
</resources>
|
|
@ -4,21 +4,21 @@
|
|||
<string name="error_network">Er deed zich een netwerkfout voor! Controleer je verbinding en probeer opnieuw!</string>
|
||||
<string name="error_empty">Dit mag niet leeg zijn.</string>
|
||||
<string name="error_invalid_domain">Ongeldige domeinnaam ingevoerd</string>
|
||||
<string name="error_failed_app_registration">Authenticatie met die server is mislukt.</string>
|
||||
<string name="error_failed_app_registration">Authenticatie met die server is mislukt. Als het probleem blijft, probeer dan de browser login via het menu.</string>
|
||||
<string name="error_no_web_browser_found">Kon geen bruikbare webbrowser vinden.</string>
|
||||
<string name="error_authorization_unknown">Er deed zich een onbekende autorisatiefout voor.</string>
|
||||
<string name="error_authorization_denied">Autorisatie werd geweigerd.</string>
|
||||
<string name="error_retrieving_oauth_token">Kon geen inlogsleutel verkrijgen.</string>
|
||||
<string name="error_authorization_unknown">Er deed zich een onbekende autorisatiefout voor. Als dit blijft, probeer dan “ Via de browser inloggen” in het menu.</string>
|
||||
<string name="error_authorization_denied">Autorisatie werd geweigerd. Als u zeker weet dat u de correcte gegevens heeft ingevoerd, probeer dan in te loggen in de browser via het menu.</string>
|
||||
<string name="error_retrieving_oauth_token">Kon geen inlogsleutel verkrijgen. Als het probleem zich blijft herhalen; probeer dan de browser login via menu.</string>
|
||||
<string name="error_compose_character_limit">Tekst van dit bericht is te lang!</string>
|
||||
<string name="error_media_upload_type">Bestandstype kan niet worden geüpload.</string>
|
||||
<string name="error_media_upload_type">Bestandstype wordt niet ondersteund.</string>
|
||||
<string name="error_media_upload_opening">Bestand kon niet worden geopend.</string>
|
||||
<string name="error_media_upload_permission">Er is toestemming nodig om deze media te lezen.</string>
|
||||
<string name="error_media_download_permission">Er is toestemming nodig om media op te slaan.</string>
|
||||
<string name="error_media_upload_image_or_video">Afbeeldingen en video\'s kunnen niet allebei aan hetzelfde bericht worden toegevoegd.</string>
|
||||
<string name="error_media_upload_image_or_video">Afbeeldingen en video\'s kunnen niet samen aan hetzelfde bericht worden toegevoegd.</string>
|
||||
<string name="error_media_upload_sending">Uploaden mislukt.</string>
|
||||
<string name="error_sender_account_gone">Fout tijdens verzenden bericht.</string>
|
||||
<string name="title_home">Start</string>
|
||||
<string name="title_notifications">Meldingen</string>
|
||||
<string name="title_notifications">Notificaties</string>
|
||||
<string name="title_public_local">Lokaal</string>
|
||||
<string name="title_public_federated">Globaal</string>
|
||||
<string name="title_direct_messages">Directe berichten</string>
|
||||
|
@ -47,7 +47,7 @@
|
|||
<string name="post_content_show_less">Inklappen</string>
|
||||
<string name="message_empty">Hier is niets.</string>
|
||||
<string name="footer_empty">Niets te zien. Swipe naar beneden om te verversen!</string>
|
||||
<string name="notification_reblog_format">%s boostte jouw bericht</string>
|
||||
<string name="notification_reblog_format">%s boostte jou bericht</string>
|
||||
<string name="notification_favourite_format">%s markeerde jouw bericht als favoriet</string>
|
||||
<string name="notification_follow_format">%s volgt jou</string>
|
||||
<string name="report_username_format">Rapporteer @%s</string>
|
||||
|
@ -60,8 +60,8 @@
|
|||
<string name="action_unfavourite">Favoriet verwijderen</string>
|
||||
<string name="action_more">Meer</string>
|
||||
<string name="action_compose">Bericht schrijven</string>
|
||||
<string name="action_login">Aanmelden met Mastodon</string>
|
||||
<string name="action_logout">Afmelden</string>
|
||||
<string name="action_login">Aanmelden met Tusky</string>
|
||||
<string name="action_logout">Uitloggen</string>
|
||||
<string name="action_logout_confirm">Ben je er zeker van dat je het account %1$s wil afmelden?</string>
|
||||
<string name="action_follow">Volgen</string>
|
||||
<string name="action_unfollow">Ontvolgen</string>
|
||||
|
@ -464,7 +464,7 @@
|
|||
<string name="account_note_hint">Jouw eigen opmerking over dit account</string>
|
||||
<string name="pref_title_wellbeing_mode">Welzijn</string>
|
||||
<string name="pref_title_hide_top_toolbar">De bovenste werkbalk verbergen</string>
|
||||
<string name="pref_title_confirm_reblogs">Vraag voor het boosten van een bericht een bevestiging</string>
|
||||
<string name="pref_title_confirm_reblogs">Vraag bevestiging voor het boosten</string>
|
||||
<string name="pref_title_show_cards_in_timelines">Linkpreviews in tijdlijnen weergeven</string>
|
||||
<string name="no_announcements">Er zijn geen aankondigingen.</string>
|
||||
<string name="duration_indefinite">Oneindig</string>
|
||||
|
@ -534,7 +534,7 @@
|
|||
<string name="duration_90_days">90 dagen</string>
|
||||
<string name="duration_180_days">180 dagen</string>
|
||||
<string name="duration_365_days">365 dagen</string>
|
||||
<string name="pref_title_confirm_favourites">Vraag voor het markeren als favoriet een bevestiging</string>
|
||||
<string name="pref_title_confirm_favourites">Vraag bevestiging voor het markeren als favoriet</string>
|
||||
<string name="tusky_compose_post_quicksetting_label">Bericht schrijven</string>
|
||||
<string name="account_date_joined">Geregistreerd in %1$s</string>
|
||||
<string name="saving_draft">Concept wordt opgeslagen…</string>
|
||||
|
@ -590,4 +590,65 @@
|
|||
<string name="account_username_copied">Gebruikersnaam gekopieerd</string>
|
||||
<string name="confirmation_hashtag_unfollowed">#%s ontvolgd</string>
|
||||
<string name="title_followed_hashtags">Gevolgde hashtags</string>
|
||||
</resources>
|
||||
<string name="dialog_follow_hashtag_title">Volg hashtag</string>
|
||||
<string name="dialog_follow_hashtag_hint">#hashtag</string>
|
||||
<string name="hint_description">Beschrijving</string>
|
||||
<string name="action_post_failed">Upload mislukt</string>
|
||||
<string name="action_post_failed_detail">Je bericht kan niet worden geüpload en is opgeslagen in concepten.
|
||||
\n
|
||||
\nEr kon geen contact worden opgenomen met de server of de post werd geweigerd.</string>
|
||||
<string name="action_post_failed_detail_plural">Je berichten kunnen niet worden geüpload en zijn opgeslagen in concepten.
|
||||
\n
|
||||
\nEr kon geen contact worden opgenomen met de server of de berichten werden geweigerd.</string>
|
||||
<string name="action_post_failed_do_nothing">Afwijzen</string>
|
||||
<string name="action_post_failed_show_drafts">Concepten tonen</string>
|
||||
<string name="error_unmuting_hashtag_format">Fout bij unmuting #%s</string>
|
||||
<string name="action_browser_login">Inloggen met een Browser</string>
|
||||
<string name="action_add_reaction">reactie toevoegen</string>
|
||||
<string name="action_discard">Veranderingen ongedaan maken</string>
|
||||
<string name="post_edited">Bewerkt %s</string>
|
||||
<string name="notification_header_report_format">%s gerapporteerd %s</string>
|
||||
<string name="notification_summary_report_format">%s · %d berichten bijgevoegd</string>
|
||||
<string name="action_share_account_link">Link naar account delen</string>
|
||||
<string name="action_share_account_username">Deel de gebruikersnaam van het account</string>
|
||||
<string name="send_account_username_to">Accountgebruikersnaam delen om…</string>
|
||||
<string name="send_account_link_to">Account-URL delen met…</string>
|
||||
<string name="error_following_hashtags_unsupported">Deze instance ondersteunt niet het volgen van hashtags.</string>
|
||||
<string name="error_status_source_load">Fout bij het laden van de statusbron van server.</string>
|
||||
<string name="title_public_trending_hashtags">Trending hashtags</string>
|
||||
<string name="pref_summary_http_proxy_missing"><niet ingesteld></string>
|
||||
<string name="pref_summary_http_proxy_invalid"><ongeldig></string>
|
||||
<string name="action_refresh">Ververs</string>
|
||||
<string name="post_media_image">Afbeelding</string>
|
||||
<string name="ui_error_reblog">Boosten bericht mislukt: %s</string>
|
||||
<string name="ui_error_vote">Stemmen in peiling mislukt: %s</string>
|
||||
<string name="pref_title_http_proxy_port_message">Poort moet liggen tussen %d en %d</string>
|
||||
<string name="notification_unknown_name">Onbekend</string>
|
||||
<string name="ui_error_clear_notifications">Wissen meldingen mislukt: %s</string>
|
||||
<string name="ui_success_accepted_follow_request">Volgverzoek geaccepteerd</string>
|
||||
<string name="error_list_load">Fout bij laden lijsten</string>
|
||||
<string name="select_list_empty">Je hebt nog geen lijsten</string>
|
||||
<string name="select_list_manage">Lijsten beheren</string>
|
||||
<string name="pref_title_account_filter_keywords">Profielen</string>
|
||||
<string name="status_filtered_show_anyway">Toch tonen</string>
|
||||
<string name="status_filter_placeholder_label_format">Gefilterd: %s</string>
|
||||
<string name="hint_filter_title">Mijn filter</string>
|
||||
<string name="label_filter_action">Filteractie</string>
|
||||
<string name="filter_action_warn">Waarschuwen</string>
|
||||
<string name="filter_action_hide">Verbergen</string>
|
||||
<string name="filter_description_warn">Verberg met een waarschuwing</string>
|
||||
<string name="filter_description_hide">Verberg helemaal</string>
|
||||
<string name="action_add">Toevoegen</string>
|
||||
<string name="filter_keyword_display_format">%s (heel woord)</string>
|
||||
<string name="filter_description_format">%s: %s</string>
|
||||
<string name="accessibility_talking_about_tag">%1$d mensen bespreken hashtag %2$s</string>
|
||||
<string name="total_usage">Totaal gebruik</string>
|
||||
<string name="total_accounts">Totaal accounts</string>
|
||||
<string name="ui_error_reject_follow_request">Afwijzen volgverzoek mislukt: %s</string>
|
||||
<string name="pref_title_show_stat_inline">Toon bericht statistieken in tijdlijn</string>
|
||||
<string name="ui_error_unknown">onbekende reden</string>
|
||||
<string name="ui_error_accept_follow_request">Accepteren volgverzoek mislukt: %s</string>
|
||||
<string name="label_filter_title">Titel</string>
|
||||
<string name="load_newest_notifications">Laad nieuwste meldingen</string>
|
||||
<string name="compose_delete_draft">Verwijder concept\?</string>
|
||||
</resources>
|
|
@ -666,4 +666,9 @@
|
|||
<string name="help_empty_home">Aquò es vòstra <b>cronologia</b>. Mòstra las publicacions recentas dels comptes que seguissètz.
|
||||
\n
|
||||
\nPer explorar mai de compte podètz siá los descobrir dins d’autres fils, per exemple lo fil local de vòstra instància [iconics gmd_group], siá los trapar per lor nom [iconics gmd_search], per exemple « Tusky » per trobar nòstre compte Mastodon.</string>
|
||||
</resources>
|
||||
<string name="error_missing_edits">Vòstre servidor sap qu’aquesta publicacion foguèt modificada mas ten pas cap de còpia de las modificacions doncas vos las pòt afichar.
|
||||
\n
|
||||
\nAquò es un problèma de <a href="https://github.com/mastodon/mastodon/issues/25398">Mastodon #25398</a>.</string>
|
||||
<string name="load_newest_notifications">Cargar las notificacions mai recentas</string>
|
||||
<string name="compose_delete_draft">Suprimir lo borrolhon \?</string>
|
||||
</resources>
|
|
@ -646,4 +646,6 @@
|
|||
<string name="select_list_manage">Quản lý danh sách</string>
|
||||
<string name="error_list_load">Xảy ra lỗi khi tải danh sách</string>
|
||||
<string name="select_list_empty">Bạn chưa có danh sách</string>
|
||||
</resources>
|
||||
<string name="load_newest_notifications">Tải những thông báo mới nhất</string>
|
||||
<string name="compose_delete_draft">Xóa bản nháp\?</string>
|
||||
</resources>
|
|
@ -423,7 +423,7 @@
|
|||
<string name="report_remote_instance">转发到 %s</string>
|
||||
<string name="failed_report">举报失败</string>
|
||||
<string name="failed_fetch_posts">无法获取嘟文</string>
|
||||
<string name="report_description_1">该报告将发送给给您的服务器管理员。您可以在下面提供有关回报此账户的原因的说明:</string>
|
||||
<string name="report_description_1">举报将发送给你所在服务器的管理员。你可以在下面提供举报此账户的相关说明:</string>
|
||||
<string name="report_description_remote_instance">该账户来自其他服务器。向那里发送一份匿名的报告副本?</string>
|
||||
<string name="title_accounts">账户</string>
|
||||
<string name="failed_search">搜索失败</string>
|
||||
|
@ -441,7 +441,7 @@
|
|||
<string name="poll_new_choice_hint">选择 %d</string>
|
||||
<string name="edit_poll">编辑</string>
|
||||
<string name="post_lookup_error_format">查找嘟文时出错 %s</string>
|
||||
<string name="no_drafts">您没有草稿。</string>
|
||||
<string name="no_drafts">你没有草稿</string>
|
||||
<string name="no_scheduled_posts">您没有任何定时嘟文。</string>
|
||||
<string name="warning_scheduling_interval">Mastodon的最小预订时间为5分钟。</string>
|
||||
<string name="notification_follow_request_name">关注请求</string>
|
||||
|
@ -486,10 +486,10 @@
|
|||
<string name="review_notifications">反馈通知</string>
|
||||
<string name="wellbeing_hide_stats_posts">隐藏嘟文的统计信息</string>
|
||||
<string name="limit_notifications">限制时间线通知</string>
|
||||
<string name="wellbeing_mode_notice">一些可能影响您精神状态的信息将被隐藏,这些信息包括:
|
||||
<string name="wellbeing_mode_notice">一些可能影响你精神状态的信息将被隐藏,包括:
|
||||
\n
|
||||
\n - 喜欢、转发、关注通知
|
||||
\n - 喜欢、转发数
|
||||
\n - 嘟文的喜欢、转发数
|
||||
\n - 账号的已关注数量、嘟文数量
|
||||
\n
|
||||
\n 推送通知不会被影响,但可以在通知设置中手动禁用。</string>
|
||||
|
@ -506,7 +506,7 @@
|
|||
<string name="pref_title_animate_custom_emojis">显示动态自定义Emoji</string>
|
||||
<string name="pref_title_notification_filter_subscriptions">关注的人发布了新嘟文</string>
|
||||
<string name="notification_subscription_format">%s 刚刚发送了新嘟文</string>
|
||||
<string name="follow_requests_info">即使您的账号未上锁,管理员 %1$s 认为您可能需要手动处理来自这些账号的关注请求。</string>
|
||||
<string name="follow_requests_info">即使你的账号未上锁,但 %1$s 的管理员认为你可能需要手动处理这些账号的关注请求。</string>
|
||||
<string name="dialog_delete_conversation_warning">删除此对话吗?</string>
|
||||
<string name="action_delete_conversation">删除对话</string>
|
||||
<string name="pref_title_confirm_favourites">收藏前提示确认</string>
|
||||
|
@ -556,7 +556,7 @@
|
|||
<string name="delete_scheduled_post_warning">删除这条定时嘟文吗?</string>
|
||||
<string name="instance_rule_info">登录即表示您同意 %s 的规定。</string>
|
||||
<string name="instance_rule_title">%s 的规定</string>
|
||||
<string name="compose_save_draft_loses_media">保存草稿?(当您恢复草稿时附件将被再次上传。)</string>
|
||||
<string name="compose_save_draft_loses_media">保存草稿?(恢复草稿时附件将被再次上传)</string>
|
||||
<string name="failed_to_pin">固定失败</string>
|
||||
<string name="failed_to_unpin">取消固定失败</string>
|
||||
<string name="action_add_reaction">添加回应</string>
|
||||
|
@ -665,4 +665,8 @@
|
|||
<string name="error_list_load">加载列表出错</string>
|
||||
<string name="select_list_empty">你还没有列表</string>
|
||||
<string name="load_newest_notifications">加载最新通知</string>
|
||||
<string name="compose_delete_draft">删除草稿?</string>
|
||||
<string name="error_missing_edits">你的服务器知晓这篇帖子被编辑,但没有编辑的副本,所以无法呈现给你。
|
||||
\n
|
||||
\n这是一个 <a href="https://github.com/mastodon/mastodon/issues/25398">Mastodon issue #25398</a>。</string>
|
||||
</resources>
|
|
@ -22,6 +22,16 @@
|
|||
<attr name="proportionalTrending" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="SliderPreference">
|
||||
<attr name="android:value" format="string|reference" />
|
||||
<attr name="android:valueFrom" format="string|reference" />
|
||||
<attr name="android:valueTo" format="string|reference" />
|
||||
<attr name="android:stepSize" format="string|reference" />
|
||||
<attr name="format" format="string|reference" />
|
||||
<attr name="iconStart" format="reference" />
|
||||
<attr name="iconEnd" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
<!--Themed Attributes-->
|
||||
<attr name="colorBackgroundAccent" format="reference|color" />
|
||||
<attr name="colorBackgroundHighlight" format="reference|color" />
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<resources>
|
||||
|
||||
<string name="error_generic">An error occurred.</string>
|
||||
<string name="error_network">A network error occurred! Please check your connection and try again!</string>
|
||||
<string name="error_network">A network error occurred. Please check your connection and try again.</string>
|
||||
<string name="error_empty">This cannot be empty.</string>
|
||||
<string name="error_invalid_domain">Invalid domain entered</string>
|
||||
<string name="error_failed_app_registration">Failed authenticating with that instance. If this persists, try "Login in Browser" from the menu.</string>
|
||||
|
@ -338,6 +338,7 @@
|
|||
<string name="post_privacy_unlisted">Unlisted</string>
|
||||
<string name="post_privacy_followers_only">Followers-only</string>
|
||||
|
||||
<string name="pref_ui_text_size">UI text size</string>
|
||||
<string name="pref_post_text_size">Post text size</string>
|
||||
|
||||
<string name="post_text_size_smallest">Smallest</string>
|
||||
|
@ -370,6 +371,8 @@
|
|||
<string name="notification_update_description">Notifications when posts you\'ve interacted with are edited</string>
|
||||
<string name="notification_report_name">Reports</string>
|
||||
<string name="notification_report_description">Notifications about moderation reports</string>
|
||||
<string name="notification_listenable_worker_name">Background activity</string>
|
||||
<string name="notification_listenable_worker_description">Notifications when Tusky is working in the background</string>
|
||||
<string name="notification_unknown_name">Unknown</string>
|
||||
|
||||
<string name="notification_mention_format">%s mentioned you</string>
|
||||
|
@ -380,6 +383,8 @@
|
|||
<item quantity="one">%d new interaction</item>
|
||||
<item quantity="other">%d new interactions</item>
|
||||
</plurals>
|
||||
<string name="notification_notification_worker">Fetching notifications…</string>
|
||||
<string name="notification_prune_cache">Cache maintenance…</string>
|
||||
|
||||
<string name="description_account_locked">Locked Account</string>
|
||||
|
||||
|
@ -764,10 +769,9 @@
|
|||
<string name="pref_reading_order_oldest_first">Oldest first</string>
|
||||
<string name="pref_reading_order_newest_first">Newest first</string>
|
||||
|
||||
<!--@Tusky edited 19th December 2022 13:37 -->
|
||||
<string name="status_edit_info">Edited: %1$s</string>
|
||||
<!--@Tusky created 19th December 2022 13:12 -->
|
||||
<string name="status_created_info">Created: %1$s</string>
|
||||
<string name="error_missing_edits">Your server knows that this post was edited, but does not have a copy of the edits, so they can\'t be shown to you.\n\nThis is <a href="https://github.com/mastodon/mastodon/issues/25398">Mastodon issue #25398</a>.</string>
|
||||
<string name="a11y_label_loading_thread">Loading thread</string>
|
||||
|
||||
<!--@knossos@fosstodon.org created 2023-01-07 -->
|
||||
|
|
|
@ -106,7 +106,7 @@
|
|||
</style>
|
||||
|
||||
<style name="TuskyTabAppearance" parent="Widget.MaterialComponents.TabLayout">
|
||||
<item name="android:textSize">?attr/status_text_medium</item>
|
||||
<item name="tabTextAppearance">?android:attr/textAppearanceButton</item>
|
||||
<item name="android:textAllCaps">true</item>
|
||||
<item name="tabIndicatorHeight">3dp</item>
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.google.ksp) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
alias(libs.plugins.kotlin.kapt) apply false
|
||||
alias(libs.plugins.kotlin.parcelize) apply false
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
Tusky 23.0 beta 1
|
||||
|
||||
New features:
|
||||
|
||||
- New preference to scale UI text
|
||||
|
||||
Fixes:
|
||||
|
||||
- Save account information correctly
|
||||
- "pull" notifications on devices running Android versions <= 11
|
||||
- Work around Android bug where text fields could "forget" they can copy/paste
|
||||
- Viewing "diffs" in edit history will not extend off screen edge
|
||||
- Don't crash if your server has no post edit history
|
||||
- Add a "Delete" button when editing a filter
|
||||
- Show non-square emoji correctly
|
|
@ -0,0 +1,18 @@
|
|||
Tusky 22.0 beta 1
|
||||
|
||||
Entre sus características se incluyen:
|
||||
|
||||
- Visualización de etiquetas que son tendencia
|
||||
- Editar descripciones de imágenes y puntos de enfoque
|
||||
- Menú "Refrescar" Para fines de accesibilidad
|
||||
- Soporte para filtros de Mastodon v4
|
||||
- Mostrar información detallada cuando se edita una publicación
|
||||
- Opción para mostrar estadísticas de publicaciones en la cronología
|
||||
|
||||
Entre las correcciones se incluye:
|
||||
|
||||
- Mostrar controles del reproductor durante la reproducción de audio
|
||||
- Calculación correcta de la longitud de una publicación
|
||||
- Siempre publicar descripciones de imágenes
|
||||
|
||||
Entre otras
|
|
@ -0,0 +1,15 @@
|
|||
تاسکی ۲۳٫۰ بتا
|
||||
|
||||
ویژگیهای جدید:
|
||||
|
||||
- ترجیح جدید برای مقیاس متن میانای کاربری
|
||||
|
||||
رفع اشکالها:
|
||||
|
||||
- ذخیرهٔ درست اطّلاعات حساب
|
||||
- «گرفتن» آگاهیها روی افزارههای با نگارش اندروید کمتر از ۱۱
|
||||
- دور زدن مشکل امکان فراموشی توانایی رونوشت و جایگذاری در زمینههای متنی اندروید
|
||||
- تجاوز نکردن از لیهٔ صفحه هنگام دیدن «تفاوتها» در تاریخچهٔ ویرایش
|
||||
- فرونپاشیدن در صورت نبودن تاریخچهٔ ویرایش فرسته روی کارساز
|
||||
- افزودن دکمهٔ «حذف» هنگام ویرایش یک پالایه
|
||||
- نمایش درست اموجیهای نامربّعی
|
|
@ -1,9 +1,9 @@
|
|||
تاسکی ۱۹٫۰
|
||||
|
||||
- Support for Unified Push. To activate the support you will have to relogin into your accounts.
|
||||
- The number of responses to a post is now indicated in timelines.
|
||||
- Images can now by cropped while composing a post.
|
||||
- Profiles now show the date when they were created.
|
||||
- When viewing a list the title is now displayed in the toolbar.
|
||||
- A lot of bugfixes
|
||||
- Translation improvements
|
||||
- پشتیبانی از Unified Push. برای فعّال کردن این پشتیبانی باید دوباره به حسابهایتان وارد شوید.
|
||||
- اکنون تعداد پاسخها به فرستهها در خطهای زمانی نشان داده میشود.
|
||||
- اکنون تصویرها میتوانند هنگام ایجاد فرسته بریده شوند.
|
||||
- اکنون نمایهها تاریخ ایجادشان را نشان میدهند.
|
||||
- اکنون عنوان سیاهه هنگام دیدنش در نوار ابزار نمایش داده میشود.
|
||||
- یک عالمه رفع اشکال
|
||||
- بهبودهای ترجمه
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
Tusky 22.0 beta 1
|
||||
|
||||
Új funkciók:
|
||||
|
||||
- Trendi hashtag-ek megtekintése
|
||||
- Képleírás és fókuszpont szerkesztése
|
||||
- "Frissítés" menü az elérhetőségért
|
||||
- Mastodon v4 szűrők támogatása
|
||||
- Részletes különbségek mutatása, amikor egy bejegyzést szerkesztettek
|
||||
- Opció bejegyzés-statisztikák idővonalon való megjelenítésére
|
||||
|
||||
Javítások:
|
||||
|
||||
- Lejátszó vezérlőinek mutatása hangvisszajátszás közben
|
||||
- Bejegyzés hosszkalkuláció javítása
|
||||
- Mindig közzétesszük a képfeliratokat
|
||||
|
||||
és még sok más
|
|
@ -0,0 +1,10 @@
|
|||
Tusky 22.0 beta 2
|
||||
|
||||
Javítások:
|
||||
|
||||
- Javított értesítés-betöltési sebesség
|
||||
- Újra mutatjuk a 0/1/1+ a válaszoknál
|
||||
- Szűrőcímek mutatása, nem a kulcsszavaké a szűrt bejegyzéseken
|
||||
- Hibajavítás: egy bejegyzés megnyitása megnyithatott egy nem kapcsolódó hivatkozást
|
||||
- Mutassuk a "Hozzáadás" a megfelelő helyen, ha nincsenek szűrők
|
||||
- Különböző programleállások javítása
|
|
@ -0,0 +1,11 @@
|
|||
Tusky 22.0 beta 3
|
||||
|
||||
Javítások:
|
||||
|
||||
- Szálak nézegetése közbeni programleállás javítása
|
||||
- Mastodon szűrők feldolgozása közbeni programleállás javítása
|
||||
- Profilokon a követési hivatkozások kattinthatóak
|
||||
- Androidos értesítés-kezelési frissítések
|
||||
- Android értesítés a Mastodonról csak egyszer mutatandó
|
||||
- Android értesítések Mastodon értesítési típus (követés, említés, megtolás, stb) szerint vannak csoportosítva
|
||||
- Lehetséges értesítés-elhagyás megoldva
|
|
@ -0,0 +1,5 @@
|
|||
Tusky 22.0 beta 4
|
||||
|
||||
Javítások:
|
||||
|
||||
- Több fiók használata esetén az értesítések újra történő lekérésének megoldása
|
|
@ -0,0 +1,6 @@
|
|||
Tusky 22.0 beta 5
|
||||
|
||||
Javítások:
|
||||
|
||||
- APNG könytár vissza a régire a törött animált emojik javításáért
|
||||
- Értesítésjelző helyi mentése arra az esetre, ha a kiszolgáló nem támogatja az API-t
|
|
@ -0,0 +1,5 @@
|
|||
Tusky 22.0 beta 6
|
||||
|
||||
Javítások:
|
||||
|
||||
- Értesítési fülön az olvasási pozíció gyakoribb mentése
|
|
@ -0,0 +1,10 @@
|
|||
Tusky 22.0 beta 7
|
||||
|
||||
Javítások:
|
||||
|
||||
|
||||
### Jelentős hibák
|
||||
|
||||
- Minden fontos Mastodon értesítés lekérése, amikor Android értesítéseket hozunk létre
|
||||
- A "Üzenetírás" kattintása rossz fiókra vitt, megoldva
|
||||
- Annak biztosítása, hogy az "utolsó olvasott értesítés azonosítója" a helyes fiókba mentődjön
|
|
@ -0,0 +1,20 @@
|
|||
Tusky 22.0
|
||||
|
||||
Új funkciók:
|
||||
|
||||
- Felkapott hashtag-ek mutatása
|
||||
- Új hashtag-ek bekövetése
|
||||
- Jobb sorrendezés nyelvek választásakor
|
||||
- Bejegyzésverziók közötti különbségek mutatása
|
||||
- Mastodon v4 szűrők támogatása
|
||||
- Lehetőség bejegyzés-statisztikák mutatására az idővonalon
|
||||
- És sok más...
|
||||
|
||||
Javítások:
|
||||
|
||||
- Kiválasztott fül és pozíció megjegyzése
|
||||
- Értesítések megtartása az elolvasásig
|
||||
- Kevert balról jobbra és jobbról balra szöveg helyes mutatása a profilon
|
||||
- Bejegyzéshossz kiszámításának javítása
|
||||
- Képfeliratok publikálása minden esetben
|
||||
- És sok más..
|
|
@ -0,0 +1,15 @@
|
|||
Tusky 23.0 beta 1
|
||||
|
||||
Új funkciók:
|
||||
|
||||
- Új beállítás UI-szöveg nagyítására
|
||||
|
||||
Javítások:
|
||||
|
||||
- Fiókinfók helyes mentése
|
||||
- "leküldési" értesítések Android 11-nél régebbi eszközön
|
||||
- Androidos hibajavítás, ahol a szövegmezők "elfelejtik", hogy tudnak szöveget másolni
|
||||
- A "különbségek" mutatása a szerkesztési történetben nem túl nagy
|
||||
- Összeomlás elkerülése, ha a kiszolgáló nem ismeri a bejegyzés történetét
|
||||
- "Törlés" gomb hozzáadása, amikor szűrőt szerkesztünk
|
||||
- Nem kocka emojik helyes megjelenítése
|
|
@ -0,0 +1,7 @@
|
|||
Tusky 21.0
|
||||
|
||||
- Stöd för inläggsredigering
|
||||
- Ny inställning för att styra önskad läsriktning
|
||||
- Större mediaförhandsvisningar och ett nytt överlägg för att indikera media med beskrivning
|
||||
– Det är nu möjligt att lägga till konton till listor från sin profil
|
||||
och mycket mer
|
|
@ -0,0 +1,18 @@
|
|||
Tusky 22.0 beta 1
|
||||
|
||||
Funktioner inklusive:
|
||||
|
||||
- Se trendiga hashtaggar
|
||||
- Redigera bildbeskrivningar och fokuspunkt
|
||||
- "Uppdatera"-menyn för tillgänglighet
|
||||
- Stöd Mastodon v4-filter
|
||||
- Visa detaljerade skillnader när ett inlägg redigeras
|
||||
- Möjlighet att visa inläggsstatistik i tidslinjen
|
||||
|
||||
Fixar inkluderar:
|
||||
|
||||
- Visa spelarkontroller under ljuduppspelning
|
||||
- Korrekt beräkning av stolplängd
|
||||
- Publicera alltid bildtexter
|
||||
|
||||
och mycket mer
|
|
@ -0,0 +1,10 @@
|
|||
Tusky 22.0 beta 2
|
||||
|
||||
Fixar inkluderar:
|
||||
|
||||
- Förbättrad aviseringshastighet
|
||||
- Återställ visar 0/1/1+ för svar
|
||||
- Visa filtertitlar, inte filtersökord, på filtrerade inlägg
|
||||
- Fixade en bugg där öppnande av en status kunde öppna en orelaterade länk
|
||||
- Visa "Lägg till"-knappen på rätt plats när det inte finns några filter
|
||||
- Fixade diverse krascher
|
|
@ -0,0 +1,11 @@
|
|||
Tusky 22.0 beta 3
|
||||
|
||||
Fixar inkluderar:
|
||||
|
||||
- Fixade en krasch vid visning av en tråd
|
||||
- Fixat kraschbehandling av Mastodon-filter
|
||||
- Länkar i bios för meddelanden om följ/följ-förfrågningar är klickbara
|
||||
- Uppdateringar av Android-aviseringar
|
||||
- Android-avisering för en Mastodon-avisering bör endast visas en gång
|
||||
- Android-aviseringar grupperas efter Mastodon-meddelandetyp (följ, nämn, boost, etc)
|
||||
- Potentialen för saknade aviseringar har tagits bort
|
|
@ -0,0 +1,5 @@
|
|||
Tusky 22.0 beta 4
|
||||
|
||||
Fixar:
|
||||
|
||||
- Fixade upprepad hämtning av meddelanden om konfigurerad med flera konton
|
|
@ -0,0 +1,6 @@
|
|||
Tusky 22.0 beta 5
|
||||
|
||||
Fixar:
|
||||
|
||||
- Återställt APNG-bibliotek för att fixa trasiga animerade emojis
|
||||
- Spara lokal kopia av meddelandemarkören om servern inte stöder API
|
|
@ -0,0 +1,5 @@
|
|||
Tusky 22.0 beta 6
|
||||
|
||||
Fixar:
|
||||
|
||||
- Spara läsposition på Aviseringar fliken oftare
|
|
@ -0,0 +1,10 @@
|
|||
Tusky 22.0 beta 7
|
||||
|
||||
Fixar:
|
||||
|
||||
|
||||
### Betydande buggfixar
|
||||
|
||||
- Hämta alla utestående Mastodon aviseringar när du skapar Android-aviseringar
|
||||
- Om du klickar på "Skriv" från ett meddelande ställs fel konto in
|
||||
- Se till att "senast lästa meddelande-ID" är sparat på rätt konto
|
|
@ -0,0 +1,20 @@
|
|||
Tusky 22.0
|
||||
|
||||
Nya egenskaper:
|
||||
|
||||
- Se trendiga hashtaggar
|
||||
- Följ nya hashtaggar
|
||||
- Bättre ordning vid val av språk
|
||||
- Visa skillnaden mellan versioner av ett inlägg
|
||||
- Stöd Mastodon v4-filter
|
||||
- Möjlighet att visa inläggsstatistik i tidslinjen
|
||||
- Och mer...
|
||||
|
||||
Fixar:
|
||||
|
||||
- Kom ihåg vald flik och position
|
||||
- Behåll aviseringar tills de läses
|
||||
- Visa blandad RTL- och LTR-text korrekt i profiler
|
||||
- Korrekt beräkning av stolplängd
|
||||
- Publicera alltid bildtexter
|
||||
- Och mer...
|
|
@ -0,0 +1,15 @@
|
|||
Tusky 23.0 beta 1
|
||||
|
||||
Nya funktioner:
|
||||
|
||||
- Ny inställning för att skala UI-text
|
||||
|
||||
Fixar:
|
||||
|
||||
- Sparar kontoinformation korrekt
|
||||
- "pull"-meddelanden på enheter som kör Android-versioner <= 11
|
||||
- Undvik Android-bugg där textfält kan "glömma" att de kan kopiera/klistra in
|
||||
- Att visa "diffs" i redigeringshistoriken kommer inte att sträcka sig utanför skärmkanten
|
||||
- Krascha inte om din server inte har någon inläggsredigeringshistorik
|
||||
- Lägg till en "Radera"-knapp när du redigerar ett filter
|
||||
- Visa icke-fyrkantiga emoji korrekt
|
|
@ -1 +1,13 @@
|
|||
https://github.com/tuskyapp/Tusky/releases
|
||||
Tusky v6.0
|
||||
|
||||
- Tidslinjefilter har flyttats till kontoinställningar och kommer att synkroniseras med servern
|
||||
- Du kan nu ha en anpassad hashtagg som flik i huvudgränssnittet
|
||||
- Listor kan nu redigeras
|
||||
- Säkerhet: tog bort stödet för TLS 1.0 och TLS 1.1 och lade till stöd för TLS 1.3 på Android 6+
|
||||
- Skrivvyn kommer nu att föreslå anpassade emojis när du börjar skriva
|
||||
- Ny temainställning "följ systemtema"
|
||||
- Förbättrad tillgänglighet till tidslinjen
|
||||
- Tusky kommer nu att ignorera okända meddelanden och inte längre krascha
|
||||
- Ny inställning: Du kan nu åsidosätta systemspråket och ställa in ett annat språk i Tusky
|
||||
- Nya översättningar: tjeckiska och esperanto
|
||||
– Många andra förbättringar och fixar
|
||||
|
|
|
@ -1 +1,9 @@
|
|||
https://github.com/tuskyapp/Tusky/releases
|
||||
Tusky v9.0
|
||||
|
||||
- Du kan nu skapa omröstningar från Tusky
|
||||
- Förbättrad sökning
|
||||
- Nytt alternativ i Kontoinställningar för att alltid utöka innehållsvarningar
|
||||
- Avatarer i navigeringslådan har nu en rundad fyrkantig form
|
||||
– Det är nu möjligt att rapportera användare även när de aldrig lagt upp en status
|
||||
- Tusky kommer nu att vägra ansluta över klartextanslutningar på Android 6+
|
||||
– Många andra små förbättringar och buggfixar
|
||||
|
|
|
@ -1,2 +1,11 @@
|
|||
Tusky v11.0
|
||||
https://github.com/tuskyapp/Tusky/releases
|
||||
|
||||
- Aviseringar om nya följningsförfrågningar när ditt konto är låst
|
||||
- Nya funktioner som kan växlas på skärmen Inställningar:
|
||||
- inaktivera svepning mellan flikarna
|
||||
- visa en bekräftelsedialog innan du förstärker en tut
|
||||
- visa länkförhandsvisningar i tidslinjer
|
||||
– Konversationer kan nu stängas av
|
||||
- Omröstningsresultat kommer nu att beräknas baserat på antalet väljare och inte på antalet totala röster, vilket gör flervalsundersökningar lättare att förstå
|
||||
– Många buggfixar, de flesta relaterade till att komponera tutter
|
||||
- Förbättrade översättningar
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
Tusky v13.0
|
||||
|
||||
- support for profile notes (Mastodon 3.2.0 feature)
|
||||
- support for admin announcements (Mastodon 3.1.0 feature)
|
||||
- stöd för profilanteckningar (Mastodon 3.2.0-funktion)
|
||||
- stöd för adminmeddelanden (Mastodon 3.1.0-funktion)
|
||||
|
||||
- the avatar of your selected account will now be shown in the main toolbar
|
||||
- clicking the display name in a timeline will now open the profile page of that user
|
||||
- avataren för ditt valda konto kommer nu att visas i huvudverktygsfältet
|
||||
- genom att klicka på visningsnamnet i en tidslinje öppnas nu användarens profilsida
|
||||
|
||||
- a lot of bug fixes and small improvements
|
||||
- improved translations
|
||||
- många buggfixar och små förbättringar
|
||||
- förbättrade översättningar
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
Tusky v14.0
|
||||
|
||||
- Få ett meddelande när en användare gör inlägg - klicka på klockikonen på sin profil! (Mastodon 3.3.0-funktion)
|
||||
- Draft-funktionen i Tusky har gjorts om helt för att vara snabbare, mer användarvänlig och mindre buggig.
|
||||
- Ett nytt välmåendeläge som låter dig begränsa vissa Tusky-funktioner har lagts till.
|
||||
- Tusky kan nu animera anpassade emojis.
|
||||
Fullständig ändringslogg: https://github.com/tuskyapp/Tusky/releases
|
|
@ -0,0 +1,5 @@
|
|||
Tusky v15.0
|
||||
|
||||
- Följ förfrågningar visas nu alltid i huvudmenyn.
|
||||
– Tidsväljaren för att schemalägga ett inlägg har en design som överensstämmer med resten av appen nu
|
||||
Fullständig ändringslogg: https://github.com/tuskyapp/Tusky/releases
|
|
@ -0,0 +1,3 @@
|
|||
Tusky v15.1
|
||||
|
||||
Den här versionen fixar en krasch vid bildtextning
|
|
@ -0,0 +1,8 @@
|
|||
Tusky v16.0
|
||||
|
||||
– Tidslinjens laddningslogik har skrivits om helt för att vara snabbare, mindre buggig och lättare att underhålla.
|
||||
- Tusky kan nu animera anpassade emojis i APNG & Animated WebP-format.
|
||||
- Många buggfixar
|
||||
- Stöd för Android 11
|
||||
- Nya översättningar: skotsk gaeliska, galiciska, ukrainska
|
||||
- Förbättrade översättningar
|
|
@ -0,0 +1,7 @@
|
|||
Tusky v17.0
|
||||
|
||||
- "Öppna som..." finns nu även tillgängligt i menyn på kontoprofiler vid användning av flera konton
|
||||
- Inloggning hanteras nu i en WebView i appen
|
||||
- Stöd för Android 12
|
||||
- stöd för det nya Mastodon-instanskonfigurations-API:et
|
||||
- och många andra småfixar och förbättringar
|
|
@ -0,0 +1,6 @@
|
|||
Tusky v18.0
|
||||
|
||||
- Stöd för nya Mastodon 3.5-meddelandetyper
|
||||
- Bot-märket ser nu bättre ut och anpassar sig till det valda temat
|
||||
- Text kan nu väljas i inläggets detaljvy
|
||||
- Fixade många buggar, inklusive en som förhindrade inloggningar på Android 6 och lägre
|
|
@ -23,7 +23,7 @@ androidx-room = "2.5.1"
|
|||
autodispose = "2.1.1"
|
||||
bouncycastle = "1.70"
|
||||
conscrypt = "2.5.2"
|
||||
coroutines = "1.7.1"
|
||||
coroutines = "1.7.2"
|
||||
dagger = "2.46.1"
|
||||
diffx = "1.1.1"
|
||||
emoji2 = "1.3.0"
|
||||
|
@ -49,18 +49,18 @@ rxjava3 = "3.1.6"
|
|||
rxkotlin3 = "3.0.1"
|
||||
photoview = "2.3.0"
|
||||
sparkbutton = "4.1.0"
|
||||
# Deliberate downgrade from 1.1.4, see https://github.com/google/truth/issues/1137
|
||||
truth = "1.1.3"
|
||||
turbine = "0.13.0"
|
||||
truth = "1.1.5"
|
||||
turbine = "1.0.0"
|
||||
unified-push = "2.1.1"
|
||||
xmlwriter = "1.0.4"
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
google-ksp = "com.google.devtools.ksp:1.8.22-1.0.11"
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
|
||||
kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }
|
||||
ktlint = "org.jlleitschuh.gradle.ktlint:11.4.0"
|
||||
ktlint = "org.jlleitschuh.gradle.ktlint:11.5.0"
|
||||
|
||||
[libraries]
|
||||
android-material = { module = "com.google.android.material:material", version.ref = "material" }
|
||||
|
|
Loading…
Reference in New Issue