Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit 5be9a90

Browse files
committed
Merge remote-tracking branch 'tuskyapp/develop'
2 parents eb622de + 965d511 commit 5be9a90

File tree

163 files changed

+6926
-1236
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

163 files changed

+6926
-1236
lines changed

app/schemas/com.keylesspalace.tusky.db.AppDatabase/43.json

Lines changed: 959 additions & 0 deletions
Large diffs are not rendered by default.

app/schemas/com.keylesspalace.tusky.db.AppDatabase/44.json

Lines changed: 965 additions & 0 deletions
Large diffs are not rendered by default.

app/schemas/com.keylesspalace.tusky.db.AppDatabase/45.json

Lines changed: 983 additions & 0 deletions
Large diffs are not rendered by default.

app/src/main/AndroidManifest.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<uses-permission android:name="android.permission.INTERNET" />
77
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
88
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
9-
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
10-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
9+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
10+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
1111
<uses-permission android:name="android.permission.VIBRATE" /> <!-- For notifications -->
1212
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
1313

@@ -19,7 +19,8 @@
1919
android:label="@string/app_name"
2020
android:supportsRtl="true"
2121
android:theme="@style/TuskyTheme"
22-
android:usesCleartextTraffic="false">
22+
android:usesCleartextTraffic="false"
23+
android:localeConfig="@xml/locales_config">
2324

2425
<activity
2526
android:name=".SplashActivity"
@@ -133,6 +134,7 @@
133134
<activity android:name=".ListsActivity" />
134135
<activity android:name=".LicenseActivity" />
135136
<activity android:name=".FiltersActivity" />
137+
<activity android:name=".components.followedtags.FollowedTagsActivity" />
136138
<activity
137139
android:name=".components.report.ReportActivity"
138140
android:windowSoftInputMode="stateAlwaysHidden|adjustResize" />

app/src/main/java/com/keylesspalace/tusky/BaseActivity.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package com.keylesspalace.tusky;
1717

1818
import android.app.ActivityManager;
19-
import android.content.Context;
2019
import android.content.Intent;
2120
import android.content.SharedPreferences;
2221
import android.content.pm.PackageManager;
@@ -92,11 +91,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
9291
requesters = new HashMap<>();
9392
}
9493

95-
@Override
96-
protected void attachBaseContext(Context base) {
97-
super.attachBaseContext(TuskyApplication.getLocaleManager().setLocale(base));
98-
}
99-
10094
protected boolean requiresLogin() {
10195
return true;
10296
}

app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,9 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
2929
import com.keylesspalace.tusky.components.account.AccountActivity
3030
import com.keylesspalace.tusky.components.viewthread.ViewThreadActivity
3131
import com.keylesspalace.tusky.network.MastodonApi
32+
import com.keylesspalace.tusky.util.looksLikeMastodonUrl
3233
import com.keylesspalace.tusky.util.openLink
3334
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
34-
import java.net.URI
35-
import java.net.URISyntaxException
3635
import javax.inject.Inject
3736

3837
/** this is the base class for all activities that open links
@@ -180,47 +179,6 @@ abstract class BottomSheetActivity : BaseActivity() {
180179
}
181180
}
182181

183-
// https://mastodon.foo.bar/@User
184-
// https://mastodon.foo.bar/@User/43456787654678
185-
// https://pleroma.foo.bar/users/User
186-
// https://pleroma.foo.bar/users/9qTHT2ANWUdXzENqC0
187-
// https://pleroma.foo.bar/notice/9sBHWIlwwGZi5QGlHc
188-
// https://pleroma.foo.bar/objects/d4643c42-3ae0-4b73-b8b0-c725f5819207
189-
// https://friendica.foo.bar/profile/user
190-
// https://friendica.foo.bar/display/d4643c42-3ae0-4b73-b8b0-c725f5819207
191-
// https://misskey.foo.bar/notes/83w6r388br (always lowercase)
192-
// https://pixelfed.social/p/connyduck/391263492998670833
193-
// https://pixelfed.social/connyduck
194-
// https://mastodon.foo.bar/users/User/statuses/000000000000000000
195-
fun looksLikeMastodonUrl(urlString: String): Boolean {
196-
val uri: URI
197-
try {
198-
uri = URI(urlString)
199-
} catch (e: URISyntaxException) {
200-
return false
201-
}
202-
203-
if (uri.query != null ||
204-
uri.fragment != null ||
205-
uri.path == null
206-
) {
207-
return false
208-
}
209-
210-
val path = uri.path
211-
return path.matches("^/@[^/]+$".toRegex()) ||
212-
path.matches("^/@[^/]+/\\d+$".toRegex()) ||
213-
path.matches("^/users/\\w+$".toRegex()) ||
214-
path.matches("^/notice/[a-zA-Z0-9]+$".toRegex()) ||
215-
path.matches("^/objects/[-a-f0-9]+$".toRegex()) ||
216-
path.matches("^/notes/[a-z0-9]+$".toRegex()) ||
217-
path.matches("^/display/[-a-f0-9]+$".toRegex()) ||
218-
path.matches("^/profile/\\w+$".toRegex()) ||
219-
path.matches("^/p/\\w+/\\d+$".toRegex()) ||
220-
path.matches("^/\\w+$".toRegex()) ||
221-
path.matches("^/users/[^/]+/statuses/\\d+$".toRegex())
222-
}
223-
224182
enum class PostLookupFallbackBehavior {
225183
OPEN_IN_BROWSER,
226184
DISPLAY_ERROR,

app/src/main/java/com/keylesspalace/tusky/MainActivity.kt

Lines changed: 102 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -434,9 +434,11 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
434434

435435
private fun setupDrawer(savedInstanceState: Bundle?, addSearchButton: Boolean) {
436436

437-
binding.mainToolbar.setNavigationOnClickListener {
438-
binding.mainDrawerLayout.open()
439-
}
437+
val drawerOpenClickListener = View.OnClickListener { binding.mainDrawerLayout.open() }
438+
439+
binding.mainToolbar.setNavigationOnClickListener(drawerOpenClickListener)
440+
binding.topNavAvatar.setOnClickListener(drawerOpenClickListener)
441+
binding.bottomNavAvatar.setOnClickListener(drawerOpenClickListener)
440442

441443
header = AccountHeaderView(this).apply {
442444
headerBackgroundScaleType = ImageView.ScaleType.CENTER_CROP
@@ -648,7 +650,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
648650
val actionBarSize = ThemeUtils.getDimension(this, R.attr.actionBarSize)
649651
val fabMargin = resources.getDimensionPixelSize(R.dimen.fabMargin)
650652
(binding.composeButton.layoutParams as CoordinatorLayout.LayoutParams).bottomMargin = actionBarSize + fabMargin
651-
binding.tabLayout.hide()
653+
binding.topNav.hide()
652654
binding.bottomTabLayout
653655
} else {
654656
binding.bottomNav.hide()
@@ -784,7 +786,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
784786
val pageMargin = resources.getDimensionPixelSize(R.dimen.tab_page_margin)
785787
binding.viewPager.setPageTransformer(MarginPageTransformer(pageMargin))
786788

787-
val enableSwipeForTabs = preferences.getBoolean("enableSwipeForTabs", true)
789+
val enableSwipeForTabs = preferences.getBoolean(PrefKeys.ENABLE_SWIPE_FOR_TABS, true)
788790
binding.viewPager.isUserInputEnabled = enableSwipeForTabs
789791

790792
onTabSelectedListener?.let {
@@ -922,71 +924,117 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
922924
}
923925

924926
private fun loadDrawerAvatar(avatarUrl: String, showPlaceholder: Boolean) {
925-
val navIconSize = resources.getDimensionPixelSize(R.dimen.avatar_toolbar_nav_icon_size)
926927

928+
val hideTopToolbar = preferences.getBoolean(PrefKeys.HIDE_TOP_TOOLBAR, false)
927929
val animateAvatars = preferences.getBoolean("animateGifAvatars", false)
928930

929-
if (animateAvatars) {
930-
glide.asDrawable()
931-
.load(avatarUrl)
932-
.transform(
933-
RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp))
934-
)
935-
.apply {
936-
if (showPlaceholder) {
937-
placeholder(R.drawable.avatar_default)
938-
}
939-
}
940-
.into(object : CustomTarget<Drawable>(navIconSize, navIconSize) {
931+
if (hideTopToolbar) {
932+
val navOnBottom = preferences.getString("mainNavPosition", "top") == "bottom"
941933

942-
override fun onLoadStarted(placeholder: Drawable?) {
943-
if (placeholder != null) {
944-
binding.mainToolbar.navigationIcon = FixedSizeDrawable(placeholder, navIconSize, navIconSize)
934+
val avatarView = if (navOnBottom) {
935+
binding.bottomNavAvatar.show()
936+
binding.bottomNavAvatar
937+
} else {
938+
binding.topNavAvatar.show()
939+
binding.topNavAvatar
940+
}
941+
942+
if (animateAvatars) {
943+
Glide.with(this)
944+
.load(avatarUrl)
945+
.placeholder(R.drawable.avatar_default)
946+
.into(avatarView)
947+
} else {
948+
Glide.with(this)
949+
.asBitmap()
950+
.load(avatarUrl)
951+
.placeholder(R.drawable.avatar_default)
952+
.into(avatarView)
953+
}
954+
} else {
955+
956+
binding.bottomNavAvatar.hide()
957+
binding.topNavAvatar.hide()
958+
959+
val navIconSize = resources.getDimensionPixelSize(R.dimen.avatar_toolbar_nav_icon_size)
960+
961+
if (animateAvatars) {
962+
glide.asDrawable()
963+
.load(avatarUrl)
964+
.transform(
965+
RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp))
966+
)
967+
.apply {
968+
if (showPlaceholder) {
969+
placeholder(R.drawable.avatar_default)
945970
}
946971
}
972+
.into(object : CustomTarget<Drawable>(navIconSize, navIconSize) {
947973

948-
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
949-
if (resource is Animatable) {
950-
resource.start()
974+
override fun onLoadStarted(placeholder: Drawable?) {
975+
if (placeholder != null) {
976+
binding.mainToolbar.navigationIcon =
977+
FixedSizeDrawable(placeholder, navIconSize, navIconSize)
978+
}
951979
}
952-
binding.mainToolbar.navigationIcon = FixedSizeDrawable(resource, navIconSize, navIconSize)
953-
}
954980

955-
override fun onLoadCleared(placeholder: Drawable?) {
956-
if (placeholder != null) {
957-
binding.mainToolbar.navigationIcon = FixedSizeDrawable(placeholder, navIconSize, navIconSize)
981+
override fun onResourceReady(
982+
resource: Drawable,
983+
transition: Transition<in Drawable>?
984+
) {
985+
if (resource is Animatable) {
986+
resource.start()
987+
}
988+
binding.mainToolbar.navigationIcon =
989+
FixedSizeDrawable(resource, navIconSize, navIconSize)
958990
}
959-
}
960-
})
961-
} else {
962-
glide.asBitmap()
963-
.load(avatarUrl)
964-
.transform(
965-
RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp))
966-
)
967-
.apply {
968-
if (showPlaceholder) {
969-
placeholder(R.drawable.avatar_default)
970-
}
971-
}
972-
.into(object : CustomTarget<Bitmap>(navIconSize, navIconSize) {
973991

974-
override fun onLoadStarted(placeholder: Drawable?) {
975-
if (placeholder != null) {
976-
binding.mainToolbar.navigationIcon = FixedSizeDrawable(placeholder, navIconSize, navIconSize)
992+
override fun onLoadCleared(placeholder: Drawable?) {
993+
if (placeholder != null) {
994+
binding.mainToolbar.navigationIcon =
995+
FixedSizeDrawable(placeholder, navIconSize, navIconSize)
996+
}
997+
}
998+
})
999+
} else {
1000+
glide.asBitmap()
1001+
.load(avatarUrl)
1002+
.transform(
1003+
RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp))
1004+
)
1005+
.apply {
1006+
if (showPlaceholder) {
1007+
placeholder(R.drawable.avatar_default)
9771008
}
9781009
}
1010+
.into(object : CustomTarget<Bitmap>(navIconSize, navIconSize) {
9791011

980-
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
981-
binding.mainToolbar.navigationIcon = FixedSizeDrawable(BitmapDrawable(resources, resource), navIconSize, navIconSize)
982-
}
1012+
override fun onLoadStarted(placeholder: Drawable?) {
1013+
if (placeholder != null) {
1014+
binding.mainToolbar.navigationIcon =
1015+
FixedSizeDrawable(placeholder, navIconSize, navIconSize)
1016+
}
1017+
}
9831018

984-
override fun onLoadCleared(placeholder: Drawable?) {
985-
if (placeholder != null) {
986-
binding.mainToolbar.navigationIcon = FixedSizeDrawable(placeholder, navIconSize, navIconSize)
1019+
override fun onResourceReady(
1020+
resource: Bitmap,
1021+
transition: Transition<in Bitmap>?
1022+
) {
1023+
binding.mainToolbar.navigationIcon = FixedSizeDrawable(
1024+
BitmapDrawable(resources, resource),
1025+
navIconSize,
1026+
navIconSize
1027+
)
9871028
}
988-
}
989-
})
1029+
1030+
override fun onLoadCleared(placeholder: Drawable?) {
1031+
if (placeholder != null) {
1032+
binding.mainToolbar.navigationIcon =
1033+
FixedSizeDrawable(placeholder, navIconSize, navIconSize)
1034+
}
1035+
}
1036+
})
1037+
}
9901038
}
9911039
}
9921040

0 commit comments

Comments
 (0)