Update incognito indicator and PreviewFragment

master
Koitharu 2 years ago
parent ff4eac8269
commit 61e02dd827
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -40,7 +40,6 @@ import org.koitharu.kotatsu.core.parser.favicon.FaviconFetcher
import org.koitharu.kotatsu.core.ui.image.CoilImageGetter import org.koitharu.kotatsu.core.ui.image.CoilImageGetter
import org.koitharu.kotatsu.core.ui.util.ActivityRecreationHandle import org.koitharu.kotatsu.core.ui.util.ActivityRecreationHandle
import org.koitharu.kotatsu.core.util.AcraScreenLogger import org.koitharu.kotatsu.core.util.AcraScreenLogger
import org.koitharu.kotatsu.core.util.IncognitoModeIndicator
import org.koitharu.kotatsu.core.util.ext.connectivityManager import org.koitharu.kotatsu.core.util.ext.connectivityManager
import org.koitharu.kotatsu.core.util.ext.isLowRamDevice import org.koitharu.kotatsu.core.util.ext.isLowRamDevice
import org.koitharu.kotatsu.details.ui.pager.pages.MangaPageFetcher import org.koitharu.kotatsu.details.ui.pager.pages.MangaPageFetcher
@ -147,12 +146,10 @@ interface AppModule {
fun provideActivityLifecycleCallbacks( fun provideActivityLifecycleCallbacks(
appProtectHelper: AppProtectHelper, appProtectHelper: AppProtectHelper,
activityRecreationHandle: ActivityRecreationHandle, activityRecreationHandle: ActivityRecreationHandle,
incognitoModeIndicator: IncognitoModeIndicator,
acraScreenLogger: AcraScreenLogger, acraScreenLogger: AcraScreenLogger,
): Set<@JvmSuppressWildcards Application.ActivityLifecycleCallbacks> = arraySetOf( ): Set<@JvmSuppressWildcards Application.ActivityLifecycleCallbacks> = arraySetOf(
appProtectHelper, appProtectHelper,
activityRecreationHandle, activityRecreationHandle,
incognitoModeIndicator,
acraScreenLogger, acraScreenLogger,
) )

@ -12,6 +12,7 @@ import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.withStyledAttributes import androidx.core.content.withStyledAttributes
import androidx.core.view.isVisible
import androidx.core.view.setPadding import androidx.core.view.setPadding
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel import com.google.android.material.shape.ShapeAppearanceModel
@ -103,16 +104,22 @@ class TipView @JvmOverloads constructor(
fun setPrimaryButtonText(@StringRes resId: Int) { fun setPrimaryButtonText(@StringRes resId: Int) {
binding.buttonPrimary.setTextAndVisible(resId) binding.buttonPrimary.setTextAndVisible(resId)
updateButtonsLayout()
} }
fun setSecondaryButtonText(@StringRes resId: Int) { fun setSecondaryButtonText(@StringRes resId: Int) {
binding.buttonSecondary.setTextAndVisible(resId) binding.buttonSecondary.setTextAndVisible(resId)
updateButtonsLayout()
} }
fun setIcon(@DrawableRes resId: Int) { fun setIcon(@DrawableRes resId: Int) {
icon = ContextCompat.getDrawable(context, resId) icon = ContextCompat.getDrawable(context, resId)
} }
private fun updateButtonsLayout() {
binding.layoutButtons.isVisible = binding.buttonPrimary.isVisible || binding.buttonSecondary.isVisible
}
interface OnButtonClickListener { interface OnButtonClickListener {
fun onPrimaryButtonClick(tipView: TipView) fun onPrimaryButtonClick(tipView: TipView)

@ -1,46 +0,0 @@
package org.koitharu.kotatsu.core.util
import android.app.Activity
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.observeAsFlow
import org.koitharu.kotatsu.core.ui.DefaultActivityLifecycleCallbacks
import org.koitharu.kotatsu.core.util.ext.getThemeColor
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class IncognitoModeIndicator @Inject constructor(
private val settings: AppSettings,
) : DefaultActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
if (activity !is AppCompatActivity) {
return
}
settings.observeAsFlow(
key = AppSettings.KEY_INCOGNITO_MODE,
valueProducer = { isIncognitoModeEnabled },
).flowOn(Dispatchers.IO)
.flowWithLifecycle(activity.lifecycle)
.onEach { updateStatusBar(activity, it) }
.launchIn(activity.lifecycleScope)
}
private fun updateStatusBar(activity: AppCompatActivity, isIncognitoModeEnabled: Boolean) {
activity.window.statusBarColor = if (isIncognitoModeEnabled) {
ContextCompat.getColor(activity, R.color.status_bar_incognito)
} else {
activity.getThemeColor(android.R.attr.statusBarColor)
}
}
}

@ -35,6 +35,7 @@ import com.google.android.material.chip.Chip
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.Bookmark
@ -160,12 +161,13 @@ class DetailsActivity :
viewModel.newChaptersCount.observe(this, ::onNewChaptersChanged) viewModel.newChaptersCount.observe(this, ::onNewChaptersChanged)
viewModel.onError.observeEvent(this, DetailsErrorObserver(this, viewModel, exceptionResolver)) viewModel.onError.observeEvent(this, DetailsErrorObserver(this, viewModel, exceptionResolver))
viewModel.onActionDone.observeEvent(this, ReversibleActionObserver(viewBinding.scrollView, null)) viewModel.onActionDone.observeEvent(this, ReversibleActionObserver(viewBinding.scrollView, null))
viewModel.historyInfo.observe(this, ::onHistoryChanged) combine(viewModel.historyInfo, viewModel.isLoading, ::Pair).observe(this) {
onHistoryChanged(it.first, it.second)
}
viewModel.isLoading.observe(this, ::onLoadingStateChanged) viewModel.isLoading.observe(this, ::onLoadingStateChanged)
viewModel.scrobblingInfo.observe(this, ::onScrobblingInfoChanged) viewModel.scrobblingInfo.observe(this, ::onScrobblingInfoChanged)
viewModel.localSize.observe(this, ::onLocalSizeChanged) viewModel.localSize.observe(this, ::onLocalSizeChanged)
viewModel.relatedManga.observe(this, ::onRelatedMangaChanged) viewModel.relatedManga.observe(this, ::onRelatedMangaChanged)
// viewModel.chapters.observe(this, ::onChaptersChanged)
viewModel.readingTime.observe(this, ::onReadingTimeChanged) viewModel.readingTime.observe(this, ::onReadingTimeChanged)
viewModel.selectedBranch.observe(this) { viewModel.selectedBranch.observe(this) {
viewBinding.infoLayout.chipBranch.text = it.ifNullOrEmpty { getString(R.string.system_default) } viewBinding.infoLayout.chipBranch.text = it.ifNullOrEmpty { getString(R.string.system_default) }
@ -197,9 +199,7 @@ class DetailsActivity :
when (v.id) { when (v.id) {
R.id.button_read -> openReader(isIncognitoMode = false) R.id.button_read -> openReader(isIncognitoMode = false)
R.id.chip_branch -> showBranchPopupMenu(v) R.id.chip_branch -> showBranchPopupMenu(v)
R.id.button_chapters -> { R.id.button_chapters -> ChaptersPagesSheet.show(supportFragmentManager)
ChaptersPagesSheet.show(supportFragmentManager)
}
R.id.chip_author -> { R.id.chip_author -> {
val manga = viewModel.manga.value ?: return val manga = viewModel.manga.value ?: return
@ -342,10 +342,6 @@ class DetailsActivity :
} }
} }
private fun onChaptersChanged(chapters: List<ChapterListItem>?) {
// TODO
}
private fun onFavoritesChanged(categories: Set<FavouriteCategory>) { private fun onFavoritesChanged(categories: Set<FavouriteCategory>) {
val chip = viewBinding.infoLayout.chipFavorite val chip = viewBinding.infoLayout.chipFavorite
chip.setChipIconResource(if (categories.isEmpty()) R.drawable.ic_heart_outline else R.drawable.ic_heart) chip.setChipIconResource(if (categories.isEmpty()) R.drawable.ic_heart_outline else R.drawable.ic_heart)
@ -449,7 +445,6 @@ class DetailsActivity :
private fun onMangaUpdated(details: MangaDetails) { private fun onMangaUpdated(details: MangaDetails) {
with(viewBinding) { with(viewBinding) {
val manga = details.toManga() val manga = details.toManga()
val hasChapters = !manga.chapters.isNullOrEmpty()
// Main // Main
loadCover(manga) loadCover(manga)
textViewTitle.text = manga.title textViewTitle.text = manga.title
@ -500,9 +495,7 @@ class DetailsActivity :
.enqueueWith(coil) .enqueueWith(coil)
} }
buttonChapters?.isEnabled = hasChapters
title = manga.title title = manga.title
buttonRead.isEnabled = hasChapters
invalidateOptionsMenu() invalidateOptionsMenu()
} }
} }
@ -531,30 +524,18 @@ class DetailsActivity :
) )
} }
private fun onHistoryChanged(info: HistoryInfo) { private fun onHistoryChanged(info: HistoryInfo, isLoading: Boolean) = with(viewBinding) {
with(viewBinding.buttonRead) { buttonRead.setTitle(if (info.history != null) R.string._continue else R.string.read)
if (info.history != null) { buttonRead.subtitle = when {
setTitle(R.string._continue) isLoading -> getString(R.string.loading_)
} else { info.isIncognitoMode -> getString(R.string.incognito_mode)
setTitle(R.string.read) info.currentChapter >= 0 -> getString(R.string.chapter_d_of_d, info.currentChapter + 1, info.totalChapters)
}
}
viewBinding.buttonRead.subtitle = when {
!info.isValid -> getString(R.string.loading_)
info.currentChapter >= 0 -> getString(
R.string.chapter_d_of_d,
info.currentChapter + 1,
info.totalChapters,
)
info.totalChapters == 0 -> getString(R.string.no_chapters) info.totalChapters == 0 -> getString(R.string.no_chapters)
else -> resources.getQuantityString( else -> resources.getQuantityString(R.plurals.chapters, info.totalChapters, info.totalChapters)
R.plurals.chapters,
info.totalChapters,
info.totalChapters,
)
} }
viewBinding.buttonRead.setProgress(info.history?.percent?.coerceIn(0f, 1f) ?: 0f, true) buttonRead.setProgress(info.history?.percent?.coerceIn(0f, 1f) ?: 0f, true)
buttonChapters?.isEnabled = info.isValid
buttonRead.isEnabled = info.isValid
} }
private fun onNewChaptersChanged(count: Int) { private fun onNewChaptersChanged(count: Int) {

@ -35,6 +35,7 @@ import org.koitharu.kotatsu.list.ui.model.EmptyState
import org.koitharu.kotatsu.list.ui.model.ListHeader import org.koitharu.kotatsu.list.ui.model.ListHeader
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.LoadingState
import org.koitharu.kotatsu.list.ui.model.TipModel
import org.koitharu.kotatsu.list.ui.model.toErrorState import org.koitharu.kotatsu.list.ui.model.toErrorState
import org.koitharu.kotatsu.list.ui.model.toGridModel import org.koitharu.kotatsu.list.ui.model.toGridModel
import org.koitharu.kotatsu.list.ui.model.toListDetailedModel import org.koitharu.kotatsu.list.ui.model.toListDetailedModel
@ -82,7 +83,8 @@ class HistoryListViewModel @Inject constructor(
isGroupingEnabled, isGroupingEnabled,
listMode, listMode,
networkState, networkState,
) { list, grouped, mode, online -> settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled },
) { list, grouped, mode, online, incognito ->
when { when {
list.isEmpty() -> listOf( list.isEmpty() -> listOf(
EmptyState( EmptyState(
@ -93,7 +95,7 @@ class HistoryListViewModel @Inject constructor(
), ),
) )
else -> mapList(list, grouped, mode, online) else -> mapList(list, grouped, mode, online, incognito)
} }
}.onStart { }.onStart {
loadingCounter.increment() loadingCounter.increment()
@ -141,8 +143,19 @@ class HistoryListViewModel @Inject constructor(
grouped: Boolean, grouped: Boolean,
mode: ListMode, mode: ListMode,
isOnline: Boolean, isOnline: Boolean,
isIncognito: Boolean,
): List<ListModel> { ): List<ListModel> {
val result = ArrayList<ListModel>(if (grouped) (list.size * 1.4).toInt() else list.size + 1) val result = ArrayList<ListModel>(if (grouped) (list.size * 1.4).toInt() else list.size + 2)
if (isIncognito) {
result += TipModel(
key = AppSettings.KEY_INCOGNITO_MODE,
title = R.string.incognito_mode,
text = R.string.incognito_mode_hint,
icon = R.drawable.ic_incognito,
primaryButtonText = 0,
secondaryButtonText = 0,
)
}
val order = sortOrder.value val order = sortOrder.value
var prevHeader: ListHeader? = null var prevHeader: ListHeader? = null
if (!isOnline) { if (!isOnline) {

@ -131,38 +131,21 @@ class PreviewFragment : BaseFragment<FragmentPreviewBinding>(), View.OnClickList
private fun onFooterUpdated(footer: PreviewViewModel.FooterInfo?) { private fun onFooterUpdated(footer: PreviewViewModel.FooterInfo?) {
with(requireViewBinding()) { with(requireViewBinding()) {
toolbarBottom.isVisible = footer != null buttonRead.isEnabled = footer != null
if (footer == null) { buttonRead.setTitle(if (footer?.isInProgress() == true) R.string._continue else R.string.read)
return buttonRead.subtitle = when {
} footer == null -> getString(R.string.loading_)
toolbarBottom.title = when { footer.isIncognito -> getString(R.string.incognito_mode)
footer.isInProgress() -> { footer.currentChapter >= 0 -> getString(
getString(R.string.chapter_d_of_d, footer.currentChapter, footer.totalChapters) R.string.chapter_d_of_d,
} footer.currentChapter + 1,
footer.totalChapters,
footer.totalChapters > 0 -> { )
resources.getQuantityString(R.plurals.chapters, footer.totalChapters, footer.totalChapters)
} footer.totalChapters == 0 -> getString(R.string.no_chapters)
else -> resources.getQuantityString(R.plurals.chapters, footer.totalChapters, footer.totalChapters)
else -> {
getString(R.string.no_chapters)
}
} }
buttonRead.isEnabled = footer.totalChapters > 0 buttonRead.setProgress(footer?.percent?.coerceIn(0f, 1f) ?: 0f, true)
buttonRead.setIconResource(
when {
footer.isIncognito -> R.drawable.ic_incognito
footer.isInProgress() -> R.drawable.ic_play
else -> R.drawable.ic_read
},
)
buttonRead.setText(
if (footer.isInProgress()) {
R.string._continue
} else {
R.string.read
},
)
} }
} }

@ -29,6 +29,7 @@ import org.koitharu.kotatsu.core.ui.widgets.ChipsView
import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.core.util.ext.require
import org.koitharu.kotatsu.core.util.ext.sanitize import org.koitharu.kotatsu.core.util.ext.sanitize
import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.history.data.HistoryRepository
import org.koitharu.kotatsu.history.data.PROGRESS_NONE
import org.koitharu.kotatsu.list.domain.ListExtraProvider import org.koitharu.kotatsu.list.domain.ListExtraProvider
import javax.inject.Inject import javax.inject.Inject
@ -56,7 +57,7 @@ class PreviewViewModel @Inject constructor(
val b = m.getPreferredBranch(history) val b = m.getPreferredBranch(history)
val chapters = m.getChapters(b).orEmpty() val chapters = m.getChapters(b).orEmpty()
FooterInfo( FooterInfo(
branch = b, percent = history?.percent ?: PROGRESS_NONE,
currentChapter = history?.chapterId?.let { currentChapter = history?.chapterId?.let {
chapters.indexOfFirst { x -> x.id == it } chapters.indexOfFirst { x -> x.id == it }
} ?: -1, } ?: -1,
@ -109,10 +110,10 @@ class PreviewViewModel @Inject constructor(
} }
data class FooterInfo( data class FooterInfo(
val branch: String?,
val currentChapter: Int, val currentChapter: Int,
val totalChapters: Int, val totalChapters: Int,
val isIncognito: Boolean, val isIncognito: Boolean,
val percent: Float,
) { ) {
fun isInProgress() = currentChapter >= 0 fun isInProgress() = currentChapter >= 0

@ -130,9 +130,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
viewModel.onFirstStart.observeEvent(this) { viewModel.onFirstStart.observeEvent(this) {
WelcomeSheet.show(supportFragmentManager) WelcomeSheet.show(supportFragmentManager)
} }
viewModel.isIncognitoMode.observe(this) {
adjustSearchUI(isSearchOpened(), false)
}
searchSuggestionViewModel.isIncognitoModeEnabled.observe(this, this::onIncognitoModeChanged) searchSuggestionViewModel.isIncognitoModeEnabled.observe(this, this::onIncognitoModeChanged)
} }
@ -368,10 +365,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
adjustFabVisibility(isSearchOpened = isOpened) adjustFabVisibility(isSearchOpened = isOpened)
supportActionBar?.apply { supportActionBar?.apply {
setHomeAsUpIndicator( setHomeAsUpIndicator(
when { if (isOpened) {
isOpened -> materialR.drawable.abc_ic_ab_back_material materialR.drawable.abc_ic_ab_back_material
viewModel.isIncognitoMode.value -> R.drawable.ic_incognito } else {
else -> materialR.drawable.abc_ic_search_api_material materialR.drawable.abc_ic_search_api_material
}, },
) )
setHomeActionContentDescription( setHomeActionContentDescription(

@ -9,7 +9,6 @@ import kotlinx.coroutines.plus
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
import org.koitharu.kotatsu.core.github.AppUpdateRepository import org.koitharu.kotatsu.core.github.AppUpdateRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.observeAsStateFlow
import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.call
@ -39,12 +38,6 @@ class MainViewModel @Inject constructor(
initialValue = false, initialValue = false,
) )
val isIncognitoMode = settings.observeAsStateFlow(
scope = viewModelScope + Dispatchers.Default,
key = AppSettings.KEY_INCOGNITO_MODE,
valueProducer = { isIncognitoModeEnabled },
)
val appUpdate = appUpdateRepository.observeAvailableUpdate() val appUpdate = appUpdateRepository.observeAvailableUpdate()
val feedCounter = trackingRepository.observeUpdatedMangaCount() val feedCounter = trackingRepository.observeUpdatedMangaCount()

@ -182,7 +182,6 @@
android:gravity="center" android:gravity="center"
android:paddingHorizontal="6dp" android:paddingHorizontal="6dp"
android:paddingVertical="8dp" android:paddingVertical="8dp"
android:textColor="?colorOnPrimaryContainer"
app:baseColor="?colorSecondaryContainer" app:baseColor="?colorSecondaryContainer"
app:layout_constraintEnd_toStartOf="@id/button_chapters" app:layout_constraintEnd_toStartOf="@id/button_chapters"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

@ -22,7 +22,7 @@
android:contentDescription="@string/back" android:contentDescription="@string/back"
android:elevation="@dimen/m3_sys_elevation_level1" android:elevation="@dimen/m3_sys_elevation_level1"
android:scaleType="center" android:scaleType="center"
android:src="?homeAsUpIndicator" /> app:srcCompat="?homeAsUpIndicator" />
<com.google.android.material.progressindicator.CircularProgressIndicator <com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar" android:id="@+id/progressBar"

@ -1,197 +1,194 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout <ScrollView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/scrollView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
tools:background="@macro/m3_comp_filled_card_container_color">
<ScrollView <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/scrollView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:scrollIndicators="bottom"> android:paddingBottom="?actionBarSize">
<androidx.constraintlayout.widget.ConstraintLayout <com.google.android.material.imageview.ShapeableImageView
android:layout_width="match_parent" android:id="@+id/imageView_cover"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:background="?colorSecondaryContainer"
android:foreground="?selectableItemBackground"
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="H,13:18"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.3"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Cover"
tools:background="@tools:sample/backgrounds/scenic[5]"
tools:ignore="ContentDescription,UnusedAttribute" />
<TextView
android:id="@+id/textView_title"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingBottom="?actionBarSize"> android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
<com.google.android.material.imageview.ShapeableImageView android:ellipsize="end"
android:id="@+id/imageView_cover" android:maxLines="5"
android:layout_width="0dp" android:textAppearance="?attr/textAppearanceHeadlineSmall"
android:layout_height="0dp" app:layout_constraintEnd_toStartOf="@id/button_open"
android:layout_marginStart="16dp" app:layout_constraintStart_toEndOf="@id/imageView_cover"
android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent"
android:background="?colorSecondaryContainer" app:layout_goneMarginEnd="16dp"
android:foreground="?selectableItemBackground" tools:text="@tools:sample/lorem" />
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="H,13:18" <ImageButton
app:layout_constraintEnd_toEndOf="parent" android:id="@+id/button_close"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.3"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Cover"
tools:background="@tools:sample/backgrounds/scenic[5]"
tools:ignore="ContentDescription,UnusedAttribute" />
<TextView
android:id="@+id/textView_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:maxLines="5"
android:textAppearance="?attr/textAppearanceHeadlineSmall"
app:layout_constraintEnd_toStartOf="@id/button_open"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toTopOf="parent"
app:layout_goneMarginEnd="16dp"
tools:text="@tools:sample/lorem" />
<ImageButton
android:id="@+id/button_open"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/details"
android:padding="12dp"
app:layout_constraintEnd_toStartOf="@id/button_close"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_expand" />
<ImageButton
android:id="@+id/button_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginEnd="4dp"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/close"
android:padding="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="?actionModeCloseDrawable"
app:tint="?colorControlNormal" />
<TextView
android:id="@+id/textView_subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:maxLines="3"
android:textAppearance="?attr/textAppearanceBodyMedium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_title"
tools:text="@tools:sample/lorem[12]" />
<TextView
android:id="@+id/textView_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:background="@drawable/list_selector"
android:padding="2dp"
android:singleLine="true"
android:textColor="?attr/colorTertiary"
android:textStyle="bold"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_subtitle"
tools:text="@tools:sample/full_names" />
<RatingBar
android:id="@+id/rating_bar"
style="?ratingBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:isIndicator="true"
android:max="1"
android:numStars="5"
android:stepSize="0.5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_author"
tools:rating="4" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:barrierMargin="8dp"
app:constraint_referenced_ids="imageView_cover,rating_bar" />
<org.koitharu.kotatsu.core.ui.widgets.ChipsView
android:id="@+id/chips_tags"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
app:chipSpacingHorizontal="6dp"
app:chipSpacingVertical="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/barrier_header" />
<org.koitharu.kotatsu.core.ui.widgets.SelectableTextView
android:id="@+id/textView_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_normal"
android:layout_marginTop="@dimen/margin_small"
android:layout_marginEnd="@dimen/margin_normal"
android:lineSpacingMultiplier="1.2"
android:paddingBottom="@dimen/margin_normal"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/chips_tags"
tools:ignore="UnusedAttribute"
tools:text="@tools:sample/lorem/random" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?colorBackgroundFloating">
<com.google.android.material.button.MaterialButton
android:id="@+id/button_read"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical" android:layout_marginTop="4dp"
android:layout_marginHorizontal="@dimen/toolbar_button_margin" android:layout_marginEnd="4dp"
android:enabled="false" android:background="?selectableItemBackgroundBorderless"
android:text="@string/read" android:contentDescription="@string/close"
android:textAllCaps="false" android:padding="12dp"
app:iconGravity="textStart" app:layout_constraintEnd_toEndOf="parent"
app:iconPadding="8dp" app:layout_constraintTop_toTopOf="parent"
tools:enabled="true" app:srcCompat="?actionModeCloseDrawable"
tools:icon="@drawable/ic_read" /> app:tint="?colorControlNormal" />
</com.google.android.material.appbar.MaterialToolbar> <TextView
android:id="@+id/textView_subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:maxLines="3"
android:textAppearance="?attr/textAppearanceBodyMedium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_title"
tools:text="@tools:sample/lorem[12]" />
<TextView
android:id="@+id/textView_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:background="@drawable/custom_selectable_item_background"
android:padding="2dp"
android:singleLine="true"
android:textColor="?attr/colorTertiary"
android:textStyle="bold"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_subtitle"
tools:text="@tools:sample/full_names" />
<RatingBar
android:id="@+id/rating_bar"
style="?ratingBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:isIndicator="true"
android:max="1"
android:numStars="5"
android:stepSize="0.5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/imageView_cover"
app:layout_constraintTop_toBottomOf="@id/textView_author"
tools:rating="4" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:barrierMargin="8dp"
app:constraint_referenced_ids="imageView_cover,rating_bar" />
</FrameLayout> <org.koitharu.kotatsu.core.ui.widgets.ProgressButton
android:id="@+id/button_read"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="@dimen/margin_normal"
android:layout_marginEnd="12dp"
android:foreground="?selectableItemBackground"
android:gravity="center"
android:paddingHorizontal="6dp"
android:paddingVertical="8dp"
app:baseColor="@color/m3_chip_background_color"
app:layout_constraintEnd_toStartOf="@id/button_open"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/barrier_header"
app:progressColor="?colorControlNormal"
app:subtitleTextAppearance="?textAppearanceBodySmall"
app:titleTextAppearance="?textAppearanceButton"
tools:max="100"
tools:progress="40"
tools:subtitle="12 chapters"
tools:title="@string/read" />
<ImageView
android:id="@+id/button_open"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="16dp"
android:background="@drawable/bg_circle_button"
android:backgroundTint="@color/m3_chip_background_color"
android:contentDescription="@string/details"
android:scaleType="centerInside"
app:layout_constraintBottom_toBottomOf="@id/button_read"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/button_read"
app:srcCompat="@drawable/ic_expand" />
<org.koitharu.kotatsu.core.ui.widgets.ChipsView
android:id="@+id/chips_tags"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_normal"
android:paddingStart="@dimen/screen_padding"
android:paddingEnd="@dimen/screen_padding"
app:chipSpacingHorizontal="6dp"
app:chipSpacingVertical="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_read" />
<org.koitharu.kotatsu.core.ui.widgets.SelectableTextView
android:id="@+id/textView_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_normal"
android:layout_marginTop="@dimen/margin_small"
android:layout_marginEnd="@dimen/margin_normal"
android:lineSpacingMultiplier="1.2"
android:paddingBottom="@dimen/margin_normal"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/chips_tags"
tools:ignore="UnusedAttribute"
tools:text="@tools:sample/lorem/random" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

@ -30,6 +30,7 @@
tools:text="Включите их, чтобы ничего не пропускать. Откройте настройки системы и разрешите их отправку." /> tools:text="Включите их, чтобы ничего не пропускать. Откройте настройки системы и разрешите их отправку." />
<LinearLayout <LinearLayout
android:id="@+id/layout_buttons"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"

Loading…
Cancel
Save