more offline stuff/bugfixes

This commit is contained in:
Finnley Somdahl 2023-11-20 00:39:14 -06:00
parent 3dfcc9fc31
commit 4db301ca7a
29 changed files with 341 additions and 119 deletions

View file

@ -221,6 +221,7 @@
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".download.DownloadContainerActivity" />
<activity
android:name="eu.kanade.tachiyomi.extension.manga.util.MangaExtensionInstallActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"

View file

@ -420,7 +420,13 @@ fun String.findBetween(a: String, b: String): String? {
fun ImageView.loadImage(url: String?, size: Int = 0) {
if (!url.isNullOrEmpty()) {
loadImage(FileUrl(url), size)
val localFile = File(url)
if (localFile.exists()) {
loadLocalImage(localFile, size)
}
else {
loadImage(FileUrl(url), size)
}
}
}
@ -433,6 +439,14 @@ fun ImageView.loadImage(file: FileUrl?, size: Int = 0) {
}
}
fun ImageView.loadLocalImage(file: File?, size: Int = 0) {
if (file?.exists() == true) {
tryWith {
Glide.with(this.context).load(file).transition(withCrossFade()).override(size).into(this)
}
}
}
class SafeClickListener(
private var defaultInterval: Int = 1000,
private val onSafeCLick: (View) -> Unit

View file

@ -21,6 +21,7 @@ import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnticipateInterpolator
import android.widget.FrameLayout
import android.widget.TextView
import androidx.activity.addCallback
import androidx.activity.viewModels
@ -40,6 +41,7 @@ import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.AnilistHomeViewModel
import ani.dantotsu.databinding.ActivityMainBinding
import ani.dantotsu.databinding.ItemNavbarBinding
import ani.dantotsu.databinding.SplashScreenBinding
import ani.dantotsu.download.manga.OfflineMangaFragment
import ani.dantotsu.home.AnimeFragment
@ -160,7 +162,7 @@ class MainActivity : AppCompatActivity() {
initActivity(this)
uiSettings = loadData("ui_settings") ?: uiSettings
selectedOption = uiSettings.defaultStartUpTab
binding.navbarContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
binding.includedNavbar.navbarContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = navBarHeight
}
}
@ -173,7 +175,7 @@ class MainActivity : AppCompatActivity() {
model.genres.observe(this) {
if (it != null) {
if (it) {
val navbar = binding.navbar
val navbar = binding.includedNavbar.navbar
bottomBar = navbar
navbar.visibility = View.VISIBLE
binding.mainProgressBar.visibility = View.GONE

View file

@ -0,0 +1,23 @@
package ani.dantotsu.download
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import ani.dantotsu.R
import ani.dantotsu.themes.ThemeManager
class DownloadContainerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
setContentView(R.layout.activity_container)
val fragmentClassName = intent.getStringExtra("FRAGMENT_CLASS_NAME")
val fragment = Class.forName(fragmentClassName).newInstance() as Fragment
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit()
}
}

View file

@ -60,7 +60,7 @@ class MangaDownloaderService : Service() {
private val downloadJobs = mutableMapOf<String, Job>()
private val mutex = Mutex()
var isCurrentlyProcessing = false
private var isCurrentlyProcessing = false
override fun onBind(intent: Intent?): IBinder? {
// This is only required for bound services.
@ -78,7 +78,7 @@ class MangaDownloaderService : Service() {
setProgress(0, 0, false)
}
startForeground(NOTIFICATION_ID, builder.build())
registerReceiver(cancelReceiver, IntentFilter(ACTION_CANCEL_DOWNLOAD))
ContextCompat.registerReceiver(this, cancelReceiver, IntentFilter(ACTION_CANCEL_DOWNLOAD), ContextCompat.RECEIVER_NOT_EXPORTED)
}
override fun onDestroy() {

View file

@ -17,7 +17,7 @@ class OfflineMangaAdapter(private val context: Context, private val items: List<
return items.size
}
override fun getItem(position: Int): Any? {
override fun getItem(position: Int): Any {
return items[position]
}

View file

@ -95,7 +95,7 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
}
binding.animeUserAvatar.setSafeOnClickListener {
SettingsDialogFragment().show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
SettingsDialogFragment(SettingsDialogFragment.Companion.PageType.ANIME).show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
}
listOf(

View file

@ -107,7 +107,7 @@ class HomeFragment : Fragment() {
}
binding.homeUserAvatarContainer.setSafeOnClickListener {
SettingsDialogFragment().show(parentFragmentManager, "dialog")
SettingsDialogFragment(SettingsDialogFragment.Companion.PageType.HOME).show(parentFragmentManager, "dialog")
}
binding.homeContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {

View file

@ -89,7 +89,7 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
}
binding.mangaUserAvatar.setSafeOnClickListener {
SettingsDialogFragment().show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
SettingsDialogFragment(SettingsDialogFragment.Companion.PageType.MANGA).show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
}
binding.mangaSearchBar.setEndIconOnClickListener {

View file

@ -1,32 +1,109 @@
package ani.dantotsu.home
import android.content.Context
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.doOnAttach
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.viewpager2.adapter.FragmentStateAdapter
import ani.dantotsu.R
import ani.dantotsu.ZoomOutPageTransformer
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.databinding.ActivityNoInternetBinding
import ani.dantotsu.download.manga.OfflineMangaFragment
import ani.dantotsu.initActivity
import ani.dantotsu.isOnline
import ani.dantotsu.loadData
import ani.dantotsu.navBarHeight
import ani.dantotsu.offline.OfflineFragment
import ani.dantotsu.selectedOption
import ani.dantotsu.settings.UserInterfaceSettings
import ani.dantotsu.startMainActivity
import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager
import nl.joery.animatedbottombar.AnimatedBottomBar
class NoInternet : AppCompatActivity() {
private lateinit var binding: ActivityNoInternetBinding
lateinit var bottomBar: AnimatedBottomBar
private var uiSettings = UserInterfaceSettings()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
val binding = ActivityNoInternetBinding.inflate(layoutInflater)
binding = ActivityNoInternetBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.refreshContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = statusBarHeight
bottomMargin = navBarHeight
val _bottomBar = findViewById<AnimatedBottomBar>(R.id.navbar)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val backgroundDrawable = _bottomBar.background as GradientDrawable
val currentColor = backgroundDrawable.color?.defaultColor ?: 0
val semiTransparentColor = (currentColor and 0x00FFFFFF) or 0xE8000000.toInt()
backgroundDrawable.setColor(semiTransparentColor)
_bottomBar.background = backgroundDrawable
}
binding.refreshButton.setOnClickListener {
if (isOnline(this)) {
startMainActivity(this)
val colorOverflow = this.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE)
.getBoolean("colorOverflow", false)
if (!colorOverflow) {
_bottomBar.background = ContextCompat.getDrawable(this, R.drawable.bottom_nav_gray)
}
binding.root.doOnAttach {
initActivity(this)
uiSettings = loadData("ui_settings") ?: uiSettings
selectedOption = uiSettings.defaultStartUpTab
binding.includedNavbar.navbarContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = navBarHeight
}
}
val navbar = binding.includedNavbar.navbar
ani.dantotsu.bottomBar = navbar
navbar.visibility = View.VISIBLE
val mainViewPager = binding.viewpager
mainViewPager.isUserInputEnabled = false
mainViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle)
mainViewPager.setPageTransformer(ZoomOutPageTransformer(uiSettings))
navbar.setOnTabSelectListener(object :
AnimatedBottomBar.OnTabSelectListener {
override fun onTabSelected(
lastIndex: Int,
lastTab: AnimatedBottomBar.Tab?,
newIndex: Int,
newTab: AnimatedBottomBar.Tab
) {
navbar.animate().translationZ(12f).setDuration(200).start()
selectedOption = newIndex
mainViewPager.setCurrentItem(newIndex, false)
}
})
navbar.selectTabAt(selectedOption)
//supportFragmentManager.beginTransaction().replace(binding.fragmentContainer.id, OfflineFragment()).commit()
}
private class ViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
FragmentStateAdapter(fragmentManager, lifecycle) {
override fun getItemCount(): Int = 3
override fun createFragment(position: Int): Fragment {
when (position) {
0 -> return OfflineFragment()
1 -> return OfflineFragment()
2 -> return OfflineMangaFragment()
}
return LoginFragment()
}
}
}

View file

@ -94,7 +94,7 @@ class MangaChapterAdapter(
fun bind(chapterNumber: String) {
if (activeDownloads.contains(chapterNumber)) {
// Show spinner
binding.itemDownload.setImageResource(R.drawable.spinner_icon_manga)
binding.itemDownload.setImageResource(R.drawable.ic_round_refresh_24)
} else if(downloadedChapters.contains(chapterNumber)) {
// Show checkmark
binding.itemDownload.setImageResource(R.drawable.ic_check)

View file

@ -74,7 +74,9 @@ class MangaReadAdapter(
setLanguageList(0,i)
}
subscribeButton(false)
fragment.loadChapters(i, false)
//invalidate if it's the last source
val invalidate = i == mangaReadSources.names.size - 1
fragment.loadChapters(i, invalidate)
}
binding.animeSourceLanguage.setOnItemClickListener { _, _, i, _ ->

View file

@ -118,7 +118,7 @@ abstract class BaseImageAdapter(
abstract suspend fun loadImage(position: Int, parent: View): Boolean
companion object {
suspend fun Context.loadBitmap_old(link: FileUrl, transforms: List<BitmapTransformation>): Bitmap? {
suspend fun Context.loadBitmap_old(link: FileUrl, transforms: List<BitmapTransformation>): Bitmap? { //still used in some places
return tryWithSuspend {
withContext(Dispatchers.IO) {
Glide.with(this@loadBitmap_old)
@ -154,8 +154,9 @@ abstract class BaseImageAdapter(
.asBitmap()
.let {
val fileUri = Uri.fromFile(File(link.url)).toString()
if (fileUri.startsWith("file://")) {
it.load(fileUri)
val localFile = File(link.url)
if (localFile.exists()) {
it.load(localFile.absoluteFile)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
} else {

View file

@ -0,0 +1,29 @@
package ani.dantotsu.offline
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import ani.dantotsu.databinding.FragmentOfflineBinding
import ani.dantotsu.isOnline
import ani.dantotsu.navBarHeight
import ani.dantotsu.startMainActivity
import ani.dantotsu.statusBarHeight
class OfflineFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val binding = FragmentOfflineBinding.inflate(inflater, container, false)
binding.refreshContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = statusBarHeight
bottomMargin = navBarHeight
}
binding.refreshButton.setOnClickListener {
if (isOnline(requireContext())) {
startMainActivity(requireActivity())
}
}
return binding.root
}
}

View file

@ -10,6 +10,7 @@ import android.content.IntentFilter
import android.net.Uri
import android.os.Environment
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
@ -142,7 +143,8 @@ object AppUpdater {
-1
}
if (id == -1L) return true
registerReceiver(
ContextCompat.registerReceiver(
this,
object : BroadcastReceiver() {
@SuppressLint("Range")
override fun onReceive(context: Context?, intent: Intent?) {
@ -171,7 +173,8 @@ object AppUpdater {
logError(e)
}
}
}, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
}, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE),
ContextCompat.RECEIVER_NOT_EXPORTED
)
return true
}

View file

@ -150,7 +150,7 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
}
override suspend fun getVideoExtractor(server: VideoServer): VideoExtractor? {
override suspend fun getVideoExtractor(server: VideoServer): VideoExtractor {
return VideoServerPassthrough(server)
}

View file

@ -51,7 +51,7 @@ abstract class BaseParser {
* **/
open suspend fun autoSearch(mediaObj: Media): ShowResponse? {
var response: ShowResponse? = null//loadSavedShowResponse(mediaObj.id)
if (response != null) {
if (response != null && this !is OfflineMangaParser) {
saveShowResponse(mediaObj.id, response, true)
} else {
setUserText("Searching : ${mediaObj.mainName()}")

View file

@ -10,14 +10,17 @@ import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Switch
import androidx.core.content.ContextCompat
import ani.dantotsu.*
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.others.imagesearch.ImageSearchActivity
import ani.dantotsu.databinding.BottomSheetSettingsBinding
import ani.dantotsu.download.DownloadContainerActivity
import ani.dantotsu.download.manga.OfflineMangaFragment
class SettingsDialogFragment : BottomSheetDialogFragment() {
class SettingsDialogFragment(val pageType: PageType) : BottomSheetDialogFragment() {
private var _binding: BottomSheetSettingsBinding? = null
private val binding get() = _binding!!
@ -70,18 +73,42 @@ class SettingsDialogFragment : BottomSheetDialogFragment() {
dismiss()
}
binding.settingsDownloads.setSafeOnClickListener {
try {
val arrayOfFiles = ContextCompat.getExternalFilesDirs(requireContext(), null)
startActivity(
if (loadData<Boolean>("sd_dl") == true && arrayOfFiles.size > 1 && arrayOfFiles[0] != null && arrayOfFiles[1] != null) {
val parentDirectory = arrayOfFiles[1].toString()
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(Uri.parse(parentDirectory), "resource/folder")
} else Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
)
} catch (e: ActivityNotFoundException) {
toast(getString(R.string.file_manager_not_found))
when(pageType) {
PageType.MANGA -> {
val intent = Intent(activity, DownloadContainerActivity::class.java)
intent.putExtra("FRAGMENT_CLASS_NAME", OfflineMangaFragment::class.java.name)
startActivity(intent)
}
PageType.ANIME -> {
try {
val arrayOfFiles = ContextCompat.getExternalFilesDirs(requireContext(), null)
startActivity(
if (loadData<Boolean>("sd_dl") == true && arrayOfFiles.size > 1 && arrayOfFiles[0] != null && arrayOfFiles[1] != null) {
val parentDirectory = arrayOfFiles[1].toString()
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(Uri.parse(parentDirectory), "resource/folder")
} else Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
)
} catch (e: ActivityNotFoundException) {
toast(getString(R.string.file_manager_not_found))
}
}
PageType.HOME -> {
try {
val arrayOfFiles = ContextCompat.getExternalFilesDirs(requireContext(), null)
startActivity(
if (loadData<Boolean>("sd_dl") == true && arrayOfFiles.size > 1 && arrayOfFiles[0] != null && arrayOfFiles[1] != null) {
val parentDirectory = arrayOfFiles[1].toString()
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(Uri.parse(parentDirectory), "resource/folder")
} else Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
)
} catch (e: ActivityNotFoundException) {
toast(getString(R.string.file_manager_not_found))
}
}
}
dismiss()
}
}
@ -90,4 +117,10 @@ class SettingsDialogFragment : BottomSheetDialogFragment() {
super.onDestroyView()
_binding = null
}
companion object{
enum class PageType{
MANGA, ANIME, HOME
}
}
}

View file

@ -8,6 +8,7 @@ import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageInstaller
import android.os.Build
import androidx.core.content.ContextCompat
import eu.kanade.tachiyomi.extension.InstallStep
import eu.kanade.tachiyomi.util.lang.use
import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat
@ -100,7 +101,7 @@ class PackageInstallerInstallerAnime(private val service: Service) : InstallerAn
}
init {
service.registerReceiver(packageActionReceiver, IntentFilter(INSTALL_ACTION))
ContextCompat.registerReceiver(service, packageActionReceiver, IntentFilter(INSTALL_ACTION), ContextCompat.RECEIVER_NOT_EXPORTED)
}
}

View file

@ -4,6 +4,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.core.content.ContextCompat
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
import eu.kanade.tachiyomi.extension.anime.model.AnimeLoadResult
import kotlinx.coroutines.CoroutineStart
@ -27,7 +28,7 @@ internal class AnimeExtensionInstallReceiver(private val listener: Listener) :
* Registers this broadcast receiver
*/
fun register(context: Context) {
context.registerReceiver(this, filter)
ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_NOT_EXPORTED)
}
/**

View file

@ -216,7 +216,7 @@ internal class AnimeExtensionInstaller(private val context: Context) {
isRegistered = true
val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
context.registerReceiver(this, filter)
ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_EXPORTED)
}
/**

View file

@ -8,6 +8,7 @@ import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageInstaller
import android.os.Build
import androidx.core.content.ContextCompat
import eu.kanade.tachiyomi.extension.InstallStep
import eu.kanade.tachiyomi.util.lang.use
import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat
@ -100,7 +101,7 @@ class PackageInstallerInstallerManga(private val service: Service) : InstallerMa
}
init {
service.registerReceiver(packageActionReceiver, IntentFilter(INSTALL_ACTION))
ContextCompat.registerReceiver(service, packageActionReceiver, IntentFilter(INSTALL_ACTION), ContextCompat.RECEIVER_NOT_EXPORTED)
}
}

View file

@ -4,6 +4,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.core.content.ContextCompat
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
import eu.kanade.tachiyomi.extension.manga.model.MangaLoadResult
import kotlinx.coroutines.CoroutineStart
@ -27,7 +28,7 @@ internal class MangaExtensionInstallReceiver(private val listener: Listener) :
* Registers this broadcast receiver
*/
fun register(context: Context) {
context.registerReceiver(this, filter)
ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_NOT_EXPORTED)
}
/**

View file

@ -213,7 +213,7 @@ internal class MangaExtensionInstaller(private val context: Context) {
isRegistered = true
val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
context.registerReceiver(this, filter)
ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_EXPORTED)
}
/**

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View file

@ -19,39 +19,9 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:id="@+id/navbar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom">
<nl.joery.animatedbottombar.AnimatedBottomBar
android:id="@+id/navbar"
android:layout_width="240dp"
android:layout_height="56dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:layout_marginBottom="32dp"
android:background="@drawable/bottom_nav"
android:elevation="4dp"
android:padding="8dp"
android:translationZ="12dp"
android:visibility="gone"
app:abb_animationDuration="300"
app:abb_animationInterpolator="@anim/over_shoot"
app:abb_badgeBackgroundColor="#F44336"
app:abb_indicatorColor="?attr/colorTertiary"
app:abb_indicatorLocation="bottom"
app:abb_indicatorMargin="28dp"
app:abb_selectedTabType="text"
app:abb_tabColor="?attr/colorOutline"
app:abb_tabColorDisabled="?attr/colorPrimaryContainer"
app:abb_tabColorSelected="?attr/colorPrimary"
app:abb_tabs="@menu/bottom_navbar_menu"
app:abb_textAppearance="@style/NavBarText"
tools:visibility="visible" />
</FrameLayout>
<include
android:id="@+id/included_navbar"
layout="@layout/item_navbar" />
<FrameLayout
android:id="@+id/fragmentContainer"

View file

@ -9,52 +9,20 @@
android:layout_height="match_parent"
tools:ignore="ContentDescription" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/included_navbar"
layout="@layout/item_navbar" />
<FrameLayout
android:id="@+id/refreshContainer"
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/noInternetSad"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_thin"
android:text="@string/sad"
android:textColor="?attr/colorPrimary"
android:textSize="64sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="@string/no_internet"
android:textAlignment="center"
android:textColor="?attr/colorOnBackground"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/noInternetSad" />
</LinearLayout>
<Button
android:id="@+id/refreshButton"
android:layout_width="150dp"
android:layout_height="64dp"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="128dp"
android:fontFamily="@font/poppins_bold"
android:text="@string/refresh"
app:cornerRadius="16dp"
app:icon="@drawable/ic_round_refresh_24" />
</FrameLayout>
</FrameLayout>

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:id="@+id/refreshContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/noInternetSad"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_thin"
android:text="@string/sad"
android:textColor="?attr/colorPrimary"
android:textSize="64sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="@string/no_internet"
android:textAlignment="center"
android:textColor="?attr/colorOnBackground"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/noInternetSad" />
</LinearLayout>
<Button
android:id="@+id/refreshButton"
android:layout_width="150dp"
android:layout_height="64dp"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="128dp"
android:fontFamily="@font/poppins_bold"
android:text="@string/refresh"
app:cornerRadius="16dp"
app:icon="@drawable/ic_round_refresh_24" />
</FrameLayout>
</FrameLayout>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
android:id="@+id/navbar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom">
<nl.joery.animatedbottombar.AnimatedBottomBar
android:id="@+id/navbar"
android:layout_width="240dp"
android:layout_height="56dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:layout_marginBottom="32dp"
android:background="@drawable/bottom_nav"
android:elevation="4dp"
android:padding="8dp"
android:translationZ="12dp"
android:visibility="gone"
app:abb_animationDuration="300"
app:abb_animationInterpolator="@anim/over_shoot"
app:abb_badgeBackgroundColor="#F44336"
app:abb_indicatorColor="?attr/colorTertiary"
app:abb_indicatorLocation="bottom"
app:abb_indicatorMargin="28dp"
app:abb_selectedTabType="text"
app:abb_tabColor="?attr/colorOutline"
app:abb_tabColorDisabled="?attr/colorPrimaryContainer"
app:abb_tabColorSelected="?attr/colorPrimary"
app:abb_tabs="@menu/bottom_navbar_menu"
app:abb_textAppearance="@style/NavBarText"
tools:visibility="visible" />
</FrameLayout>