Migrate bottom reader menu to Compose

This commit is contained in:
arkon 2023-08-04 18:05:02 -04:00
parent 7308090288
commit 8680accd8e
7 changed files with 144 additions and 236 deletions

View File

@ -0,0 +1,76 @@
package eu.kanade.presentation.reader
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
@Composable
fun BottomReaderBar(
readingMode: ReadingModeType,
onClickReadingMode: () -> Unit,
orientationMode: OrientationType,
onClickOrientationMode: () -> Unit,
cropEnabled: Boolean,
onClickCropBorder: () -> Unit,
onClickSettings: () -> Unit,
) {
// Match with toolbar background color set in ReaderActivity
val backgroundColor = MaterialTheme.colorScheme
.surfaceColorAtElevation(3.dp)
.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
Row(
modifier = Modifier
.fillMaxWidth()
.background(backgroundColor)
.padding(8.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
) {
IconButton(onClick = onClickReadingMode) {
Icon(
painter = painterResource(readingMode.iconRes),
contentDescription = stringResource(R.string.viewer),
)
}
IconButton(onClick = onClickCropBorder) {
Icon(
painter = painterResource(if (cropEnabled) R.drawable.ic_crop_24dp else R.drawable.ic_crop_off_24dp),
contentDescription = stringResource(R.string.pref_crop_borders),
)
}
IconButton(onClick = onClickOrientationMode) {
Icon(
painter = painterResource(orientationMode.iconRes),
contentDescription = stringResource(R.string.pref_rotation_type),
)
}
IconButton(onClick = onClickSettings) {
Icon(
imageVector = Icons.Outlined.Settings,
contentDescription = stringResource(R.string.action_settings),
)
}
}
}

View File

@ -53,6 +53,15 @@ fun ChapterNavigator(
val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
val haptic = LocalHapticFeedback.current val haptic = LocalHapticFeedback.current
// Match with toolbar background color set in ReaderActivity
val backgroundColor = MaterialTheme.colorScheme
.surfaceColorAtElevation(3.dp)
.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
val buttonColor = IconButtonDefaults.filledIconButtonColors(
containerColor = backgroundColor,
disabledContainerColor = backgroundColor,
)
// We explicitly handle direction based on the reader viewer rather than the system direction // We explicitly handle direction based on the reader viewer rather than the system direction
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
Row( Row(
@ -61,14 +70,6 @@ fun ChapterNavigator(
.padding(horizontal = horizontalPadding), .padding(horizontal = horizontalPadding),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
// Match with toolbar background color set in ReaderActivity
val backgroundColor = MaterialTheme.colorScheme
.surfaceColorAtElevation(3.dp)
.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
val buttonColor = IconButtonDefaults.filledIconButtonColors(
containerColor = backgroundColor,
disabledContainerColor = backgroundColor,
)
FilledIconButton( FilledIconButton(
enabled = if (isRtl) enabledNext else enabledPrevious, enabled = if (isRtl) enabledNext else enabledPrevious,
onClick = if (isRtl) onNextChapter else onPreviousChapter, onClick = if (isRtl) onNextChapter else onPreviousChapter,

View File

@ -25,6 +25,7 @@ import android.view.animation.AnimationUtils
import android.widget.Toast import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
@ -49,6 +50,7 @@ import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.transition.platform.MaterialContainerTransform import com.google.android.material.transition.platform.MaterialContainerTransform
import dev.chrisbanes.insetter.applyInsetter import dev.chrisbanes.insetter.applyInsetter
import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.base.BasePreferences
import eu.kanade.presentation.reader.BottomReaderBar
import eu.kanade.presentation.reader.ChapterNavigator import eu.kanade.presentation.reader.ChapterNavigator
import eu.kanade.presentation.reader.OrientationModeSelectDialog import eu.kanade.presentation.reader.OrientationModeSelectDialog
import eu.kanade.presentation.reader.PageIndicatorText import eu.kanade.presentation.reader.PageIndicatorText
@ -80,9 +82,7 @@ import eu.kanade.tachiyomi.util.system.hasDisplayCutout
import eu.kanade.tachiyomi.util.system.isNightMode import eu.kanade.tachiyomi.util.system.isNightMode
import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toShareIntent
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.copy
import eu.kanade.tachiyomi.util.view.setComposeContent import eu.kanade.tachiyomi.util.view.setComposeContent
import eu.kanade.tachiyomi.util.view.setTooltip
import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.drop
@ -95,12 +95,12 @@ import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.Constants import tachiyomi.core.Constants
import tachiyomi.core.preference.toggle
import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.launchIO
import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.launchNonCancellable
import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import kotlin.math.abs import kotlin.math.abs
@ -434,8 +434,6 @@ class ReaderActivity : BaseActivity() {
if (!readerPreferences.showReadingMode().get()) { if (!readerPreferences.showReadingMode().get()) {
menuToggleToast = toast(stringRes) menuToggleToast = toast(stringRes)
} }
updateCropBordersShortcut()
}, },
) )
} }
@ -461,36 +459,61 @@ class ReaderActivity : BaseActivity() {
} }
} }
// Init listeners on bottom menu binding.readerMenuBottom.setComposeContent {
binding.readerNav.setComposeContent {
val state by viewModel.state.collectAsState() val state by viewModel.state.collectAsState()
if (state.viewer == null) return@setComposeContent if (state.viewer == null) return@setComposeContent
val isRtl = state.viewer is R2LPagerViewer val isRtl = state.viewer is R2LPagerViewer
ChapterNavigator( val cropBorderPaged by readerPreferences.cropBorders().collectAsState()
isRtl = isRtl, val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState()
onNextChapter = ::loadNextChapter, val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode())
enabledNext = state.viewerChapters?.nextChapter != null, val cropEnabled = if (isPagerType) cropBorderPaged else cropBorderWebtoon
onPreviousChapter = ::loadPreviousChapter,
enabledPrevious = state.viewerChapters?.prevChapter != null,
currentPage = state.currentPage,
totalPages = state.totalPages,
onSliderValueChange = {
isScrollingThroughPages = true
moveToPageIndex(it)
},
)
}
initBottomShortcuts() Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
ChapterNavigator(
isRtl = isRtl,
onNextChapter = ::loadNextChapter,
enabledNext = state.viewerChapters?.nextChapter != null,
onPreviousChapter = ::loadPreviousChapter,
enabledPrevious = state.viewerChapters?.prevChapter != null,
currentPage = state.currentPage,
totalPages = state.totalPages,
onSliderValueChange = {
isScrollingThroughPages = true
moveToPageIndex(it)
},
)
BottomReaderBar(
readingMode = ReadingModeType.fromPreference(viewModel.getMangaReadingMode(resolveDefault = false)),
onClickReadingMode = viewModel::openReadingModeSelectDialog,
orientationMode = OrientationType.fromPreference(viewModel.getMangaOrientationType(resolveDefault = false)),
onClickOrientationMode = viewModel::openOrientationModeSelectDialog,
cropEnabled = cropEnabled,
onClickCropBorder = {
val enabled = viewModel.toggleCropBorders()
menuToggleToast?.cancel()
menuToggleToast = toast(
if (enabled) {
R.string.on
} else {
R.string.off
},
)
},
onClickSettings = viewModel::openSettingsDialog,
)
}
}
val toolbarBackground = (binding.toolbar.background as MaterialShapeDrawable).apply { val toolbarBackground = (binding.toolbar.background as MaterialShapeDrawable).apply {
elevation = resources.getDimension(R.dimen.m3_sys_elevation_level2) elevation = resources.getDimension(R.dimen.m3_sys_elevation_level2)
alpha = if (isNightMode()) 230 else 242 // 90% dark 95% light alpha = if (isNightMode()) 230 else 242 // 90% dark 95% light
} }
binding.toolbarBottom.background = toolbarBackground.copy(this@ReaderActivity)
val toolbarColor = ColorUtils.setAlphaComponent( val toolbarColor = ColorUtils.setAlphaComponent(
toolbarBackground.resolvedTintColor, toolbarBackground.resolvedTintColor,
toolbarBackground.alpha, toolbarBackground.alpha,
@ -504,87 +527,6 @@ class ReaderActivity : BaseActivity() {
setMenuVisibility(viewModel.state.value.menuVisible) setMenuVisibility(viewModel.state.value.menuVisible)
} }
private fun initBottomShortcuts() {
// Reading mode
with(binding.actionReadingMode) {
setTooltip(R.string.viewer)
setOnClickListener {
viewModel.openReadingModeSelectDialog()
}
}
// Crop borders
with(binding.actionCropBorders) {
setTooltip(R.string.pref_crop_borders)
setOnClickListener {
val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode())
val enabled = if (isPagerType) {
readerPreferences.cropBorders().toggle()
} else {
readerPreferences.cropBordersWebtoon().toggle()
}
menuToggleToast?.cancel()
menuToggleToast = toast(
if (enabled) {
R.string.on
} else {
R.string.off
},
)
}
}
updateCropBordersShortcut()
listOf(readerPreferences.cropBorders(), readerPreferences.cropBordersWebtoon())
.forEach { pref ->
pref.changes()
.onEach { updateCropBordersShortcut() }
.launchIn(lifecycleScope)
}
// Rotation
with(binding.actionRotation) {
setTooltip(R.string.rotation_type)
setOnClickListener {
viewModel.openOrientationModeSelectDialog()
}
}
// Settings sheet
with(binding.actionSettings) {
setTooltip(R.string.action_settings)
setOnClickListener {
viewModel.openSettingsDialog()
}
}
}
private fun updateOrientationShortcut(preference: Int) {
val orientation = OrientationType.fromPreference(preference)
binding.actionRotation.setImageResource(orientation.iconRes)
}
private fun updateCropBordersShortcut() {
val isPagerType = ReadingModeType.isPagerType(viewModel.getMangaReadingMode())
val enabled = if (isPagerType) {
readerPreferences.cropBorders().get()
} else {
readerPreferences.cropBordersWebtoon().get()
}
binding.actionCropBorders.setImageResource(
if (enabled) {
R.drawable.ic_crop_24dp
} else {
R.drawable.ic_crop_off_24dp
},
)
}
/** /**
* Sets the visibility of the menu according to [visible] and with an optional parameter to * Sets the visibility of the menu according to [visible] and with an optional parameter to
* [animate] the views. * [animate] the views.
@ -651,13 +593,8 @@ class ReaderActivity : BaseActivity() {
*/ */
private fun setManga(manga: Manga) { private fun setManga(manga: Manga) {
val prevViewer = viewModel.state.value.viewer val prevViewer = viewModel.state.value.viewer
val viewerMode = ReadingModeType.fromPreference(viewModel.getMangaReadingMode(resolveDefault = false))
binding.actionReadingMode.setImageResource(viewerMode.iconRes)
val newViewer = ReadingModeType.toViewer(viewModel.getMangaReadingMode(), this) val newViewer = ReadingModeType.toViewer(viewModel.getMangaReadingMode(), this)
updateCropBordersShortcut()
if (window.sharedElementEnterTransition is MaterialContainerTransform) { if (window.sharedElementEnterTransition is MaterialContainerTransform) {
// Wait until transition is complete to avoid crash on API 26 // Wait until transition is complete to avoid crash on API 26
window.sharedElementEnterTransition.doOnEnd { window.sharedElementEnterTransition.doOnEnd {
@ -892,7 +829,6 @@ class ReaderActivity : BaseActivity() {
if (newOrientation.flag != requestedOrientation) { if (newOrientation.flag != requestedOrientation) {
requestedOrientation = newOrientation.flag requestedOrientation = newOrientation.flag
} }
updateOrientationShortcut(viewModel.getMangaOrientationType(resolveDefault = false))
} }
/** /**

View File

@ -54,6 +54,7 @@ import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.preference.toggle
import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.launchIO
import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.launchNonCancellable
import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withIOContext
@ -661,6 +662,15 @@ class ReaderViewModel(
} }
} }
fun toggleCropBorders(): Boolean {
val isPagerType = ReadingModeType.isPagerType(getMangaReadingMode())
return if (isPagerType) {
readerPreferences.cropBorders().toggle()
} else {
readerPreferences.cropBordersWebtoon().toggle()
}
}
/** /**
* Generate a filename for the given [manga] and [page] * Generate a filename for the given [manga] and [page]
*/ */

View File

@ -2,10 +2,8 @@
package eu.kanade.tachiyomi.util.view package eu.kanade.tachiyomi.util.view
import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.view.Gravity import android.view.Gravity
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@ -13,9 +11,7 @@ import android.view.View
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.annotation.MenuRes import androidx.annotation.MenuRes
import androidx.annotation.StringRes
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.TooltipCompat
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -24,7 +20,6 @@ import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.platform.ViewCompositionStrategy
import com.google.android.material.shape.MaterialShapeDrawable
import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
@ -60,24 +55,6 @@ fun ComposeView.setComposeContent(
} }
} }
/**
* Adds a tooltip shown on long press.
*
* @param stringRes String resource for tooltip.
*/
inline fun View.setTooltip(@StringRes stringRes: Int) {
setTooltip(context.getString(stringRes))
}
/**
* Adds a tooltip shown on long press.
*
* @param text Text for tooltip.
*/
inline fun View.setTooltip(text: String) {
TooltipCompat.setTooltipText(this, text)
}
/** /**
* Shows a popup menu on top of this view. * Shows a popup menu on top of this view.
* *
@ -105,17 +82,6 @@ inline fun View.popupMenu(
return popup return popup
} }
/**
* Returns a deep copy of the provided [Drawable]
*/
inline fun <reified T : Drawable> T.copy(context: Context): T? {
return (constantState?.newDrawable()?.mutate() as? T).apply {
if (this is MaterialShapeDrawable) {
initializeElevationOverlay(context)
}
}
}
fun View?.isVisibleOnScreen(): Boolean { fun View?.isVisibleOnScreen(): Boolean {
if (this == null) { if (this == null) {
return false return false

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98 0,-0.34 -0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.09,-0.16 -0.26,-0.25 -0.44,-0.25 -0.06,0 -0.12,0.01 -0.17,0.03l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.06,-0.02 -0.12,-0.03 -0.18,-0.03 -0.17,0 -0.34,0.09 -0.43,0.25l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98 0,0.33 0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.09,0.16 0.26,0.25 0.44,0.25 0.06,0 0.12,-0.01 0.17,-0.03l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.06,0.02 0.12,0.03 0.18,0.03 0.17,0 0.34,-0.09 0.43,-0.25l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM17.45,11.27c0.04,0.31 0.05,0.52 0.05,0.73 0,0.21 -0.02,0.43 -0.05,0.73l-0.14,1.13 0.89,0.7 1.08,0.84 -0.7,1.21 -1.27,-0.51 -1.04,-0.42 -0.9,0.68c-0.43,0.32 -0.84,0.56 -1.25,0.73l-1.06,0.43 -0.16,1.13 -0.2,1.35h-1.4l-0.19,-1.35 -0.16,-1.13 -1.06,-0.43c-0.43,-0.18 -0.83,-0.41 -1.23,-0.71l-0.91,-0.7 -1.06,0.43 -1.27,0.51 -0.7,-1.21 1.08,-0.84 0.89,-0.7 -0.14,-1.13c-0.03,-0.31 -0.05,-0.54 -0.05,-0.74s0.02,-0.43 0.05,-0.73l0.14,-1.13 -0.89,-0.7 -1.08,-0.84 0.7,-1.21 1.27,0.51 1.04,0.42 0.9,-0.68c0.43,-0.32 0.84,-0.56 1.25,-0.73l1.06,-0.43 0.16,-1.13 0.2,-1.35h1.39l0.19,1.35 0.16,1.13 1.06,0.43c0.43,0.18 0.83,0.41 1.23,0.71l0.91,0.7 1.06,-0.43 1.27,-0.51 0.7,1.21 -1.07,0.85 -0.89,0.7 0.14,1.13zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z" />
</vector>

View File

@ -57,83 +57,11 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" /> android:minHeight="?attr/actionBarSize" />
<LinearLayout <androidx.compose.ui.platform.ComposeView
android:id="@+id/reader_menu_bottom" android:id="@+id/reader_menu_bottom"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" android:layout_gravity="bottom" />
android:orientation="vertical">
<androidx.compose.ui.platform.ComposeView
android:id="@+id/reader_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layoutDirection="ltr" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/toolbar_bottom"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom"
android:clickable="true"
tools:ignore="KeyboardInaccessibleWidget">
<ImageButton
android:id="@+id/action_reading_mode"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/viewer"
android:padding="@dimen/screen_edge_margin"
app:layout_constraintEnd_toStartOf="@id/action_crop_borders"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_reader_default_24dp"
app:tint="?attr/colorOnSurface" />
<ImageButton
android:id="@+id/action_crop_borders"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/pref_crop_borders"
android:padding="@dimen/screen_edge_margin"
app:layout_constraintEnd_toStartOf="@id/action_rotation"
app:layout_constraintStart_toEndOf="@+id/action_reading_mode"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_crop_24dp"
app:tint="?attr/colorOnSurface" />
<ImageButton
android:id="@+id/action_rotation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/pref_rotation_type"
android:padding="@dimen/screen_edge_margin"
app:layout_constraintEnd_toStartOf="@id/action_settings"
app:layout_constraintStart_toEndOf="@+id/action_crop_borders"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_screen_rotation_24dp"
app:tint="?attr/colorOnSurface" />
<ImageButton
android:id="@+id/action_settings"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/action_settings"
android:padding="@dimen/screen_edge_margin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/action_rotation"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_settings_24dp"
app:tint="?attr/colorOnSurface" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</FrameLayout> </FrameLayout>