diff --git a/app/build.gradle b/app/build.gradle
index b970cc7e1..192eff688 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -22,13 +22,13 @@ final def CUSTOM_INSTANCE = ""
final def SUPPORT_ACCOUNT_URL = "https://mastodon.social/@Tusky"
android {
- compileSdk 34
+ compileSdk 35
namespace "com.keylesspalace.tusky"
defaultConfig {
applicationId APP_ID
namespace "com.keylesspalace.tusky"
minSdk 24
- targetSdk 34
+ targetSdk 35
versionCode 129
versionName "27.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index eee4b80d0..e6a7e3864 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -107,8 +107,7 @@
+ android:alwaysRetainTaskState="true" />
@@ -117,7 +116,7 @@
android:theme="@style/TuskyBaseTheme"
android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize" />
-
+
diff --git a/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt b/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt
index 93cb08478..73180ac93 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt
@@ -10,6 +10,9 @@ import android.text.style.URLSpan
import android.text.util.Linkify
import android.widget.TextView
import androidx.annotation.StringRes
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.keylesspalace.tusky.components.instanceinfo.InstanceInfoRepository
import com.keylesspalace.tusky.databinding.ActivityAboutBinding
@@ -41,6 +44,13 @@ class AboutActivity : BottomSheetActivity() {
setTitle(R.string.about_title_activity)
+ ViewCompat.setOnApplyWindowInsetsListener(binding.scrollView) { scrollView, insets ->
+ val systemBarInsets = insets.getInsets(systemBars())
+ scrollView.updatePadding(bottom = systemBarInsets.bottom)
+
+ insets.inset(0, 0, 0, systemBarInsets.bottom)
+ }
+
binding.versionTextView.text = getString(R.string.about_app_version, getString(R.string.app_name), BuildConfig.VERSION_NAME)
binding.deviceInfo.text = getString(
diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.kt b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.kt
index 70b158e0a..d8d02f457 100644
--- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.kt
@@ -21,12 +21,23 @@ import android.content.Intent
import android.content.SharedPreferences
import android.graphics.BitmapFactory
import android.graphics.Color
+import android.os.Build
import android.os.Bundle
import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
import androidx.annotation.StyleRes
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.graphics.Insets
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsCompat.Type.displayCutout
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updateLayoutParams
+import androidx.core.view.updatePadding
import androidx.lifecycle.ViewModelProvider.Factory
import androidx.lifecycle.lifecycleScope
+import com.google.android.material.R as materialR
import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.keylesspalace.tusky.MainActivity.Companion.redirectIntent
@@ -88,16 +99,28 @@ abstract class BaseActivity : AppCompatActivity() {
setTheme(R.style.TuskyTheme)
}
- /* set the taskdescription programmatically, the theme would turn it blue */
+ /* Set the taskdescription programmatically - by default the primary color is used.
+ * On newer Android versions (or launchers?) this doesn't seem to have an effect. */
val appName = getString(R.string.app_name)
- val appIcon = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
val recentsBackgroundColor = MaterialColors.getColor(
this,
- com.google.android.material.R.attr.colorSurface,
+ materialR.attr.colorSurface,
Color.BLACK
)
- setTaskDescription(TaskDescription(appName, appIcon, recentsBackgroundColor))
+ val taskDescription = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ TaskDescription.Builder()
+ .setLabel(appName)
+ .setIcon(R.mipmap.ic_launcher)
+ .setPrimaryColor(recentsBackgroundColor)
+ .build()
+ } else {
+ val appIcon = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
+ @Suppress("DEPRECATION")
+ TaskDescription(appName, appIcon, recentsBackgroundColor)
+ }
+
+ setTaskDescription(taskDescription)
val style = textStyle(preferences.getString(PrefKeys.STATUS_TEXT_SIZE, "medium"))
getTheme().applyStyle(style, true)
@@ -107,6 +130,31 @@ abstract class BaseActivity : AppCompatActivity() {
}
}
+ override fun onPostCreate(savedInstanceState: Bundle?) {
+ super.onPostCreate(savedInstanceState)
+ window.decorView.setBackgroundColor(Color.BLACK)
+
+ val contentView: View = findViewById(android.R.id.content)
+ contentView.setBackgroundColor(MaterialColors.getColor(contentView, android.R.attr.colorBackground))
+
+ // handle left/right insets. This is relevant for edge-to-edge mode in landscape orientation
+ ViewCompat.setOnApplyWindowInsetsListener(contentView) { _, insets ->
+ val systemBarInsets = insets.getInsets(systemBars())
+ val displayCutoutInsets = insets.getInsets(displayCutout())
+ // use padding for system bar insets so they get our background color and margin for cutout insets to turn them black
+ contentView.updatePadding(left = systemBarInsets.left, right = systemBarInsets.right)
+ contentView.updateLayoutParams {
+ leftMargin = displayCutoutInsets.left
+ rightMargin = displayCutoutInsets.right
+ }
+
+ WindowInsetsCompat.Builder(insets)
+ .setInsets(systemBars(), Insets.of(0, systemBarInsets.top, 0, systemBarInsets.bottom))
+ .setInsets(displayCutout(), Insets.of(0, displayCutoutInsets.top, 0, displayCutoutInsets.bottom))
+ .build()
+ }
+ }
+
private fun activityTransitionWasRequested(): Boolean {
return intent.getBooleanExtra(OPEN_WITH_SLIDE_IN, false)
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt b/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt
index d0a342622..87eea1340 100644
--- a/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt
@@ -27,7 +27,13 @@ import android.widget.ImageView
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
+import androidx.core.graphics.Insets
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsCompat.Type.ime
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
import androidx.core.view.isVisible
+import androidx.core.view.updatePadding
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
@@ -119,6 +125,25 @@ class EditProfileActivity : BaseActivity() {
setDisplayShowHomeEnabled(true)
}
+ ViewCompat.setOnApplyWindowInsetsListener(binding.root) { scrollView, insets ->
+ // if keyboard visible -> set inset on the root to push the scrollview up
+ // if keyboard hidden -> set inset on the scrollview so last element does not get obscured by navigation bar
+ // scrollview has clipToPadding set to false so it draws behind the navigation bar in edge-to-edge mode
+ val imeInsets = insets.getInsets(ime())
+ val systemBarsInsets = insets.getInsets(systemBars())
+ binding.root.updatePadding(bottom = imeInsets.bottom)
+ val scrollViewPadding = if (imeInsets.bottom == 0) {
+ systemBarsInsets.bottom
+ } else {
+ 0
+ }
+ binding.scrollView.updatePadding(bottom = scrollViewPadding)
+ WindowInsetsCompat.Builder(insets)
+ .setInsets(ime(), Insets.of(imeInsets.left, imeInsets.top, imeInsets.right, 0))
+ .setInsets(systemBars(), Insets.of(systemBarsInsets.left, systemBarsInsets.top, imeInsets.right, 0))
+ .build()
+ }
+
binding.avatarButton.setOnClickListener { pickMedia(PickType.AVATAR) }
binding.headerButton.setOnClickListener { pickMedia(PickType.HEADER) }
diff --git a/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt b/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt
index 426fa1c88..e4cd82b3b 100644
--- a/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt
@@ -19,6 +19,9 @@ import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.annotation.RawRes
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.keylesspalace.tusky.databinding.ActivityLicenseBinding
import dagger.hilt.android.AndroidEntryPoint
@@ -45,6 +48,13 @@ class LicenseActivity : BaseActivity() {
setTitle(R.string.title_licenses)
+ ViewCompat.setOnApplyWindowInsetsListener(binding.scrollView) { scrollView, insets ->
+ val systemBarInsets = insets.getInsets(systemBars())
+ scrollView.updatePadding(bottom = systemBarInsets.bottom)
+
+ insets.inset(0, 0, 0, systemBarInsets.bottom)
+ }
+
loadFileIntoTextView(R.raw.apache, binding.licenseApacheTextView)
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt
index da4af6f43..804ac5a30 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt
@@ -40,6 +40,8 @@ import com.keylesspalace.tusky.databinding.DialogListBinding
import com.keylesspalace.tusky.databinding.ItemListBinding
import com.keylesspalace.tusky.entity.MastoList
import com.keylesspalace.tusky.util.BindingHolder
+import com.keylesspalace.tusky.util.ensureBottomMargin
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation
@@ -78,6 +80,9 @@ class ListsActivity : BaseActivity() {
setDisplayShowHomeEnabled(true)
}
+ binding.addListButton.ensureBottomMargin()
+ binding.listsRecycler.ensureBottomPadding(fab = true)
+
binding.listsRecycler.adapter = adapter
binding.listsRecycler.layoutManager = LinearLayoutManager(this)
binding.listsRecycler.addItemDecoration(
diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
index b88125b5c..445bb3dd2 100644
--- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
@@ -38,6 +38,7 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.MenuItem.SHOW_AS_ACTION_NEVER
import android.view.View
+import android.view.ViewGroup.LayoutParams
import android.widget.ImageView
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
@@ -49,8 +50,12 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.MenuProvider
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
import androidx.core.view.forEach
import androidx.core.view.isVisible
+import androidx.core.view.updateLayoutParams
+import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.widget.MarginPageTransformer
import com.bumptech.glide.Glide
@@ -91,7 +96,6 @@ import com.keylesspalace.tusky.usecase.DeveloperToolsUseCase
import com.keylesspalace.tusky.usecase.LogoutUsecase
import com.keylesspalace.tusky.util.ActivityConstants
import com.keylesspalace.tusky.util.emojify
-import com.keylesspalace.tusky.util.getDimension
import com.keylesspalace.tusky.util.getParcelableExtraCompat
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.overrideActivityTransitionCompat
@@ -236,9 +240,45 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
}
}
- window.statusBarColor = Color.TRANSPARENT // don't draw a status bar, the DrawerLayout and the MaterialDrawerLayout have their own
setContentView(binding.root)
+ val bottomBarHeight = if (preferences.getString(PrefKeys.MAIN_NAV_POSITION, "top") == "bottom") {
+ resources.getDimensionPixelSize(R.dimen.bottomAppBarHeight)
+ } else {
+ 0
+ }
+
+ val fabMargin = resources.getDimensionPixelSize(R.dimen.fabMargin)
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ ViewCompat.setOnApplyWindowInsetsListener(binding.viewPager) { _, insets ->
+ val systemBarsInsets = insets.getInsets(systemBars())
+ val bottomInsets = systemBarsInsets.bottom
+
+ binding.composeButton.updateLayoutParams {
+ bottomMargin = bottomBarHeight + fabMargin + bottomInsets
+ }
+ binding.mainDrawer.recyclerView.updatePadding(bottom = bottomInsets)
+
+ if (preferences.getString(PrefKeys.MAIN_NAV_POSITION, "top") == "top") {
+ insets
+ } else {
+ binding.viewPager.updatePadding(bottom = bottomBarHeight + bottomInsets)
+ insets.inset(0, 0, 0, bottomInsets)
+ }
+ }
+ } else {
+ // don't draw a status bar, the DrawerLayout and the MaterialDrawerLayout have their own
+ // on Vanilla Ice Cream (API 35) and up there is no status bar color because of edge-to-edge mode
+ @Suppress("DEPRECATION")
+ window.statusBarColor = Color.TRANSPARENT
+
+ binding.composeButton.updateLayoutParams {
+ bottomMargin = bottomBarHeight + fabMargin
+ }
+ binding.viewPager.updatePadding(bottom = bottomBarHeight)
+ }
+
binding.composeButton.setOnClickListener {
val composeIntent = Intent(applicationContext, ComposeActivity::class.java)
startActivity(composeIntent)
@@ -252,11 +292,14 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
"top" -> setSupportActionBar(binding.topNav)
"bottom" -> setSupportActionBar(binding.bottomNav)
}
- binding.mainToolbar.hide()
+ // this is a bit hacky, but when the mainToolbar is GONE, the toolbar size gets messed up for some reason
+ binding.mainToolbar.layoutParams.height = 0
+ binding.mainToolbar.visibility = View.INVISIBLE
// There's not enough space in the top/bottom bars to show the title as well.
supportActionBar?.setDisplayShowTitleEnabled(false)
} else {
setSupportActionBar(binding.mainToolbar)
+ binding.mainToolbar.layoutParams.height = LayoutParams.WRAP_CONTENT
binding.mainToolbar.show()
}
@@ -793,15 +836,10 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
private fun setupTabs(tabs: List) {
val activeTabLayout = if (preferences.getString(PrefKeys.MAIN_NAV_POSITION, "top") == "bottom") {
- val actionBarSize = getDimension(this, androidx.appcompat.R.attr.actionBarSize)
- val fabMargin = resources.getDimensionPixelSize(R.dimen.fabMargin)
- (binding.composeButton.layoutParams as CoordinatorLayout.LayoutParams).bottomMargin = actionBarSize + fabMargin
binding.topNav.hide()
binding.bottomTabLayout
} else {
binding.bottomNav.hide()
- (binding.viewPager.layoutParams as CoordinatorLayout.LayoutParams).bottomMargin = 0
- (binding.composeButton.layoutParams as CoordinatorLayout.LayoutParams).anchorId = R.id.viewPager
binding.tabLayout
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt b/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt
index bede65b4c..90c2e1df9 100644
--- a/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt
@@ -18,7 +18,11 @@ package com.keylesspalace.tusky
import android.graphics.Color
import android.os.Bundle
import android.view.View
+import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.ItemTouchHelper
@@ -34,7 +38,7 @@ import com.keylesspalace.tusky.components.account.list.ListSelectionFragment
import com.keylesspalace.tusky.databinding.ActivityTabPreferenceBinding
import com.keylesspalace.tusky.entity.MastoList
import com.keylesspalace.tusky.network.MastodonApi
-import com.keylesspalace.tusky.util.hashtagPattern
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.unsafeLazy
import com.keylesspalace.tusky.util.viewBinding
import com.keylesspalace.tusky.util.visible
@@ -82,6 +86,19 @@ class TabPreferenceActivity : BaseActivity(), ItemInteractionListener, ListSelec
setDisplayShowHomeEnabled(true)
}
+ binding.currentTabsRecyclerView.ensureBottomPadding(fab = true)
+ ViewCompat.setOnApplyWindowInsetsListener(binding.actionButton) { _, insets ->
+ val bottomInset = insets.getInsets(systemBars()).bottom
+ val actionButtonMargin = resources.getDimensionPixelSize(R.dimen.fabMargin)
+ binding.actionButton.updateLayoutParams {
+ bottomMargin = bottomInset + actionButtonMargin
+ }
+ binding.sheet.updateLayoutParams {
+ bottomMargin = bottomInset + actionButtonMargin
+ }
+ insets.inset(0, 0, 0, bottomInset)
+ }
+
currentTabs = accountManager.activeAccount?.tabPreferences.orEmpty().toMutableList()
currentTabsAdapter = TabAdapter(currentTabs, false, this, currentTabs.size <= MIN_TAB_COUNT)
binding.currentTabsRecyclerView.adapter = currentTabsAdapter
@@ -253,11 +270,6 @@ class TabPreferenceActivity : BaseActivity(), ItemInteractionListener, ListSelec
saveTabs()
}
- private fun validateHashtag(input: CharSequence?): Boolean {
- val trimmedInput = input?.trim() ?: ""
- return trimmedInput.isNotEmpty() && hashtagPattern.matcher(trimmedInput).matches()
- }
-
private fun updateAvailableTabs() {
val addableTabs: MutableList = mutableListOf()
diff --git a/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt b/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt
index 596689b07..1430327ab 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt
@@ -156,9 +156,13 @@ class ViewMediaActivity :
true
}
+ // yes it is deprecated, but it looks cool so it stays for now
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE
- window.statusBarColor = Color.BLACK
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ @Suppress("DEPRECATION")
+ window.statusBarColor = Color.BLACK
+ }
window.sharedElementEnterTransition.addListener(object : NoopTransitionListener {
override fun onTransitionEnd(transition: Transition) {
adapter.onTransitionEnd(binding.viewPager.currentItem)
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/PreviewPollOptionsAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/PreviewPollOptionsAdapter.kt
index 10c2f14f7..d24cba8cd 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/PreviewPollOptionsAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/PreviewPollOptionsAdapter.kt
@@ -19,7 +19,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
-import androidx.core.widget.TextViewCompat
import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.R
@@ -58,7 +57,7 @@ class PreviewPollOptionsAdapter : RecyclerView.Adapter() {
R.drawable.ic_radio_button_unchecked_18dp
}
- TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, iconId, 0, 0, 0)
+ textView.setCompoundDrawablesRelativeWithIntrinsicBounds(iconId, 0, 0, 0)
textView.text = options[position]
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt
index 0acfceff1..98602b2a0 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt
@@ -21,6 +21,7 @@ import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.Typeface
+import android.os.Build
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.text.TextWatcher
@@ -40,8 +41,8 @@ import androidx.core.graphics.ColorUtils
import androidx.core.view.MenuProvider
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
-import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.lifecycleScope
@@ -83,6 +84,7 @@ import com.keylesspalace.tusky.util.Loading
import com.keylesspalace.tusky.util.Success
import com.keylesspalace.tusky.util.copyToClipboard
import com.keylesspalace.tusky.util.emojify
+import com.keylesspalace.tusky.util.ensureBottomMargin
import com.keylesspalace.tusky.util.getDomain
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.loadAvatar
@@ -285,25 +287,21 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide
}
private fun handleWindowInsets() {
+ binding.accountFloatingActionButton.ensureBottomMargin()
ViewCompat.setOnApplyWindowInsetsListener(binding.accountCoordinatorLayout) { _, insets ->
- val top = insets.getInsets(systemBars()).top
- val toolbarParams = binding.accountToolbar.layoutParams as ViewGroup.MarginLayoutParams
- toolbarParams.topMargin = top
+ val systemBarInsets = insets.getInsets(systemBars())
+ val top = systemBarInsets.top
+
+ binding.accountToolbar.updateLayoutParams {
+ topMargin = top
+ }
- val right = insets.getInsets(systemBars()).right
- val bottom = insets.getInsets(systemBars()).bottom
- val left = insets.getInsets(systemBars()).left
- binding.accountCoordinatorLayout.updatePadding(
- right = right,
- bottom = bottom,
- left = left
- )
binding.swipeToRefreshLayout.setProgressViewEndTarget(
false,
top + resources.getDimensionPixelSize(R.dimen.account_swiperefresh_distance)
)
- WindowInsetsCompat.CONSUMED
+ insets.inset(0, top, 0, 0)
}
}
@@ -355,7 +353,10 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide
1f
)
- window.statusBarColor = argbEvaluator.evaluate(transparencyPercent, statusBarColorTransparent, statusBarColorOpaque) as Int
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ @Suppress("DEPRECATION")
+ window.statusBarColor = argbEvaluator.evaluate(transparencyPercent, statusBarColorTransparent, statusBarColorOpaque) as Int
+ }
val evaluatedToolbarColor = argbEvaluator.evaluate(
transparencyPercent,
@@ -364,6 +365,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide
) as Int
binding.accountToolbar.setBackgroundColor(evaluatedToolbarColor)
+ binding.accountStatusBarScrim.setBackgroundColor(evaluatedToolbarColor)
binding.swipeToRefreshLayout.isEnabled = verticalOffset == 0
}
@@ -372,7 +374,10 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide
private fun makeNotificationBarTransparent() {
WindowCompat.setDecorFitsSystemWindows(window, false)
- window.statusBarColor = statusBarColorTransparent
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ @Suppress("DEPRECATION")
+ window.statusBarColor = statusBarColorTransparent
+ }
}
/**
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListFragment.kt
index a463ef76d..e43b87d45 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListFragment.kt
@@ -49,6 +49,7 @@ import com.keylesspalace.tusky.interfaces.LinkListener
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.HttpHeaderLink
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.getSerializableCompat
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.show
@@ -92,6 +93,7 @@ class AccountListFragment :
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ binding.recyclerView.ensureBottomPadding()
binding.recyclerView.setHasFixedSize(true)
val layoutManager = LinearLayoutManager(view.context)
binding.recyclerView.layoutManager = layoutManager
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt
index fdab56ee3..eafbdb5fa 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt
@@ -38,6 +38,7 @@ import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.Error
import com.keylesspalace.tusky.util.Loading
import com.keylesspalace.tusky.util.Success
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation
@@ -87,6 +88,7 @@ class AnnouncementsActivity :
binding.swipeRefreshLayout.setOnRefreshListener(this::refreshAnnouncements)
+ binding.announcementsList.ensureBottomPadding()
binding.announcementsList.setHasFixedSize(true)
binding.announcementsList.layoutManager = LinearLayoutManager(this)
val divider = DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt
index 2b288aeb4..5a3baada5 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt
@@ -50,8 +50,11 @@ import androidx.core.content.FileProvider
import androidx.core.content.res.use
import androidx.core.view.ContentInfoCompat
import androidx.core.view.OnReceiveContentListener
+import androidx.core.view.WindowInsetsCompat.Type.ime
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
import androidx.core.view.isGone
import androidx.core.view.isVisible
+import androidx.core.view.updatePadding
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.lifecycleScope
@@ -106,6 +109,7 @@ import com.keylesspalace.tusky.util.loadAvatar
import com.keylesspalace.tusky.util.map
import com.keylesspalace.tusky.util.modernLanguageCode
import com.keylesspalace.tusky.util.setDrawableTint
+import com.keylesspalace.tusky.util.setOnWindowInsetsChangeListener
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.viewBinding
import com.keylesspalace.tusky.util.visible
@@ -259,6 +263,16 @@ class ComposeActivity :
}
setContentView(binding.root)
+ binding.composeBottomBar.setOnWindowInsetsChangeListener { windowInsets ->
+ val insets = windowInsets.getInsets(systemBars() or ime())
+ binding.composeBottomBar.updatePadding(bottom = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 4))
+ binding.addMediaBottomSheet.updatePadding(bottom = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 50))
+ binding.emojiView.updatePadding(bottom = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 50))
+ binding.composeOptionsBottomSheet.updatePadding(bottom = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 50))
+ binding.composeScheduleView.updatePadding(bottom = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 50))
+ (binding.composeMainScrollView.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 58)
+ }
+
setupActionBar()
setupAvatar(activeAccount)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt
index 08f912b2c..1bab75ebd 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt
@@ -49,6 +49,7 @@ import com.keylesspalace.tusky.interfaces.StatusActionListener
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.CardViewMode
import com.keylesspalace.tusky.util.StatusDisplayOptions
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.isAnyLoading
import com.keylesspalace.tusky.util.show
@@ -228,6 +229,7 @@ class ConversationsFragment :
}
private fun setupRecyclerView(adapter: ConversationAdapter) {
+ binding.recyclerView.ensureBottomPadding(fab = true)
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.layoutManager = LinearLayoutManager(context)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksFragment.kt
index 10438087e..0978e06a4 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksFragment.kt
@@ -12,6 +12,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.databinding.FragmentDomainBlocksBinding
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.viewBinding
@@ -30,6 +31,8 @@ class DomainBlocksFragment : Fragment(R.layout.fragment_domain_blocks) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val adapter = DomainBlocksAdapter(viewModel::unblock)
+ binding.recyclerView.ensureBottomPadding()
+
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.addItemDecoration(
DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsActivity.kt
index d6668c189..095bd9469 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsActivity.kt
@@ -34,6 +34,7 @@ import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.databinding.ActivityDraftsBinding
import com.keylesspalace.tusky.db.DraftsAlert
import com.keylesspalace.tusky.db.entity.DraftEntity
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.isHttpNotFound
import com.keylesspalace.tusky.util.parseAsMastodonHtml
import com.keylesspalace.tusky.util.visible
@@ -66,6 +67,8 @@ class DraftsActivity : BaseActivity(), DraftActionListener {
setDisplayShowHomeEnabled(true)
}
+ binding.draftsRecyclerView.ensureBottomPadding()
+
binding.draftsErrorMessageView.setup(R.drawable.elephant_friend_empty, R.string.no_drafts)
val adapter = DraftsAdapter(this)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/filters/EditFilterActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/filters/EditFilterActivity.kt
index 227cdcacb..81a5d5e15 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/filters/EditFilterActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/filters/EditFilterActivity.kt
@@ -20,7 +20,10 @@ import android.os.Bundle
import android.view.WindowManager
import android.widget.AdapterView
import androidx.activity.viewModels
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
import androidx.core.view.size
+import androidx.core.view.updatePadding
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.lifecycleScope
import at.connyduck.calladapter.networkresult.fold
@@ -91,6 +94,12 @@ class EditFilterActivity : BaseActivity() {
}
)
+ ViewCompat.setOnApplyWindowInsetsListener(binding.scrollView) { scrollView, insets ->
+ val systemBarsInsets = insets.getInsets(systemBars())
+ scrollView.updatePadding(bottom = systemBarsInsets.bottom)
+ insets.inset(0, 0, 0, systemBarsInsets.bottom)
+ }
+
binding.actionChip.setOnClickListener { showAddKeywordDialog() }
binding.filterSaveButton.setOnClickListener { saveChanges() }
binding.filterDeleteButton.setOnClickListener {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/filters/FiltersActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/filters/FiltersActivity.kt
index edfa81abc..c4087fd57 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/filters/FiltersActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/filters/FiltersActivity.kt
@@ -11,6 +11,8 @@ import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.databinding.ActivityFiltersBinding
import com.keylesspalace.tusky.entity.Filter
+import com.keylesspalace.tusky.util.ensureBottomMargin
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.launchAndRepeatOnLifecycle
import com.keylesspalace.tusky.util.show
@@ -43,6 +45,9 @@ class FiltersActivity : BaseActivity(), FiltersListener {
setDisplayShowHomeEnabled(true)
}
+ binding.filtersList.ensureBottomPadding(fab = true)
+ binding.addFilterButton.ensureBottomMargin()
+
binding.addFilterButton.setOnClickListener {
launchEditFilterActivity()
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt
index 3c6fe5d47..c3920e801 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt
@@ -18,6 +18,8 @@ import com.keylesspalace.tusky.databinding.ActivityFollowedTagsBinding
import com.keylesspalace.tusky.interfaces.HashtagActionListener
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.copyToClipboard
+import com.keylesspalace.tusky.util.ensureBottomMargin
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.viewBinding
@@ -54,6 +56,9 @@ class FollowedTagsActivity :
setDisplayShowHomeEnabled(true)
}
+ binding.fab.ensureBottomMargin()
+ binding.followedTagsView.ensureBottomPadding(fab = true)
+
binding.fab.setOnClickListener {
showDialog()
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt
index 3ddb0f706..9bd35af3e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt
@@ -25,6 +25,9 @@ import android.view.Menu
import android.view.View
import android.widget.TextView
import androidx.core.net.toUri
+import androidx.core.view.WindowInsetsCompat.Type.ime
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import at.connyduck.calladapter.networkresult.fold
import com.bumptech.glide.Glide
@@ -39,6 +42,7 @@ import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.getNonNullString
import com.keylesspalace.tusky.util.openLinkInCustomTab
import com.keylesspalace.tusky.util.rickRoll
+import com.keylesspalace.tusky.util.setOnWindowInsetsChangeListener
import com.keylesspalace.tusky.util.shouldRickRoll
import com.keylesspalace.tusky.util.viewBinding
import dagger.hilt.android.AndroidEntryPoint
@@ -75,6 +79,11 @@ class LoginActivity : BaseActivity() {
setContentView(binding.root)
+ binding.loginScrollView.setOnWindowInsetsChangeListener { windowInsets ->
+ val insets = windowInsets.getInsets(systemBars() or ime())
+ binding.loginScrollView.updatePadding(bottom = insets.bottom)
+ }
+
if (savedInstanceState == null &&
BuildConfig.CUSTOM_INSTANCE.isNotBlank() &&
!isAdditionalLogin()
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt
index 3eb271f4e..29c63ddee 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt
@@ -33,6 +33,11 @@ import android.webkit.WebViewClient
import androidx.activity.result.contract.ActivityResultContract
import androidx.activity.viewModels
import androidx.core.net.toUri
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsCompat.Type.ime
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.keylesspalace.tusky.BaseActivity
@@ -122,10 +127,15 @@ class LoginWebViewActivity : BaseActivity() {
setTitle(R.string.title_login)
+ ViewCompat.setOnApplyWindowInsetsListener(binding.loginWebView) { _, insets ->
+ val bottomInsets = insets.getInsets(systemBars() or ime()).bottom
+ binding.root.updatePadding(bottom = bottomInsets)
+ WindowInsetsCompat.CONSUMED
+ }
+
val webView = binding.loginWebView
webView.settings.allowContentAccess = false
webView.settings.allowFileAccess = false
- webView.settings.databaseEnabled = false
webView.settings.displayZoomControls = false
webView.settings.javaScriptCanOpenWindowsAutomatically = false
// JavaScript needs to be enabled because otherwise 2FA does not work in some instances
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt
index 1aa53147a..6c1a81f6c 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt
@@ -65,6 +65,7 @@ import com.keylesspalace.tusky.util.CardViewMode
import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate
import com.keylesspalace.tusky.util.StatusDisplayOptions
import com.keylesspalace.tusky.util.StatusProvider
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.openLink
import com.keylesspalace.tusky.util.show
@@ -137,6 +138,8 @@ class NotificationsFragment :
openSpoiler = accountManager.activeAccount!!.alwaysOpenSpoiler
)
+ binding.recyclerView.ensureBottomPadding(fab = true)
+
// setup the notifications filter bar
showNotificationsFilterBar = preferences.getBoolean(PrefKeys.SHOW_NOTIFICATIONS_FILTER, true)
updateFilterBarVisibility()
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/AccountPreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/AccountPreferencesFragment.kt
index 8f6425115..d48f92d0e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/preference/AccountPreferencesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/AccountPreferencesFragment.kt
@@ -23,7 +23,6 @@ import android.os.Bundle
import android.util.Log
import androidx.lifecycle.lifecycleScope
import androidx.preference.ListPreference
-import androidx.preference.PreferenceFragmentCompat
import at.connyduck.calladapter.networkresult.fold
import com.google.android.material.color.MaterialColors
import com.google.android.material.snackbar.Snackbar
@@ -64,7 +63,7 @@ import javax.inject.Inject
import kotlinx.coroutines.launch
@AndroidEntryPoint
-class AccountPreferencesFragment : PreferenceFragmentCompat() {
+class AccountPreferencesFragment : BasePreferencesFragment() {
@Inject
lateinit var accountManager: AccountManager
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/BasePreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/BasePreferencesFragment.kt
new file mode 100644
index 000000000..ba452f0bb
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/BasePreferencesFragment.kt
@@ -0,0 +1,20 @@
+package com.keylesspalace.tusky.components.preference
+
+import android.os.Bundle
+import android.view.View
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updatePadding
+import androidx.preference.PreferenceFragmentCompat
+
+abstract class BasePreferencesFragment : PreferenceFragmentCompat() {
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ ViewCompat.setOnApplyWindowInsetsListener(listView) { listView, insets ->
+ val systemBarsInsets = insets.getInsets(systemBars())
+ listView.updatePadding(bottom = systemBarsInsets.bottom)
+ insets.inset(0, 0, 0, systemBarsInsets.bottom)
+ }
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/NotificationPreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/NotificationPreferencesFragment.kt
index 46c8719b2..e59ba9186 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/preference/NotificationPreferencesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/NotificationPreferencesFragment.kt
@@ -17,7 +17,6 @@ package com.keylesspalace.tusky.components.preference
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
-import androidx.preference.PreferenceFragmentCompat
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.systemnotifications.NotificationService
import com.keylesspalace.tusky.db.AccountManager
@@ -31,7 +30,7 @@ import javax.inject.Inject
import kotlinx.coroutines.launch
@AndroidEntryPoint
-class NotificationPreferencesFragment : PreferenceFragmentCompat() {
+class NotificationPreferencesFragment : BasePreferencesFragment() {
@Inject
lateinit var accountManager: AccountManager
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt
index 689f83982..9a71d34bd 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt
@@ -18,9 +18,11 @@ package com.keylesspalace.tusky.components.preference
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
+import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.activity.OnBackPressedCallback
+import androidx.core.view.WindowCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope
@@ -66,6 +68,12 @@ class PreferencesActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ // Workaround for edge-to-edge mode not working when an activity is recreated
+ // https://stackoverflow.com/questions/79319740/edge-to-edge-doesnt-work-when-activity-recreated-or-appcompatdelegate-setdefaul
+ if (savedInstanceState != null && Build.VERSION.SDK_INT >= 35) {
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+ }
+
val binding = ActivityPreferencesBinding.inflate(layoutInflater)
setContentView(binding.root)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt
index ff66c9e6f..66de6335f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt
@@ -18,7 +18,6 @@ package com.keylesspalace.tusky.components.preference
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
-import androidx.preference.PreferenceFragmentCompat
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.entity.Notification
@@ -40,7 +39,7 @@ import javax.inject.Inject
import kotlinx.coroutines.launch
@AndroidEntryPoint
-class PreferencesFragment : PreferenceFragmentCompat() {
+class PreferencesFragment : BasePreferencesFragment() {
@Inject
lateinit var accountManager: AccountManager
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/ProxyPreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/ProxyPreferencesFragment.kt
index 84f1336f1..fba6c8ba8 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/preference/ProxyPreferencesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/ProxyPreferencesFragment.kt
@@ -17,7 +17,6 @@ package com.keylesspalace.tusky.components.preference
import android.os.Bundle
import androidx.preference.Preference
-import androidx.preference.PreferenceFragmentCompat
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.settings.ProxyConfiguration
@@ -30,7 +29,7 @@ import com.keylesspalace.tusky.settings.validatedEditTextPreference
import com.keylesspalace.tusky.util.getNonNullString
import kotlin.system.exitProcess
-class ProxyPreferencesFragment : PreferenceFragmentCompat() {
+class ProxyPreferencesFragment : BasePreferencesFragment() {
private var pendingRestart = false
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/TabFilterPreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/TabFilterPreferencesFragment.kt
index 032b80ced..6d9141c93 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/preference/TabFilterPreferencesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/TabFilterPreferencesFragment.kt
@@ -19,7 +19,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.color.MaterialColors
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.settings.AccountPreferenceDataStore
@@ -31,7 +30,7 @@ import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
-class TabFilterPreferencesFragment : PreferenceFragmentCompat() {
+class TabFilterPreferencesFragment : BasePreferencesFragment() {
@Inject
lateinit var accountPreferenceDataStore: AccountPreferenceDataStore
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/ReportActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/ReportActivity.kt
index 7cbb97782..fa3a43251 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/report/ReportActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/report/ReportActivity.kt
@@ -19,6 +19,9 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.keylesspalace.tusky.BottomSheetActivity
import com.keylesspalace.tusky.R
@@ -58,6 +61,13 @@ class ReportActivity : BottomSheetActivity() {
setHomeAsUpIndicator(R.drawable.ic_close_24dp)
}
+ ViewCompat.setOnApplyWindowInsetsListener(binding.wizard) { wizard, insets ->
+ val systemBarInsets = insets.getInsets(systemBars())
+ wizard.updatePadding(bottom = systemBarInsets.bottom)
+
+ insets.inset(0, 0, 0, systemBarInsets.bottom)
+ }
+
initViewPager()
if (savedInstanceState == null) {
viewModel.navigateTo(Screen.Statuses)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt
index aa59a59a9..d613d78d4 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt
@@ -36,6 +36,7 @@ import com.keylesspalace.tusky.appstore.StatusScheduledEvent
import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.databinding.ActivityScheduledStatusBinding
import com.keylesspalace.tusky.entity.ScheduledStatus
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.viewBinding
@@ -76,6 +77,8 @@ class ScheduledStatusActivity :
setDisplayShowHomeEnabled(true)
}
+ binding.scheduledTootList.ensureBottomPadding()
+
binding.swipeRefreshLayout.setOnRefreshListener(this::refreshStatuses)
binding.scheduledTootList.setHasFixedSize(true)
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt
index 6dfe2c02b..7b6b3f3fd 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt
@@ -26,6 +26,7 @@ import com.keylesspalace.tusky.components.search.SearchViewModel
import com.keylesspalace.tusky.databinding.FragmentSearchBinding
import com.keylesspalace.tusky.interfaces.LinkListener
import com.keylesspalace.tusky.network.MastodonApi
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation
import com.keylesspalace.tusky.util.viewBinding
import com.keylesspalace.tusky.util.visible
@@ -63,6 +64,7 @@ abstract class SearchFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val adapter = initAdapter()
binding.swipeRefreshLayout.setOnRefreshListener(this)
+ binding.searchRecyclerView.ensureBottomPadding()
requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
subscribeObservables(adapter)
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt
index a4d98648f..30a1e5fbe 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt
@@ -25,7 +25,6 @@ import android.view.View
import android.view.accessibility.AccessibilityManager
import androidx.core.content.getSystemService
import androidx.core.view.MenuProvider
-import androidx.core.view.updatePadding
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
@@ -61,6 +60,7 @@ import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.CardViewMode
import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate
import com.keylesspalace.tusky.util.StatusDisplayOptions
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation
@@ -378,6 +378,9 @@ class TimelineFragment :
}
private fun setupRecyclerView(adapter: TimelinePagingAdapter) {
+ val hasFab = (activity as? ActionButtonActivity?)?.actionButton != null
+ binding.recyclerView.ensureBottomPadding(fab = hasFab)
+
binding.recyclerView.setAccessibilityDelegateCompat(
ListStatusAccessibilityDelegate(binding.recyclerView, this) { pos ->
if (pos in 0 until adapter.itemCount) {
@@ -387,19 +390,11 @@ class TimelineFragment :
}
}
)
- binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.layoutManager = LinearLayoutManager(context)
+
val divider = DividerItemDecoration(context, RecyclerView.VERTICAL)
binding.recyclerView.addItemDecoration(divider)
- val recyclerViewBottomPadding = if ((activity as? ActionButtonActivity?)?.actionButton != null) {
- resources.getDimensionPixelSize(R.dimen.recyclerview_bottom_padding_actionbutton)
- } else {
- resources.getDimensionPixelSize(R.dimen.recyclerview_bottom_padding_no_actionbutton)
- }
-
- binding.recyclerView.updatePadding(bottom = recyclerViewBottomPadding)
-
// CWs are expanded without animation, buttons animate itself, we don't need it basically
(binding.recyclerView.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
binding.recyclerView.adapter = adapter
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/trending/TrendingTagsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/trending/TrendingTagsFragment.kt
index b6c195679..217e47165 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/trending/TrendingTagsFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/trending/TrendingTagsFragment.kt
@@ -38,6 +38,7 @@ import com.keylesspalace.tusky.databinding.FragmentTrendingTagsBinding
import com.keylesspalace.tusky.interfaces.ActionButtonActivity
import com.keylesspalace.tusky.interfaces.RefreshableFragment
import com.keylesspalace.tusky.interfaces.ReselectableFragment
+import com.keylesspalace.tusky.util.ensureBottomPadding
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation
@@ -121,6 +122,8 @@ class TrendingTagsFragment :
}
private fun setupRecyclerView(adapter: TrendingTagsAdapter) {
+ binding.recyclerView.ensureBottomPadding()
+
val columnCount =
requireContext().resources.getInteger(R.integer.trending_column_count)
setupLayoutManager(adapter, columnCount)
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewImageFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewImageFragment.kt
index a386d5524..dc9721f09 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewImageFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewImageFragment.kt
@@ -27,6 +27,9 @@ import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
@@ -107,6 +110,14 @@ class ViewImageFragment : ViewMediaFragment() {
}
}
+ ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
+ val systemBarInsets = insets.getInsets(systemBars())
+ val mediaDescriptionBottomPadding = requireContext().resources.getDimensionPixelSize(R.dimen.media_description_sheet_bottom_padding)
+ binding.mediaDescription.updatePadding(bottom = mediaDescriptionBottomPadding + systemBarInsets.bottom)
+
+ insets.inset(0, 0, 0, systemBarInsets.bottom)
+ }
+
val singleTapDetector = GestureDetector(
requireContext(),
object : GestureDetector.SimpleOnGestureListener() {
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt
index d450d0f28..e40d79be4 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewVideoFragment.kt
@@ -31,6 +31,11 @@ import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.annotation.OptIn
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updateLayoutParams
+import androidx.core.view.updatePadding
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.media3.common.AudioAttributes
@@ -130,6 +135,16 @@ class ViewVideoFragment : ViewMediaFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+ ViewCompat.setOnApplyWindowInsetsListener(binding.mediaDescriptionScrollView) { captionSheet, insets ->
+ val systemBarInsets = insets.getInsets(systemBars())
+ captionSheet.updatePadding(bottom = systemBarInsets.bottom)
+ binding.videoView.updateLayoutParams {
+ bottomMargin = systemBarInsets.bottom
+ }
+
+ insets.inset(0, 0, 0, systemBarInsets.bottom)
+ }
+
/**
* Handle single taps, flings, and dragging
*/
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ViewExtensions.kt b/app/src/main/java/com/keylesspalace/tusky/util/ViewExtensions.kt
index 392f65b77..879d6470d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/ViewExtensions.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/util/ViewExtensions.kt
@@ -18,9 +18,21 @@ package com.keylesspalace.tusky.util
import android.util.Log
import android.view.View
+import android.view.ViewGroup
import android.widget.TextView
+import androidx.core.graphics.Insets
+import androidx.core.view.OnApplyWindowInsetsListener
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsAnimationCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsCompat.Type.ime
+import androidx.core.view.WindowInsetsCompat.Type.systemBars
+import androidx.core.view.updateLayoutParams
+import androidx.core.view.updatePadding
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+import com.keylesspalace.tusky.R
fun View.show() {
this.visibility = View.VISIBLE
@@ -78,3 +90,98 @@ fun TextView.fixTextSelection() {
setTextIsSelectable(false)
post { setTextIsSelectable(true) }
}
+
+/**
+ * Makes sure the [RecyclerView] has the correct bottom padding set
+ * and no system bars or floating action buttons cover the content when it is scrolled all the way up.
+ * This must be called before window insets are applied (Activity.onCreate or Fragment.onViewCreated).
+ * The RecyclerView needs to have clipToPadding set to false for this to work.
+ * @param fab true if there is a [FloatingActionButton] above the RecyclerView
+ */
+fun RecyclerView.ensureBottomPadding(fab: Boolean = false) {
+ val bottomPadding = if (fab) {
+ context.resources.getDimensionPixelSize(R.dimen.recyclerview_bottom_padding_actionbutton)
+ } else {
+ context.resources.getDimensionPixelSize(R.dimen.recyclerview_bottom_padding_no_actionbutton)
+ }
+
+ ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
+ val systemBarsInsets = insets.getInsets(systemBars())
+ view.updatePadding(bottom = bottomPadding + systemBarsInsets.bottom)
+ WindowInsetsCompat.Builder(insets)
+ .setInsets(systemBars(), Insets.of(systemBarsInsets.left, systemBarsInsets.top, systemBarsInsets.right, 0))
+ .build()
+ }
+}
+
+/** Makes sure a [FloatingActionButton] has the correct bottom margin set
+ * so it is not covered by any system bars.
+ */
+fun FloatingActionButton.ensureBottomMargin() {
+ ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
+ val bottomInsets = insets.getInsets(systemBars()).bottom
+ val actionButtonMargin = resources.getDimensionPixelSize(R.dimen.fabMargin)
+ view.updateLayoutParams {
+ bottomMargin = bottomInsets + actionButtonMargin
+ }
+ insets
+ }
+}
+
+/**
+ * Combines WindowInsetsAnimationCompat.Callback and OnApplyWindowInsetsListener
+ * for easy implementation of layouts that animate with they keyboard.
+ * The animation callback is only called when something animates, so it isn't suitable for initial setup.
+ * The OnApplyWindowInsetsListener can do that, but the insets it supplies must not be used when an animation is ongoing,
+ * as that messes with the animation.
+ */
+fun View.setOnWindowInsetsChangeListener(listener: (WindowInsetsCompat) -> Unit) {
+ val callback = WindowInsetsCallback(listener)
+
+ ViewCompat.setWindowInsetsAnimationCallback(this, callback)
+ ViewCompat.setOnApplyWindowInsetsListener(this, callback)
+}
+
+private class WindowInsetsCallback(
+ private val listener: (WindowInsetsCompat) -> Unit,
+) : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP),
+ OnApplyWindowInsetsListener {
+
+ var imeVisible = false
+ var deferredInsets: WindowInsetsCompat? = null
+
+ override fun onStart(animation: WindowInsetsAnimationCompat, bounds: WindowInsetsAnimationCompat.BoundsCompat): WindowInsetsAnimationCompat.BoundsCompat {
+ imeVisible = true
+ return super.onStart(animation, bounds)
+ }
+
+ override fun onProgress(
+ insets: WindowInsetsCompat,
+ runningAnimations: List,
+ ): WindowInsetsCompat {
+ listener(insets)
+ return WindowInsetsCompat.CONSUMED
+ }
+
+ override fun onApplyWindowInsets(
+ view: View,
+ insets: WindowInsetsCompat,
+ ): WindowInsetsCompat {
+ val ime = insets.getInsets(ime()).bottom
+ if (!imeVisible && ime == 0) {
+ listener(insets)
+ deferredInsets = null
+ } else {
+ deferredInsets = insets
+ }
+ return WindowInsetsCompat.CONSUMED
+ }
+
+ override fun onEnd(animation: WindowInsetsAnimationCompat) {
+ imeVisible = deferredInsets?.isVisible(ime()) == true
+ deferredInsets?.let { insets ->
+ listener(insets)
+ deferredInsets = null
+ }
+ }
+}
diff --git a/app/src/main/res/layout-sw640dp/fragment_timeline.xml b/app/src/main/res/layout-sw640dp/fragment_timeline.xml
index 415695912..19a95b21e 100644
--- a/app/src/main/res/layout-sw640dp/fragment_timeline.xml
+++ b/app/src/main/res/layout-sw640dp/fragment_timeline.xml
@@ -16,10 +16,10 @@
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:indeterminate="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
- android:indeterminate="true"
app:layout_constraintTop_toTopOf="parent" />
-
+ android:layout_height="match_parent"
+ android:clipToPadding="false" />
-
-
-
-
+
+
-
+ android:layout_height="match_parent"
+ android:background="?android:attr/colorBackground"
+ android:clipToPadding="false"
+ android:paddingBottom="@dimen/recyclerview_bottom_padding_actionbutton" />
-
-
-
-
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_compose.xml b/app/src/main/res/layout/activity_compose.xml
index ec0df7c93..77ec47fa4 100644
--- a/app/src/main/res/layout/activity_compose.xml
+++ b/app/src/main/res/layout/activity_compose.xml
@@ -6,79 +6,87 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+ android:background="@android:color/transparent"
+ android:fitsSystemWindows="true">
-
-
+
-
+
+
-
+
-
+
-
+
-
+
+
+
+
+
+ android:layout_marginBottom="52dp"
+ android:clipToPadding="false"
+ android:paddingTop="8dp"
+ app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
+ android:paddingBottom="4dp"
+ app:layout_insetEdge="bottom">
+ android:paddingBottom="12dp"
+ android:textDirection="anyRtl">
@@ -37,9 +39,9 @@
@@ -47,9 +49,9 @@
@@ -57,9 +59,9 @@
@@ -67,9 +69,9 @@
@@ -77,9 +79,9 @@
@@ -87,9 +89,9 @@
@@ -97,9 +99,9 @@
@@ -107,9 +109,9 @@
@@ -117,9 +119,9 @@
@@ -127,9 +129,9 @@
@@ -137,9 +139,9 @@
@@ -147,9 +149,9 @@
@@ -157,9 +159,9 @@
@@ -167,9 +169,9 @@
@@ -177,9 +179,9 @@
@@ -187,9 +189,9 @@
@@ -197,9 +199,9 @@
@@ -207,9 +209,9 @@
@@ -218,9 +220,9 @@
android:id="@+id/licenseApacheTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginEnd="18dp"
android:layout_marginStart="18dp"
android:layout_marginTop="12dp"
+ android:layout_marginEnd="18dp"
android:textSize="12sp" />
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index b885fd053..c25a28920 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -1,19 +1,33 @@
-
+
+
+
+
+
+
+ android:clipToPadding="false"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior">
+ android:layout_gravity="center"
+ android:indeterminate="true" />
+
-
-
-
+
diff --git a/app/src/main/res/layout/activity_login_webview.xml b/app/src/main/res/layout/activity_login_webview.xml
index 5dee10361..e14e86d84 100644
--- a/app/src/main/res/layout/activity_login_webview.xml
+++ b/app/src/main/res/layout/activity_login_webview.xml
@@ -8,6 +8,7 @@
+ android:fitsSystemWindows="@bool/is_edge_to_edge"
+ app:liftOnScroll="false"
+ app:statusBarForeground="?attr/colorSurface">
+ app:paddingBottomSystemWindowInsets="true">
+ app:liftOnScroll="false"
+ app:statusBarForeground="?attr/colorSurface">
@@ -37,7 +37,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
- android:layout_margin="16dp"
+ android:layout_margin="@dimen/fabMargin"
android:visibility="invisible"
app:strokeWidth="0dp"
app:cardBackgroundColor="?attr/colorSurface"
diff --git a/app/src/main/res/layout/activity_view_media.xml b/app/src/main/res/layout/activity_view_media.xml
index 94ffa8f65..d29d34538 100644
--- a/app/src/main/res/layout/activity_view_media.xml
+++ b/app/src/main/res/layout/activity_view_media.xml
@@ -1,30 +1,39 @@
-
+ android:background="@color/black">
+
+
+
+
+
+
-
-
-
+
diff --git a/app/src/main/res/layout/fragment_timeline.xml b/app/src/main/res/layout/fragment_timeline.xml
index 66e645dfb..7f5257a10 100644
--- a/app/src/main/res/layout/fragment_timeline.xml
+++ b/app/src/main/res/layout/fragment_timeline.xml
@@ -1,34 +1,11 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:paddingBottom="@dimen/recyclerview_bottom_padding_actionbutton" />
+
+
-
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:paddingBottom="@dimen/recyclerview_bottom_padding_no_actionbutton" />
-
-
-
-
+
+