Skip to content

Commit 5f621b9

Browse files
committed
Add Edge-to-Edge support to further views
Fixes #599
1 parent 0b680e8 commit 5f621b9

18 files changed

+212
-29
lines changed

presentation/src/main/java/org/cryptomator/presentation/ui/fragment/AutoUploadChooseVaultFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class AutoUploadChooseVaultFragment : BaseFragment<FragmentAutoUploadChooseVault
2323
lateinit var sharedPreferencesHandler: SharedPreferencesHandler
2424

2525
override fun setupView() {
26-
binding.toolbarBottom.saveFiles.setOnClickListener { presenter.onChooseVaultPressed() }
26+
binding.chooseVaultLayout.saveFiles.setOnClickListener { presenter.onChooseVaultPressed() }
2727

2828
setupRecyclerView()
2929
}

presentation/src/main/java/org/cryptomator/presentation/ui/fragment/LicensesFragment.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package org.cryptomator.presentation.ui.fragment
22

33
import android.os.Bundle
4-
import androidx.preference.PreferenceFragmentCompat
54
import org.cryptomator.presentation.R
5+
import org.cryptomator.presentation.ui.layout.PreferenceFragmentCompatLayout
66

77
// Don't delete this file as it isn't unused but referenced by layout file
8-
class LicensesFragment : PreferenceFragmentCompat() {
8+
class LicensesFragment : PreferenceFragmentCompatLayout() {
99

1010
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
1111
addPreferencesFromResource(R.xml.licenses)

presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import androidx.biometric.BiometricManager
1111
import androidx.core.content.ContextCompat
1212
import androidx.preference.Preference
1313
import androidx.preference.PreferenceCategory
14-
import androidx.preference.PreferenceFragmentCompat
1514
import androidx.preference.SwitchPreference
1615
import org.cryptomator.presentation.BuildConfig
1716
import org.cryptomator.presentation.R
@@ -26,6 +25,7 @@ import org.cryptomator.presentation.ui.dialog.DebugModeDisclaimerDialog
2625
import org.cryptomator.presentation.ui.dialog.DisableAppWhenObscuredDisclaimerDialog
2726
import org.cryptomator.presentation.ui.dialog.DisableSecureScreenDisclaimerDialog
2827
import org.cryptomator.presentation.ui.dialog.MicrosoftWorkaroundDisclaimerDialog
28+
import org.cryptomator.presentation.ui.layout.PreferenceFragmentCompatLayout
2929
import org.cryptomator.util.SharedPreferencesHandler
3030
import org.cryptomator.util.SharedPreferencesHandler.Companion.CRYPTOMATOR_VARIANTS
3131
import org.cryptomator.util.file.LruFileCacheUtil
@@ -36,7 +36,7 @@ import java.text.DecimalFormat
3636
import kotlin.math.log10
3737
import timber.log.Timber
3838

39-
class SettingsFragment : PreferenceFragmentCompat() {
39+
class SettingsFragment : PreferenceFragmentCompatLayout() {
4040

4141
private lateinit var sharedPreferencesHandler: SharedPreferencesHandler
4242

presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SharedFilesFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class SharedFilesFragment : BaseFragment<FragmentSharedFilesBinding>(FragmentSha
4747
}
4848

4949
override fun setupView() {
50-
binding.toolbarBottom.saveFiles.setOnClickListener { presenter.onSaveButtonPressed(filesAdapter.all) }
50+
binding.receiveSaveLayout.saveFiles.setOnClickListener { presenter.onSaveButtonPressed(filesAdapter.all) }
5151
setupRecyclerView()
5252
}
5353

presentation/src/main/java/org/cryptomator/presentation/ui/fragment/TextEditorFragment.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package org.cryptomator.presentation.ui.fragment
22

3+
import android.os.Bundle
34
import android.text.Spannable
45
import android.text.style.BackgroundColorSpan
6+
import android.view.View
57
import androidx.annotation.NonNull
68
import androidx.core.content.ContextCompat
79
import com.google.android.material.textfield.TextInputEditText
810
import org.cryptomator.generator.Fragment
911
import org.cryptomator.presentation.R
1012
import org.cryptomator.presentation.databinding.FragmentTextEditorBinding
1113
import org.cryptomator.presentation.presenter.TextEditorPresenter
14+
import org.cryptomator.presentation.ui.layout.applySystemBarsPadding
1215
import javax.inject.Inject
1316

1417
@Fragment
@@ -93,7 +96,8 @@ class TextEditorFragment : BaseFragment<FragmentTextEditorBinding>(FragmentTextE
9396

9497
textEditorPresenter.lastFilterLocation = index
9598

96-
binding.textViewWrapper.scrollTo(0, binding.textEditor.layout.getLineTop(binding.textEditor.layout.getLineForOffset(index)))
99+
binding.textEditor.setSelection(index, index + it.length)
100+
binding.textEditor.post { binding.textEditor.bringPointIntoView(index) }
97101
}
98102
}
99103

@@ -105,5 +109,10 @@ class TextEditorFragment : BaseFragment<FragmentTextEditorBinding>(FragmentTextE
105109
}
106110
}
107111

112+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
113+
super.onViewCreated(view, savedInstanceState)
114+
binding.textEditor.applySystemBarsPadding(left = true, right = true, bottom = true)
115+
}
116+
108117
enum class Direction { PREVIOUS, NEXT }
109118
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.cryptomator.presentation.ui.layout
2+
3+
import android.content.Context
4+
import android.util.AttributeSet
5+
import android.widget.RelativeLayout
6+
7+
class BottomToolbarLayout @JvmOverloads constructor(
8+
context: Context,
9+
attrs: AttributeSet? = null,
10+
defStyleAttr: Int = 0
11+
) : RelativeLayout(context, attrs, defStyleAttr) {
12+
13+
override fun onAttachedToWindow() {
14+
super.onAttachedToWindow()
15+
applySystemBarsMargins(end = true, bottom = true)
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.cryptomator.presentation.ui.layout
2+
3+
import android.content.Context
4+
import android.util.AttributeSet
5+
import com.google.android.material.floatingactionbutton.FloatingActionButton
6+
7+
class FloatingActionButtonLayout @JvmOverloads constructor(
8+
context: Context,
9+
attrs: AttributeSet? = null,
10+
defStyleAttr: Int = com.google.android.material.R.attr.floatingActionButtonStyle
11+
) : FloatingActionButton(context, attrs, defStyleAttr) {
12+
13+
override fun onAttachedToWindow() {
14+
super.onAttachedToWindow()
15+
applySystemBarsMargins(end = true, bottom = true)
16+
}
17+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package org.cryptomator.presentation.ui.layout
2+
3+
import android.view.View
4+
import android.view.ViewGroup
5+
import androidx.core.view.ViewCompat
6+
import androidx.core.view.WindowInsetsCompat
7+
import androidx.core.view.updatePadding
8+
import androidx.recyclerview.widget.RecyclerView
9+
import kotlin.math.max
10+
11+
/** Apply system bar/IME insets as *padding* on any View (e.g., toolbars, bottom bars, scroll containers). */
12+
fun View.applySystemBarsPadding(
13+
left: Boolean = false,
14+
top: Boolean = false,
15+
right: Boolean = false,
16+
bottom: Boolean = false,
17+
includeIme: Boolean = true
18+
) {
19+
val baseL = paddingLeft
20+
val baseT = paddingTop
21+
val baseR = paddingRight
22+
val baseB = paddingBottom
23+
24+
ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
25+
val sys = insets.getInsets(WindowInsetsCompat.Type.systemBars())
26+
val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
27+
val btm = if (includeIme) max(sys.bottom, ime.bottom) else sys.bottom
28+
v.updatePadding(
29+
left = if (left) baseL + sys.left else baseL,
30+
top = if (top) baseT + sys.top else baseT,
31+
right = if (right) baseR + sys.right else baseR,
32+
bottom = if (bottom) baseB + btm else baseB
33+
)
34+
insets
35+
}
36+
requestApplyInsetsWhenAttached()
37+
}
38+
39+
/** Apply system bar/IME insets as *margins* (useful for floating views like FABs). */
40+
fun View.applySystemBarsMargins(
41+
start: Boolean = false,
42+
top: Boolean = false,
43+
end: Boolean = false,
44+
bottom: Boolean = false,
45+
includeIme: Boolean = true
46+
) {
47+
val lp = layoutParams as? ViewGroup.MarginLayoutParams ?: return
48+
val baseStart = lp.marginStart
49+
val baseEnd = lp.marginEnd
50+
val baseTop = lp.topMargin
51+
val baseBottom = lp.bottomMargin
52+
53+
ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
54+
val sys = insets.getInsets(WindowInsetsCompat.Type.systemBars())
55+
val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
56+
val btm = if (includeIme) max(sys.bottom, ime.bottom) else sys.bottom
57+
58+
if (start) lp.marginStart = baseStart + sys.left
59+
if (end) lp.marginEnd = baseEnd + sys.right
60+
if (top) lp.topMargin = baseTop + sys.top
61+
if (bottom) lp.bottomMargin = baseBottom + btm
62+
63+
v.layoutParams = lp
64+
insets
65+
}
66+
requestApplyInsetsWhenAttached()
67+
}
68+
69+
/** Helper for preferences */
70+
fun RecyclerView.applyPreferenceInsets(
71+
left: Boolean = true,
72+
right: Boolean = true,
73+
bottom: Boolean = true,
74+
includeIme: Boolean = true
75+
) {
76+
clipToPadding = false
77+
scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY
78+
applySystemBarsPadding(left = left, right = right, bottom = bottom, includeIme = includeIme)
79+
}
80+
81+
/** Ensure we receive insets once attached. */
82+
private fun View.requestApplyInsetsWhenAttached() {
83+
if (isAttachedToWindow) requestApplyInsets() else addOnAttachStateChangeListener(
84+
object : View.OnAttachStateChangeListener {
85+
override fun onViewAttachedToWindow(v: View) {
86+
v.removeOnAttachStateChangeListener(this); v.requestApplyInsets()
87+
}
88+
89+
override fun onViewDetachedFromWindow(v: View) {}
90+
}
91+
)
92+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.cryptomator.presentation.ui.layout
2+
3+
import android.os.Bundle
4+
import android.view.LayoutInflater
5+
import android.view.View
6+
import android.view.ViewGroup
7+
import androidx.preference.PreferenceFragmentCompat
8+
import androidx.recyclerview.widget.RecyclerView
9+
10+
abstract class PreferenceFragmentCompatLayout : PreferenceFragmentCompat() {
11+
12+
override fun onCreateRecyclerView(
13+
inflater: LayoutInflater,
14+
parent: ViewGroup,
15+
savedInstanceState: Bundle?
16+
): RecyclerView {
17+
val rv = super.onCreateRecyclerView(inflater, parent, savedInstanceState)
18+
rv.clipToPadding = false
19+
rv.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY
20+
rv.applyPreferenceInsets(left = true, right = true, bottom = true)
21+
return rv
22+
}
23+
}
24+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.cryptomator.presentation.ui.layout
2+
3+
import android.content.Context
4+
import android.util.AttributeSet
5+
import com.google.android.material.appbar.MaterialToolbar
6+
7+
class ToolbarLayout @JvmOverloads constructor(
8+
context: Context,
9+
attrs: AttributeSet? = null,
10+
defStyleAttr: Int = com.google.android.material.R.attr.toolbarStyle
11+
) : MaterialToolbar(context, attrs, defStyleAttr) {
12+
13+
override fun onAttachedToWindow() {
14+
super.onAttachedToWindow()
15+
this.applySystemBarsPadding(left = true, top = true, right = true)
16+
}
17+
}

0 commit comments

Comments
 (0)