This commit is contained in:
rebelonion 2024-04-04 04:49:08 -05:00
commit 7688ffa39f
11 changed files with 644 additions and 656 deletions

View file

@ -92,6 +92,7 @@ import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.BuildConfig.APPLICATION_ID import ani.dantotsu.BuildConfig.APPLICATION_ID
import ani.dantotsu.connections.anilist.Genre import ani.dantotsu.connections.anilist.Genre
import ani.dantotsu.connections.anilist.api.FuzzyDate import ani.dantotsu.connections.anilist.api.FuzzyDate
import ani.dantotsu.connections.bakaupdates.MangaUpdates
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
import ani.dantotsu.databinding.ItemCountDownBinding import ani.dantotsu.databinding.ItemCountDownBinding
import ani.dantotsu.media.Media import ani.dantotsu.media.Media
@ -102,6 +103,7 @@ import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.settings.saving.internal.PreferenceKeystore import ani.dantotsu.settings.saving.internal.PreferenceKeystore
import ani.dantotsu.settings.saving.internal.PreferenceKeystore.Companion.generateSalt import ani.dantotsu.settings.saving.internal.PreferenceKeystore.Companion.generateSalt
import ani.dantotsu.util.CountUpTimer
import ani.dantotsu.util.Logger import ani.dantotsu.util.Logger
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.RequestBuilder import com.bumptech.glide.RequestBuilder
@ -134,9 +136,12 @@ import io.noties.markwon.html.TagHandlerNoOp
import io.noties.markwon.image.AsyncDrawable import io.noties.markwon.image.AsyncDrawable
import io.noties.markwon.image.glide.GlideImagesPlugin import io.noties.markwon.image.glide.GlideImagesPlugin
import jp.wasabeef.glide.transformations.BlurTransformation import jp.wasabeef.glide.transformations.BlurTransformation
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import nl.joery.animatedbottombar.AnimatedBottomBar import nl.joery.animatedbottombar.AnimatedBottomBar
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -985,6 +990,54 @@ fun countDown(media: Media, view: ViewGroup) {
} }
} }
fun sinceWhen(media: Media, view: ViewGroup) {
CoroutineScope(Dispatchers.IO).launch {
MangaUpdates().search(media.name ?: media.nameRomaji, media.startDate)?.let {
val latestChapter = it.metadata.series.latestChapter ?: it.record.chapter?.let { chapter ->
if (chapter.contains("-"))
chapter.split("-")[1].trim()
else
chapter
}?.toInt()
val timeSince = (System.currentTimeMillis() -
(it.metadata.series.lastUpdated!!.timestamp * 1000)) / 1000
withContext(Dispatchers.Main) {
val v =
ItemCountDownBinding.inflate(LayoutInflater.from(view.context), view, false)
view.addView(v.root, 0)
v.mediaCountdownText.text =
currActivity()?.getString(R.string.chapter_release_timeout, latestChapter)
object : CountUpTimer(86400000) {
override fun onTick(second: Int) {
val a = second + timeSince
v.mediaCountdown.text = currActivity()?.getString(
R.string.time_format,
a / 86400,
a % 86400 / 3600,
a % 86400 % 3600 / 60,
a % 86400 % 3600 % 60
)
}
override fun onFinish() {
// The legend will never die.
}
}.start()
}
}
}
}
fun displayTimer(media: Media, view: ViewGroup) {
when {
media.anime != null -> countDown(media, view)
media.format == "MANGA" || media.format == "ONE_SHOT" -> sinceWhen(media, view)
else -> { } // No timer yet
}
}
fun MutableMap<String, Genre>.checkId(id: Int): Boolean { fun MutableMap<String, Genre>.checkId(id: Int): Boolean {
this.forEach { this.forEach {
if (it.value.id == id) { if (it.value.id == id) {

View file

@ -0,0 +1,98 @@
package ani.dantotsu.connections.bakaupdates
import ani.dantotsu.client
import ani.dantotsu.connections.anilist.api.FuzzyDate
import ani.dantotsu.tryWithSuspend
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import okio.ByteString.Companion.encode
import org.json.JSONException
import org.json.JSONObject
import java.nio.charset.Charset
class MangaUpdates {
private val Int?.dateFormat get() = String.format("%02d", this)
private val apiUrl = "https://api.mangaupdates.com/v1/releases/search"
suspend fun search(title: String, startDate: FuzzyDate?) : MangaUpdatesResponse.Results? {
return tryWithSuspend {
val query = JSONObject().apply {
try {
put("search", title.encode(Charset.forName("UTF-8")))
startDate?.let {
put(
"start_date",
"${it.year}-${it.month.dateFormat}-${it.day.dateFormat}"
)
}
put("include_metadata", true)
} catch (e: JSONException) {
e.printStackTrace()
}
}
val res = client.post(apiUrl, json = query).parsed<MangaUpdatesResponse>()
res.results?.forEach{ println("MangaUpdates: $it") }
res.results?.first { it.metadata.series.lastUpdated?.timestamp != null }
}
}
@Serializable
data class MangaUpdatesResponse(
@SerialName("total_hits")
val totalHits: Int?,
@SerialName("page")
val page: Int?,
@SerialName("per_page")
val perPage: Int?,
val results: List<Results>? = null
) {
@Serializable
data class Results(
val record: Record,
val metadata: MetaData
) {
@Serializable
data class Record(
@SerialName("id")
val id: Int,
@SerialName("title")
val title: String,
@SerialName("volume")
val volume: String?,
@SerialName("chapter")
val chapter: String?,
@SerialName("release_date")
val releaseDate: String
)
@Serializable
data class MetaData(
val series: Series
) {
@Serializable
data class Series(
@SerialName("series_id")
val seriesId: Long?,
@SerialName("title")
val title: String?,
@SerialName("latest_chapter")
val latestChapter: Int?,
@SerialName("last_updated")
val lastUpdated: LastUpdated?
) {
@Serializable
data class LastUpdated(
@SerialName("timestamp")
val timestamp: Long,
@SerialName("as_rfc3339")
val asRfc3339: String,
@SerialName("as_string")
val asString: String
)
}
}
}
}
}

View file

@ -27,7 +27,6 @@ import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.GenresViewModel import ani.dantotsu.connections.anilist.GenresViewModel
import ani.dantotsu.copyToClipboard import ani.dantotsu.copyToClipboard
import ani.dantotsu.countDown
import ani.dantotsu.currActivity import ani.dantotsu.currActivity
import ani.dantotsu.databinding.ActivityGenreBinding import ani.dantotsu.databinding.ActivityGenreBinding
import ani.dantotsu.databinding.FragmentMediaInfoBinding import ani.dantotsu.databinding.FragmentMediaInfoBinding
@ -38,6 +37,7 @@ import ani.dantotsu.databinding.ItemTitleRecyclerBinding
import ani.dantotsu.databinding.ItemTitleSearchBinding import ani.dantotsu.databinding.ItemTitleSearchBinding
import ani.dantotsu.databinding.ItemTitleTextBinding import ani.dantotsu.databinding.ItemTitleTextBinding
import ani.dantotsu.databinding.ItemTitleTrailerBinding import ani.dantotsu.databinding.ItemTitleTrailerBinding
import ani.dantotsu.displayTimer
import ani.dantotsu.loadImage import ani.dantotsu.loadImage
import ani.dantotsu.navBarHeight import ani.dantotsu.navBarHeight
import ani.dantotsu.px import ani.dantotsu.px
@ -225,8 +225,7 @@ class MediaInfoFragment : Fragment() {
.setDuration(400).start() .setDuration(400).start()
} }
} }
displayTimer(media, binding.mediaInfoContainer)
countDown(media, binding.mediaInfoContainer)
val parent = _binding?.mediaInfoContainer!! val parent = _binding?.mediaInfoContainer!!
val screenWidth = resources.displayMetrics.run { widthPixels / density } val screenWidth = resources.displayMetrics.run { widthPixels / density }

View file

@ -17,11 +17,11 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.FileUrl import ani.dantotsu.FileUrl
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.countDown
import ani.dantotsu.currActivity import ani.dantotsu.currActivity
import ani.dantotsu.databinding.DialogLayoutBinding import ani.dantotsu.databinding.DialogLayoutBinding
import ani.dantotsu.databinding.ItemAnimeWatchBinding import ani.dantotsu.databinding.ItemAnimeWatchBinding
import ani.dantotsu.databinding.ItemChipBinding import ani.dantotsu.databinding.ItemChipBinding
import ani.dantotsu.displayTimer
import ani.dantotsu.isOnline import ani.dantotsu.isOnline
import ani.dantotsu.loadImage import ani.dantotsu.loadImage
import ani.dantotsu.media.Media import ani.dantotsu.media.Media
@ -500,8 +500,7 @@ class AnimeWatchAdapter(
inner class ViewHolder(val binding: ItemAnimeWatchBinding) : inner class ViewHolder(val binding: ItemAnimeWatchBinding) :
RecyclerView.ViewHolder(binding.root) { RecyclerView.ViewHolder(binding.root) {
init { init {
//Timer displayTimer(media, binding.animeSourceContainer)
countDown(media, binding.animeSourceContainer)
} }
} }
} }

View file

@ -6,7 +6,6 @@ import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.PopupMenu import android.widget.PopupMenu
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@ -23,6 +22,7 @@ import ani.dantotsu.blurImage
import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.api.Query import ani.dantotsu.connections.anilist.api.Query
import ani.dantotsu.databinding.ActivityProfileBinding import ani.dantotsu.databinding.ActivityProfileBinding
import ani.dantotsu.databinding.ItemProfileAppBarBinding
import ani.dantotsu.initActivity import ani.dantotsu.initActivity
import ani.dantotsu.loadImage import ani.dantotsu.loadImage
import ani.dantotsu.media.user.ListActivity import ani.dantotsu.media.user.ListActivity
@ -46,6 +46,7 @@ import kotlin.math.abs
class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListener { class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListener {
lateinit var binding: ActivityProfileBinding lateinit var binding: ActivityProfileBinding
private lateinit var bindingProfileAppBar: ItemProfileAppBarBinding
private var selected: Int = 0 private var selected: Int = 0
lateinit var navBar: AnimatedBottomBar lateinit var navBar: AnimatedBottomBar
@ -109,147 +110,165 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
binding.profileViewPager.setCurrentItem(selected, true) binding.profileViewPager.setCurrentItem(selected, true)
} }
}) })
val userLevel = intent.getStringExtra("userLVL") ?: ""
binding.followButton.isGone = user.id == Anilist.userid || Anilist.userid == null bindingProfileAppBar = ItemProfileAppBarBinding.bind(binding.root).apply {
binding.followButton.text = getString(
when { val userLevel = intent.getStringExtra("userLVL") ?: ""
user.isFollowing -> R.string.unfollow followButton.isGone =
user.isFollower -> R.string.follows_you user.id == Anilist.userid || Anilist.userid == null
else -> R.string.follow followButton.text = getString(
} when {
) user.isFollowing -> R.string.unfollow
if (user.isFollowing && user.isFollower) binding.followButton.text = getString(R.string.mutual) user.isFollower -> R.string.follows_you
binding.followButton.setOnClickListener { else -> R.string.follow
lifecycleScope.launch(Dispatchers.IO) { }
val res = Anilist.query.toggleFollow(user.id) )
if (res?.data?.toggleFollow != null) { if (user.isFollowing && user.isFollower) followButton.text =
withContext(Dispatchers.Main) { getString(R.string.mutual)
snackString(R.string.success) followButton.setOnClickListener {
user.isFollowing = res.data.toggleFollow.isFollowing lifecycleScope.launch(Dispatchers.IO) {
binding.followButton.text = getString( val res = Anilist.query.toggleFollow(user.id)
when { if (res?.data?.toggleFollow != null) {
user.isFollowing -> R.string.unfollow withContext(Dispatchers.Main) {
user.isFollower -> R.string.follows_you snackString(R.string.success)
else -> R.string.follow user.isFollowing = res.data.toggleFollow.isFollowing
} followButton.text = getString(
) when {
if (user.isFollowing && user.isFollower) user.isFollowing -> R.string.unfollow
binding.followButton.text = getString(R.string.mutual) user.isFollower -> R.string.follows_you
else -> R.string.follow
}
)
if (user.isFollowing && user.isFollower)
followButton.text = getString(R.string.mutual)
}
} }
} }
} }
} binding.profileProgressBar.visibility = View.GONE
binding.profileProgressBar.visibility = View.GONE profileAppBar.visibility = View.VISIBLE
binding.profileAppBar.visibility = View.VISIBLE profileMenuButton.setOnClickListener {
binding.profileMenuButton.setOnClickListener { val popup = PopupMenu(this@ProfileActivity, profileMenuButton)
val popup = PopupMenu(this@ProfileActivity, binding.profileMenuButton) popup.menuInflater.inflate(R.menu.menu_profile, popup.menu)
popup.menuInflater.inflate(R.menu.menu_profile, popup.menu) popup.setOnMenuItemClickListener { item ->
popup.setOnMenuItemClickListener { item -> when (item.itemId) {
when (item.itemId) { R.id.action_view_following -> {
R.id.action_view_following -> { ContextCompat.startActivity(
ContextCompat.startActivity( this@ProfileActivity,
this@ProfileActivity, Intent(this@ProfileActivity, FollowActivity::class.java)
Intent(this@ProfileActivity, FollowActivity::class.java) .putExtra("title", "Following")
.putExtra("title", "Following") .putExtra("userId", user.id),
.putExtra("userId", user.id), null
null )
) true
true }
}
R.id.action_view_followers -> { R.id.action_view_followers -> {
ContextCompat.startActivity( ContextCompat.startActivity(
this@ProfileActivity, this@ProfileActivity,
Intent(this@ProfileActivity, FollowActivity::class.java) Intent(this@ProfileActivity, FollowActivity::class.java)
.putExtra("title", "Followers") .putExtra("title", "Followers")
.putExtra("userId", user.id), .putExtra("userId", user.id),
null null
) )
true true
} }
R.id.action_view_on_anilist -> { R.id.action_view_on_anilist -> {
openLinkInBrowser("https://anilist.co/user/${user.name}") openLinkInBrowser("https://anilist.co/user/${user.name}")
true true
} }
else -> false else -> false
}
} }
popup.show()
} }
popup.show()
}
binding.profileUserAvatar.loadImage(user.avatar?.medium) profileUserAvatar.loadImage(user.avatar?.medium)
binding.profileUserAvatar.setOnLongClickListener { profileUserAvatar.setOnLongClickListener {
ImageViewDialog.newInstance( ImageViewDialog.newInstance(
this@ProfileActivity, this@ProfileActivity,
"${user.name}'s [Avatar]", "${user.name}'s [Avatar]",
user.avatar?.medium user.avatar?.medium
)
}
val userLevelText = "${user.name} $userLevel"
profileUserName.text = userLevelText
val bannerAnimations: Boolean = PrefManager.getVal(PrefName.BannerAnimations)
blurImage(
if (bannerAnimations) profileBannerImage else profileBannerImageNoKen,
user.bannerImage ?: user.avatar?.medium
) )
} profileBannerImage.updateLayoutParams { height += statusBarHeight }
profileBannerImageNoKen.updateLayoutParams { height += statusBarHeight }
profileBannerGradient.updateLayoutParams { height += statusBarHeight }
profileCloseButton.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
profileMenuButton.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
profileButtonContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
profileBannerImage.setOnLongClickListener {
ImageViewDialog.newInstance(
this@ProfileActivity,
user.name + " [Banner]",
user.bannerImage
)
}
val userLevelText = "${user.name} $userLevel" mMaxScrollSize = profileAppBar.totalScrollRange
binding.profileUserName.text = userLevelText profileAppBar.addOnOffsetChangedListener(this@ProfileActivity)
val bannerAnimations: Boolean = PrefManager.getVal(PrefName.BannerAnimations)
blurImage(if (bannerAnimations) binding.profileBannerImage else binding.profileBannerImageNoKen as ImageView, user.bannerImage ?: user.avatar?.medium)
binding.profileBannerImage.updateLayoutParams { height += statusBarHeight }
binding.profileBannerImageNoKen?.updateLayoutParams { height += statusBarHeight }
binding.profileBannerGradient.updateLayoutParams { height += statusBarHeight }
binding.profileMenuButton.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
binding.profileButtonContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
binding.profileBannerImage.setOnLongClickListener {
ImageViewDialog.newInstance(
this@ProfileActivity,
user.name + " [Banner]",
user.bannerImage
)
}
mMaxScrollSize = binding.profileAppBar.totalScrollRange
binding.profileAppBar.addOnOffsetChangedListener(this@ProfileActivity)
binding.profileFollowerCount.text = followers.toString() profileFollowerCount.text = followers.toString()
binding.profileFollowerCountContainer.setOnClickListener { profileFollowerCountContainer.setOnClickListener {
ContextCompat.startActivity( ContextCompat.startActivity(
this@ProfileActivity, this@ProfileActivity,
Intent(this@ProfileActivity, FollowActivity::class.java) Intent(this@ProfileActivity, FollowActivity::class.java)
.putExtra("title", getString(R.string.followers)) .putExtra("title", getString(R.string.followers))
.putExtra("userId", user.id), .putExtra("userId", user.id),
null null
) )
} }
binding.profileFollowingCount.text = following.toString() profileFollowingCount.text = following.toString()
binding.profileFollowingCountContainer.setOnClickListener { profileFollowingCountContainer.setOnClickListener {
ContextCompat.startActivity( ContextCompat.startActivity(
this@ProfileActivity, this@ProfileActivity,
Intent(this@ProfileActivity, FollowActivity::class.java) Intent(this@ProfileActivity, FollowActivity::class.java)
.putExtra("title", "Following") .putExtra("title", "Following")
.putExtra("userId", user.id), .putExtra("userId", user.id),
null null
) )
} }
binding.profileAnimeCount.text = user.statistics.anime.count.toString() profileAnimeCount.text = user.statistics.anime.count.toString()
binding.profileAnimeCountContainer.setOnClickListener { profileAnimeCountContainer.setOnClickListener {
ContextCompat.startActivity( ContextCompat.startActivity(
this@ProfileActivity, Intent(this@ProfileActivity, ListActivity::class.java) this@ProfileActivity,
.putExtra("anime", true) Intent(this@ProfileActivity, ListActivity::class.java)
.putExtra("userId", user.id) .putExtra("anime", true)
.putExtra("username", user.name), null .putExtra("userId", user.id)
) .putExtra("username", user.name),
} null
)
}
binding.profileMangaCount.text = user.statistics.manga.count.toString() profileMangaCount.text = user.statistics.manga.count.toString()
binding.profileMangaCountContainer.setOnClickListener { profileMangaCountContainer.setOnClickListener {
ContextCompat.startActivity( ContextCompat.startActivity(
this@ProfileActivity, Intent(this@ProfileActivity, ListActivity::class.java) this@ProfileActivity,
.putExtra("anime", false) Intent(this@ProfileActivity, ListActivity::class.java)
.putExtra("userId", user.id) .putExtra("anime", false)
.putExtra("username", user.name), null .putExtra("userId", user.id)
) .putExtra("username", user.name),
null
)
}
profileCloseButton.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
} }
} }
} }
@ -265,29 +284,31 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
if (mMaxScrollSize == 0) mMaxScrollSize = appBar.totalScrollRange if (mMaxScrollSize == 0) mMaxScrollSize = appBar.totalScrollRange
val percentage = abs(i) * 100 / mMaxScrollSize val percentage = abs(i) * 100 / mMaxScrollSize
binding.profileUserAvatarContainer.visibility = with (bindingProfileAppBar) {
if (binding.profileUserAvatarContainer.scaleX == 0f) View.GONE else View.VISIBLE profileUserAvatarContainer.visibility =
val duration = (200 * (PrefManager.getVal(PrefName.AnimationSpeed) as Float)).toLong() if (profileUserAvatarContainer.scaleX == 0f) View.GONE else View.VISIBLE
if (percentage >= percent && !isCollapsed) { val duration = (200 * (PrefManager.getVal(PrefName.AnimationSpeed) as Float)).toLong()
isCollapsed = true if (percentage >= percent && !isCollapsed) {
ObjectAnimator.ofFloat(binding.profileUserDataContainer, "translationX", screenWidth) isCollapsed = true
.setDuration(duration).start() ObjectAnimator.ofFloat(profileUserDataContainer, "translationX", screenWidth)
ObjectAnimator.ofFloat(binding.profileUserAvatarContainer, "translationX", screenWidth) .setDuration(duration).start()
.setDuration(duration).start() ObjectAnimator.ofFloat(profileUserAvatarContainer, "translationX", screenWidth)
ObjectAnimator.ofFloat(binding.profileButtonContainer, "translationX", screenWidth) .setDuration(duration).start()
.setDuration(duration).start() ObjectAnimator.ofFloat(profileButtonContainer, "translationX", screenWidth)
binding.profileBannerImage.pause() .setDuration(duration).start()
} profileBannerImage.pause()
if (percentage <= percent && isCollapsed) { }
isCollapsed = false if (percentage <= percent && isCollapsed) {
ObjectAnimator.ofFloat(binding.profileUserDataContainer, "translationX", 0f) isCollapsed = false
.setDuration(duration).start() ObjectAnimator.ofFloat(profileUserDataContainer, "translationX", 0f)
ObjectAnimator.ofFloat(binding.profileUserAvatarContainer, "translationX", 0f) .setDuration(duration).start()
.setDuration(duration).start() ObjectAnimator.ofFloat(profileUserAvatarContainer, "translationX", 0f)
ObjectAnimator.ofFloat(binding.profileButtonContainer, "translationX", 0f) .setDuration(duration).start()
.setDuration(duration).start() ObjectAnimator.ofFloat(profileButtonContainer, "translationX", 0f)
.setDuration(duration).start()
if (PrefManager.getVal(PrefName.BannerAnimations)) binding.profileBannerImage.resume() if (PrefManager.getVal(PrefName.BannerAnimations)) profileBannerImage.resume()
}
} }
} }

View file

@ -0,0 +1,22 @@
package ani.dantotsu.util
import android.os.CountDownTimer
// https://stackoverflow.com/a/40422151/461982
abstract class CountUpTimer protected constructor(
private val duration: Long
) : CountDownTimer(duration, INTERVAL_MS) {
abstract fun onTick(second: Int)
override fun onTick(msUntilFinished: Long) {
val second = ((duration - msUntilFinished) / 1000).toInt()
onTick(second)
}
override fun onFinish() {
onTick(duration / 1000)
}
companion object {
private const val INTERVAL_MS: Long = 1000
}
}

View file

@ -0,0 +1,17 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:tint="#000000"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp">
<group
android:translateX="24"
android:rotation="90">
<path
android:fillColor="@android:color/white"
android:pathData="M12,4c4.41,0 8,3.59 8,8s-3.59,8 -8,8s-8,-3.59 -8,-8S7.59,4 12,4M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2L12,2zM13,12l0,-4h-2l0,4H8l4,4l4,-4H13z"/>
</group>
</vector>

View file

@ -24,253 +24,7 @@
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
<com.google.android.material.appbar.AppBarLayout <include layout="@layout/item_profile_app_bar" />
android:id="@+id/profileAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:translationZ="5dp"
android:visibility="gone"
tools:visibility="visible">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="false"
app:contentScrim="?android:colorBackground"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.flaviofaria.kenburnsview.KenBurnsView
android:id="@+id/profileBannerImage"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
tools:ignore="ContentDescription"
tools:src="@tools:sample/backgrounds/scenic" />
<ImageView
android:id="@+id/profileBannerGradient"
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@drawable/linear_gradient_bg"
tools:ignore="ContentDescription" />
<LinearLayout
android:id="@+id/profileUserDataContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="8dp"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:id="@+id/profileUserAvatarContainer"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_gravity="center"
android:backgroundTint="@color/transparent"
app:cardCornerRadius="64dp"
app:strokeColor="@color/transparent">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profileUserAvatar"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:ignore="ContentDescription,ImageContrastCheck"
tools:tint="@color/transparent" />
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/profileUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/username"
android:textColor="?attr/colorPrimary"
android:textSize="18sp" />
<Button
android:id="@+id/followButton"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:backgroundTint="?attr/colorSecondaryContainer"
android:enabled="true"
android:fontFamily="@font/poppins_bold"
android:text="@string/follow"
android:textColor="@color/bg_opp"
android:textSize="14sp"
app:cornerRadius="8dp"
app:strokeColor="?attr/colorSecondaryContainer"
tools:ignore="SpeakableTextPresentCheck" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="20dp"
android:layout_marginEnd="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/profileMenuButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/menu"
android:src="@drawable/ic_round_dots_vertical_24"
app:tint="@color/bg_opp" />
</LinearLayout>
</FrameLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/profileButtonContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginTop="200dp"
android:layout_marginBottom="2dp"
android:backgroundTint="?attr/colorSurfaceVariant"
android:baselineAligned="false"
app:cardCornerRadius="24dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/profileFollowerCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileFollowerCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/followers" />
</LinearLayout>
<View
android:layout_width="3dp"
android:layout_height="match_parent"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/profileFollowingCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileFollowingCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/following" />
</LinearLayout>
<View
android:layout_width="3dp"
android:layout_height="match_parent"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/profileAnimeCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileAnimeCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/anime" />
</LinearLayout>
<View
android:layout_width="3dp"
android:layout_height="match_parent"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/profileMangaCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileMangaCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="4" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/manga" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -19,261 +19,7 @@
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
<com.google.android.material.appbar.AppBarLayout <include layout="@layout/item_profile_app_bar" />
android:id="@+id/profileAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:translationZ="5dp"
android:visibility="gone"
tools:visibility="visible">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="false"
app:contentScrim="?android:colorBackground"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.flaviofaria.kenburnsview.KenBurnsView
android:id="@+id/profileBannerImage"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
tools:ignore="ContentDescription"
tools:src="@tools:sample/backgrounds/scenic" />
<ImageView
android:id="@+id/profileBannerImageNoKen"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
tools:ignore="ContentDescription"
tools:src="@tools:sample/backgrounds/scenic" />
<ImageView
android:id="@+id/profileBannerGradient"
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@drawable/linear_gradient_bg"
tools:ignore="ContentDescription" />
<LinearLayout
android:id="@+id/profileUserDataContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="8dp"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:id="@+id/profileUserAvatarContainer"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_gravity="center"
android:backgroundTint="@color/transparent"
app:cardCornerRadius="64dp"
app:strokeColor="@color/transparent">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profileUserAvatar"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:ignore="ContentDescription,ImageContrastCheck"
tools:tint="@color/transparent" />
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/profileUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/username"
android:textColor="?attr/colorPrimary"
android:textSize="18sp" />
<Button
android:id="@+id/followButton"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:backgroundTint="?attr/colorSecondaryContainer"
android:enabled="true"
android:fontFamily="@font/poppins_bold"
android:text="@string/follow"
android:textColor="@color/bg_opp"
android:textSize="14sp"
app:cornerRadius="8dp"
app:strokeColor="?attr/colorSecondaryContainer"
tools:ignore="SpeakableTextPresentCheck" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="20dp"
android:layout_marginEnd="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/profileMenuButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/menu"
android:src="@drawable/ic_round_dots_vertical_24"
app:tint="@color/bg_opp" />
</LinearLayout>
</FrameLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/profileButtonContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginStart="12dp"
android:layout_marginTop="200dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="2dp"
android:backgroundTint="?attr/colorSurfaceVariant"
android:baselineAligned="false"
app:cardCornerRadius="24dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/profileFollowerCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileFollowerCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/followers" />
</LinearLayout>
<View
android:layout_width="3dp"
android:layout_height="match_parent"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/profileFollowingCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileFollowingCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/following" />
</LinearLayout>
<View
android:layout_width="3dp"
android:layout_height="match_parent"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/profileAnimeCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileAnimeCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/anime" />
</LinearLayout>
<View
android:layout_width="3dp"
android:layout_height="match_parent"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/profileMangaCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileMangaCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="4" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/manga" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -0,0 +1,278 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/profileAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:translationZ="5dp"
android:visibility="gone"
tools:visibility="visible">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="false"
app:contentScrim="?android:colorBackground"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.flaviofaria.kenburnsview.KenBurnsView
android:id="@+id/profileBannerImage"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
tools:ignore="ContentDescription"
tools:src="@tools:sample/backgrounds/scenic" />
<ImageView
android:id="@+id/profileBannerImageNoKen"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
tools:ignore="ContentDescription"
tools:src="@tools:sample/backgrounds/scenic" />
<ImageView
android:id="@+id/profileBannerGradient"
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@drawable/linear_gradient_bg"
tools:ignore="ContentDescription" />
<LinearLayout
android:id="@+id/profileUserDataContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="8dp"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:id="@+id/profileUserAvatarContainer"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_gravity="center"
android:backgroundTint="@color/transparent"
app:cardCornerRadius="64dp"
app:strokeColor="@color/transparent">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profileUserAvatar"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:ignore="ContentDescription,ImageContrastCheck"
tools:tint="@color/transparent" />
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/profileUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/username"
android:textColor="?attr/colorPrimary"
android:textSize="18sp" />
<Button
android:id="@+id/followButton"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:backgroundTint="?attr/colorSecondaryContainer"
android:enabled="true"
android:fontFamily="@font/poppins_bold"
android:text="@string/follow"
android:textColor="@color/bg_opp"
android:textSize="14sp"
app:cornerRadius="8dp"
app:strokeColor="?attr/colorSecondaryContainer"
tools:ignore="SpeakableTextPresentCheck" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginTop="20dp"
android:layout_marginStart="24dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/profileCloseButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/menu"
android:src="@drawable/ic_circle_arrow_left_24"
app:tint="@color/bg_opp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="20dp"
android:layout_marginEnd="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/profileMenuButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/menu"
android:src="@drawable/ic_round_dots_vertical_24"
app:tint="@color/bg_opp" />
</LinearLayout>
</FrameLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/profileButtonContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginStart="12dp"
android:layout_marginTop="200dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="2dp"
android:backgroundTint="?attr/colorSurfaceVariant"
android:baselineAligned="false"
app:cardCornerRadius="24dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/profileFollowerCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileFollowerCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/followers" />
</LinearLayout>
<View
android:layout_width="3dp"
android:layout_height="match_parent"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/profileFollowingCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileFollowingCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/following" />
</LinearLayout>
<View
android:layout_width="3dp"
android:layout_height="match_parent"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/profileAnimeCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileAnimeCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/anime" />
</LinearLayout>
<View
android:layout_width="3dp"
android:layout_height="match_parent"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/profileMangaCountContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/profileMangaCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?attr/colorPrimary"
tools:text="4" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/manga" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</merge>

View file

@ -503,6 +503,7 @@
<string name="refresh_token_load_failed">Refresh Token : Failed to load Saved Token</string> <string name="refresh_token_load_failed">Refresh Token : Failed to load Saved Token</string>
<string name="refreshing_token_failed">Refreshing Token Failed</string> <string name="refreshing_token_failed">Refreshing Token Failed</string>
<string name="episode_release_countdown">Episode %1$d will be released in</string> <string name="episode_release_countdown">Episode %1$d will be released in</string>
<string name="chapter_release_timeout">Chapter %1$d has been available for</string>
<string name="time_format">%1$d days %2$d hrs %3$d mins %4$d secs</string> <string name="time_format">%1$d days %2$d hrs %3$d mins %4$d secs</string>
<string-array name="sort_by"> <string-array name="sort_by">
<item>Score</item> <item>Score</item>