chore: code cleanup
This commit is contained in:
parent
386e02a564
commit
24147e746a
198 changed files with 1367 additions and 965 deletions
|
@ -7,11 +7,11 @@ import android.os.Bundle
|
||||||
import androidx.multidex.MultiDex
|
import androidx.multidex.MultiDex
|
||||||
import androidx.multidex.MultiDexApplication
|
import androidx.multidex.MultiDexApplication
|
||||||
import ani.dantotsu.addons.download.DownloadAddonManager
|
import ani.dantotsu.addons.download.DownloadAddonManager
|
||||||
|
import ani.dantotsu.addons.torrent.TorrentAddonManager
|
||||||
import ani.dantotsu.aniyomi.anime.custom.AppModule
|
import ani.dantotsu.aniyomi.anime.custom.AppModule
|
||||||
import ani.dantotsu.aniyomi.anime.custom.PreferenceModule
|
import ani.dantotsu.aniyomi.anime.custom.PreferenceModule
|
||||||
import ani.dantotsu.connections.comments.CommentsAPI
|
import ani.dantotsu.connections.comments.CommentsAPI
|
||||||
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||||
import ani.dantotsu.addons.torrent.TorrentAddonManager
|
|
||||||
import ani.dantotsu.notifications.TaskScheduler
|
import ani.dantotsu.notifications.TaskScheduler
|
||||||
import ani.dantotsu.others.DisabledReports
|
import ani.dantotsu.others.DisabledReports
|
||||||
import ani.dantotsu.parsers.AnimeSources
|
import ani.dantotsu.parsers.AnimeSources
|
||||||
|
|
|
@ -190,7 +190,7 @@ var loadMedia: Int? = null
|
||||||
var loadIsMAL = false
|
var loadIsMAL = false
|
||||||
|
|
||||||
val Int.toPx get() = TypedValue.applyDimension(
|
val Int.toPx get() = TypedValue.applyDimension(
|
||||||
TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics
|
TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), getSystem().displayMetrics
|
||||||
).toInt()
|
).toInt()
|
||||||
|
|
||||||
fun initActivity(a: Activity) {
|
fun initActivity(a: Activity) {
|
||||||
|
@ -464,7 +464,7 @@ class InputFilterMinMax(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ZoomOutPageTransformer() :
|
class ZoomOutPageTransformer :
|
||||||
ViewPager2.PageTransformer {
|
ViewPager2.PageTransformer {
|
||||||
override fun transformPage(view: View, position: Float) {
|
override fun transformPage(view: View, position: Float) {
|
||||||
if (position == 0.0f && PrefManager.getVal(PrefName.LayoutAnimations)) {
|
if (position == 0.0f && PrefManager.getVal(PrefName.LayoutAnimations)) {
|
||||||
|
|
|
@ -1,38 +1,23 @@
|
||||||
package ani.dantotsu.addons
|
package ani.dantotsu.addons
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.DownloadManager
|
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.content.IntentFilter
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Environment
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.content.getSystemService
|
|
||||||
import androidx.core.net.toUri
|
|
||||||
import ani.dantotsu.BuildConfig
|
|
||||||
import ani.dantotsu.Mapper
|
import ani.dantotsu.Mapper
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.client
|
import ani.dantotsu.client
|
||||||
import ani.dantotsu.logError
|
import ani.dantotsu.logError
|
||||||
import ani.dantotsu.media.MediaType
|
|
||||||
import ani.dantotsu.openLinkInBrowser
|
import ani.dantotsu.openLinkInBrowser
|
||||||
import ani.dantotsu.others.AppUpdater
|
import ani.dantotsu.others.AppUpdater
|
||||||
import ani.dantotsu.settings.InstallerSteps
|
import ani.dantotsu.settings.InstallerSteps
|
||||||
import ani.dantotsu.toast
|
import ani.dantotsu.toast
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.json.JsonArray
|
import kotlinx.serialization.json.JsonArray
|
||||||
import kotlinx.serialization.json.decodeFromJsonElement
|
import kotlinx.serialization.json.decodeFromJsonElement
|
||||||
import rx.Observable
|
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
|
||||||
class AddonDownloader {
|
class AddonDownloader {
|
||||||
|
@ -101,8 +86,7 @@ class AddonDownloader {
|
||||||
{ error -> installerSteps.onError(error) {} },
|
{ error -> installerSteps.onError(error) {} },
|
||||||
{ installerSteps.onComplete {} }
|
{ installerSteps.onComplete {} }
|
||||||
)
|
)
|
||||||
}
|
} else openLinkInBrowser("https://github.com/repos/$repo/releases/tag/v$version")
|
||||||
else openLinkInBrowser("https://github.com/repos/$repo/releases/tag/v$version")
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
|
|
|
@ -9,8 +9,8 @@ import ani.dantotsu.addons.download.DownloadAddon
|
||||||
import ani.dantotsu.addons.download.DownloadAddonApi
|
import ani.dantotsu.addons.download.DownloadAddonApi
|
||||||
import ani.dantotsu.addons.download.DownloadAddonManager
|
import ani.dantotsu.addons.download.DownloadAddonManager
|
||||||
import ani.dantotsu.addons.download.DownloadLoadResult
|
import ani.dantotsu.addons.download.DownloadLoadResult
|
||||||
import ani.dantotsu.addons.torrent.TorrentAddonApi
|
|
||||||
import ani.dantotsu.addons.torrent.TorrentAddon
|
import ani.dantotsu.addons.torrent.TorrentAddon
|
||||||
|
import ani.dantotsu.addons.torrent.TorrentAddonApi
|
||||||
import ani.dantotsu.addons.torrent.TorrentAddonManager
|
import ani.dantotsu.addons.torrent.TorrentAddonManager
|
||||||
import ani.dantotsu.addons.torrent.TorrentLoadResult
|
import ani.dantotsu.addons.torrent.TorrentLoadResult
|
||||||
import ani.dantotsu.media.AddonType
|
import ani.dantotsu.media.AddonType
|
||||||
|
@ -56,7 +56,8 @@ class AddonLoader {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
val extName = pkgManager.getApplicationLabel(appInfo).toString().substringAfter("Dantotsu: ")
|
val extName =
|
||||||
|
pkgManager.getApplicationLabel(appInfo).toString().substringAfter("Dantotsu: ")
|
||||||
val versionName = pkgInfo.versionName
|
val versionName = pkgInfo.versionName
|
||||||
val versionCode = PackageInfoCompat.getLongVersionCode(pkgInfo)
|
val versionCode = PackageInfoCompat.getLongVersionCode(pkgInfo)
|
||||||
|
|
||||||
|
@ -64,7 +65,8 @@ class AddonLoader {
|
||||||
Logger.log("Missing versionName for extension $extName")
|
Logger.log("Missing versionName for extension $extName")
|
||||||
throw IllegalStateException("Missing versionName for extension $extName")
|
throw IllegalStateException("Missing versionName for extension $extName")
|
||||||
}
|
}
|
||||||
val classLoader = PathClassLoader(appInfo.sourceDir, appInfo.nativeLibraryDir, context.classLoader)
|
val classLoader =
|
||||||
|
PathClassLoader(appInfo.sourceDir, appInfo.nativeLibraryDir, context.classLoader)
|
||||||
val loadedClass = try {
|
val loadedClass = try {
|
||||||
Class.forName(className, false, classLoader)
|
Class.forName(className, false, classLoader)
|
||||||
} catch (e: ClassNotFoundException) {
|
} catch (e: ClassNotFoundException) {
|
||||||
|
@ -75,7 +77,7 @@ class AddonLoader {
|
||||||
Logger.log("Extension load error: $extName ($className)")
|
Logger.log("Extension load error: $extName ($className)")
|
||||||
Logger.log(e)
|
Logger.log(e)
|
||||||
throw e
|
throw e
|
||||||
}catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Logger.log("Extension load error: $extName ($className)")
|
Logger.log("Extension load error: $extName ($className)")
|
||||||
Logger.log(e)
|
Logger.log(e)
|
||||||
throw e
|
throw e
|
||||||
|
@ -84,7 +86,8 @@ class AddonLoader {
|
||||||
|
|
||||||
return when (type) {
|
return when (type) {
|
||||||
AddonType.TORRENT -> {
|
AddonType.TORRENT -> {
|
||||||
val extension = instance as? TorrentAddonApi ?: throw IllegalStateException("Extension is not a TorrentAddonApi")
|
val extension = instance as? TorrentAddonApi
|
||||||
|
?: throw IllegalStateException("Extension is not a TorrentAddonApi")
|
||||||
TorrentLoadResult.Success(
|
TorrentLoadResult.Success(
|
||||||
TorrentAddon.Installed(
|
TorrentAddon.Installed(
|
||||||
name = extName,
|
name = extName,
|
||||||
|
@ -96,8 +99,10 @@ class AddonLoader {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
AddonType.DOWNLOAD -> {
|
AddonType.DOWNLOAD -> {
|
||||||
val extension = instance as? DownloadAddonApi ?: throw IllegalStateException("Extension is not a DownloadAddonApi")
|
val extension = instance as? DownloadAddonApi
|
||||||
|
?: throw IllegalStateException("Extension is not a DownloadAddonApi")
|
||||||
DownloadLoadResult.Success(
|
DownloadLoadResult.Success(
|
||||||
DownloadAddon.Installed(
|
DownloadAddon.Installed(
|
||||||
name = extName,
|
name = extName,
|
||||||
|
@ -120,6 +125,7 @@ class AddonLoader {
|
||||||
TorrentAddonManager.TORRENT_CLASS,
|
TorrentAddonManager.TORRENT_CLASS,
|
||||||
type
|
type
|
||||||
)
|
)
|
||||||
|
|
||||||
AddonType.DOWNLOAD -> loadExtension(
|
AddonType.DOWNLOAD -> loadExtension(
|
||||||
context,
|
context,
|
||||||
packageName,
|
packageName,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
|
||||||
abstract class AddonManager<T: Addon.Installed>(
|
abstract class AddonManager<T : Addon.Installed>(
|
||||||
private val context: Context
|
private val context: Context
|
||||||
) {
|
) {
|
||||||
abstract var extension: T?
|
abstract var extension: T?
|
||||||
|
@ -31,14 +31,16 @@ abstract class AddonManager<T: Addon.Installed>(
|
||||||
installer.uninstallApk(it)
|
installer.uninstallApk(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addListenerAction(action: (AddonListener.ListenerAction) -> Unit) {
|
fun addListenerAction(action: (AddonListener.ListenerAction) -> Unit) {
|
||||||
onListenerAction = action
|
onListenerAction = action
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeListenerAction() {
|
fun removeListenerAction() {
|
||||||
onListenerAction = null
|
onListenerAction = null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun install(url: String): Observable<InstallStep> {
|
fun install(url: String): Observable<InstallStep> {
|
||||||
return installer.downloadAndInstall(url, getPackageName()?: "", name, type)
|
return installer.downloadAndInstall(url, getPackageName() ?: "", name, type)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,7 +3,6 @@ package ani.dantotsu.addons.download
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import ani.dantotsu.addons.AddonListener
|
import ani.dantotsu.addons.AddonListener
|
||||||
import ani.dantotsu.addons.AddonLoader
|
import ani.dantotsu.addons.AddonLoader
|
||||||
|
@ -26,7 +25,7 @@ internal class AddonInstallReceiver : BroadcastReceiver() {
|
||||||
ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_EXPORTED)
|
ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_EXPORTED)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setListener(listener: AddonListener, type: AddonType) : AddonInstallReceiver {
|
fun setListener(listener: AddonListener, type: AddonType): AddonInstallReceiver {
|
||||||
this.listener = listener
|
this.listener = listener
|
||||||
this.type = type
|
this.type = type
|
||||||
return this
|
return this
|
||||||
|
|
|
@ -2,6 +2,6 @@ package ani.dantotsu.addons.download
|
||||||
|
|
||||||
import ani.dantotsu.addons.LoadResult
|
import ani.dantotsu.addons.LoadResult
|
||||||
|
|
||||||
open class DownloadLoadResult: LoadResult() {
|
open class DownloadLoadResult : LoadResult() {
|
||||||
class Success(val extension: DownloadAddon.Installed) : DownloadLoadResult()
|
class Success(val extension: DownloadAddon.Installed) : DownloadLoadResult()
|
||||||
}
|
}
|
|
@ -14,10 +14,7 @@ import ani.dantotsu.addons.download.AddonInstallReceiver
|
||||||
import ani.dantotsu.media.AddonType
|
import ani.dantotsu.media.AddonType
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class TorrentAddonManager(
|
class TorrentAddonManager(
|
||||||
|
|
|
@ -2,6 +2,6 @@ package ani.dantotsu.addons.torrent
|
||||||
|
|
||||||
import ani.dantotsu.addons.LoadResult
|
import ani.dantotsu.addons.LoadResult
|
||||||
|
|
||||||
open class TorrentLoadResult: LoadResult() {
|
open class TorrentLoadResult : LoadResult() {
|
||||||
class Success(val extension: TorrentAddon.Installed) : TorrentLoadResult()
|
class Success(val extension: TorrentAddon.Installed) : TorrentLoadResult()
|
||||||
}
|
}
|
|
@ -22,7 +22,7 @@ import uy.kohesive.injekt.api.get
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
|
|
||||||
class ServerService: Service() {
|
class ServerService : Service() {
|
||||||
private val serviceScope = CoroutineScope(EmptyCoroutineContext)
|
private val serviceScope = CoroutineScope(EmptyCoroutineContext)
|
||||||
private val applicationContext = Injekt.get<Application>()
|
private val applicationContext = Injekt.get<Application>()
|
||||||
private val extension = Injekt.get<TorrentAddonManager>().extension!!.extension
|
private val extension = Injekt.get<TorrentAddonManager>().extension!!.extension
|
||||||
|
@ -42,6 +42,7 @@ class ServerService: Service() {
|
||||||
notification(applicationContext)
|
notification(applicationContext)
|
||||||
return START_STICKY
|
return START_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_STOP -> {
|
ACTION_STOP -> {
|
||||||
stopServer()
|
stopServer()
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
|
@ -109,7 +110,7 @@ class ServerService: Service() {
|
||||||
const val ACTION_STOP = "stop_torrent_server"
|
const val ACTION_STOP = "stop_torrent_server"
|
||||||
|
|
||||||
fun isRunning(): Boolean {
|
fun isRunning(): Boolean {
|
||||||
with (Injekt.get<Application>().getSystemService(ACTIVITY_SERVICE) as ActivityManager) {
|
with(Injekt.get<Application>().getSystemService(ACTIVITY_SERVICE) as ActivityManager) {
|
||||||
@Suppress("DEPRECATION") // We only need our services
|
@Suppress("DEPRECATION") // We only need our services
|
||||||
getRunningServices(Int.MAX_VALUE).forEach {
|
getRunningServices(Int.MAX_VALUE).forEach {
|
||||||
if (ServerService::class.java.name.equals(it.service.className)) {
|
if (ServerService::class.java.name.equals(it.service.className)) {
|
||||||
|
|
|
@ -7,9 +7,9 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.database.StandaloneDatabaseProvider
|
import androidx.media3.database.StandaloneDatabaseProvider
|
||||||
import ani.dantotsu.addons.download.DownloadAddonManager
|
import ani.dantotsu.addons.download.DownloadAddonManager
|
||||||
|
import ani.dantotsu.addons.torrent.TorrentAddonManager
|
||||||
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||||
import ani.dantotsu.download.DownloadsManager
|
import ani.dantotsu.download.DownloadsManager
|
||||||
import ani.dantotsu.addons.torrent.TorrentAddonManager
|
|
||||||
import ani.dantotsu.media.manga.MangaCache
|
import ani.dantotsu.media.manga.MangaCache
|
||||||
import ani.dantotsu.parsers.novel.NovelExtensionManager
|
import ani.dantotsu.parsers.novel.NovelExtensionManager
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
|
|
|
@ -1188,7 +1188,7 @@ query (${"$"}page: Int = 1, ${"$"}id: Int, ${"$"}type: MediaType, ${"$"}isAdult:
|
||||||
suspend fun recentlyUpdated(
|
suspend fun recentlyUpdated(
|
||||||
greater: Long = 0,
|
greater: Long = 0,
|
||||||
lesser: Long = System.currentTimeMillis() / 1000 - 10000
|
lesser: Long = System.currentTimeMillis() / 1000 - 10000
|
||||||
): MutableList<Media>? {
|
): MutableList<Media> {
|
||||||
suspend fun execute(page: Int = 1): Page? {
|
suspend fun execute(page: Int = 1): Page? {
|
||||||
val query = """{
|
val query = """{
|
||||||
Page(page:$page,perPage:50) {
|
Page(page:$page,perPage:50) {
|
||||||
|
|
|
@ -84,9 +84,9 @@ data class Notification(
|
||||||
@SerialName("createdAt")
|
@SerialName("createdAt")
|
||||||
val createdAt: Int,
|
val createdAt: Int,
|
||||||
@SerialName("media")
|
@SerialName("media")
|
||||||
val media: ani.dantotsu.connections.anilist.api.Media? = null,
|
val media: Media? = null,
|
||||||
@SerialName("user")
|
@SerialName("user")
|
||||||
val user: ani.dantotsu.connections.anilist.api.User? = null,
|
val user: User? = null,
|
||||||
@SerialName("message")
|
@SerialName("message")
|
||||||
val message: MessageActivity? = null,
|
val message: MessageActivity? = null,
|
||||||
@SerialName("activity")
|
@SerialName("activity")
|
||||||
|
|
|
@ -355,7 +355,7 @@ class NovelDownloaderService : Service() {
|
||||||
private fun saveMediaInfo(task: DownloadTask) {
|
private fun saveMediaInfo(task: DownloadTask) {
|
||||||
launchIO {
|
launchIO {
|
||||||
val directory =
|
val directory =
|
||||||
DownloadsManager.getSubDirectory(
|
getSubDirectory(
|
||||||
this@NovelDownloaderService,
|
this@NovelDownloaderService,
|
||||||
MediaType.NOVEL,
|
MediaType.NOVEL,
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -101,7 +101,7 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
view.context,
|
view.context,
|
||||||
Intent(view.context, ProfileActivity::class.java)
|
Intent(view.context, ProfileActivity::class.java)
|
||||||
.putExtra("userId", Anilist.userid),null
|
.putExtra("userId", Anilist.userid), null
|
||||||
)
|
)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,8 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||||
trendingBinding.searchBar.performClick()
|
trendingBinding.searchBar.performClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
trendingBinding.notificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
|
trendingBinding.notificationCount.visibility =
|
||||||
|
if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
|
||||||
trendingBinding.notificationCount.text = Anilist.unreadNotificationCount.toString()
|
trendingBinding.notificationCount.text = Anilist.unreadNotificationCount.toString()
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
|
@ -167,7 +168,8 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||||
trendingBinding.trendingProgressBar.visibility = View.GONE
|
trendingBinding.trendingProgressBar.visibility = View.GONE
|
||||||
trendingBinding.trendingViewPager.adapter = adaptor
|
trendingBinding.trendingViewPager.adapter = adaptor
|
||||||
trendingBinding.trendingViewPager.offscreenPageLimit = 3
|
trendingBinding.trendingViewPager.offscreenPageLimit = 3
|
||||||
trendingBinding.trendingViewPager.getChildAt(0).overScrollMode = RecyclerView.OVER_SCROLL_NEVER
|
trendingBinding.trendingViewPager.getChildAt(0).overScrollMode =
|
||||||
|
RecyclerView.OVER_SCROLL_NEVER
|
||||||
trendingBinding.trendingViewPager.setPageTransformer(MediaPageTransformer())
|
trendingBinding.trendingViewPager.setPageTransformer(MediaPageTransformer())
|
||||||
trendHandler = Handler(Looper.getMainLooper())
|
trendHandler = Handler(Looper.getMainLooper())
|
||||||
trendRun = Runnable {
|
trendRun = Runnable {
|
||||||
|
@ -195,7 +197,7 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateRecent(adaptor: MediaAdaptor) {
|
fun updateRecent(adaptor: MediaAdaptor) {
|
||||||
binding.apply{
|
binding.apply {
|
||||||
init(
|
init(
|
||||||
adaptor,
|
adaptor,
|
||||||
animeUpdatedRecyclerView,
|
animeUpdatedRecyclerView,
|
||||||
|
@ -210,8 +212,9 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateMovies(adaptor: MediaAdaptor) {
|
fun updateMovies(adaptor: MediaAdaptor) {
|
||||||
binding.apply{
|
binding.apply {
|
||||||
init(
|
init(
|
||||||
adaptor,
|
adaptor,
|
||||||
animeMoviesRecyclerView,
|
animeMoviesRecyclerView,
|
||||||
|
@ -222,7 +225,7 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateTopRated(adaptor: MediaAdaptor) {
|
fun updateTopRated(adaptor: MediaAdaptor) {
|
||||||
binding.apply{
|
binding.apply {
|
||||||
init(
|
init(
|
||||||
adaptor,
|
adaptor,
|
||||||
animeTopRatedRecyclerView,
|
animeTopRatedRecyclerView,
|
||||||
|
@ -231,8 +234,9 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateMostFav(adaptor: MediaAdaptor) {
|
fun updateMostFav(adaptor: MediaAdaptor) {
|
||||||
binding.apply{
|
binding.apply {
|
||||||
init(
|
init(
|
||||||
adaptor,
|
adaptor,
|
||||||
animeMostFavRecyclerView,
|
animeMostFavRecyclerView,
|
||||||
|
@ -241,7 +245,8 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun init(adaptor: MediaAdaptor,recyclerView: RecyclerView, progress: View, title: View){
|
|
||||||
|
fun init(adaptor: MediaAdaptor, recyclerView: RecyclerView, progress: View, title: View) {
|
||||||
progress.visibility = View.GONE
|
progress.visibility = View.GONE
|
||||||
recyclerView.adapter = adaptor
|
recyclerView.adapter = adaptor
|
||||||
recyclerView.layoutManager =
|
recyclerView.layoutManager =
|
||||||
|
@ -256,6 +261,7 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||||
recyclerView.layoutAnimation =
|
recyclerView.layoutAnimation =
|
||||||
LayoutAnimationController(setSlideIn(), 0.25f)
|
LayoutAnimationController(setSlideIn(), 0.25f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateAvatar() {
|
fun updateAvatar() {
|
||||||
if (Anilist.avatar != null && ready.value == true) {
|
if (Anilist.avatar != null && ready.value == true) {
|
||||||
trendingBinding.userAvatar.loadImage(Anilist.avatar)
|
trendingBinding.userAvatar.loadImage(Anilist.avatar)
|
||||||
|
|
|
@ -81,7 +81,10 @@ class HomeFragment : Fragment() {
|
||||||
binding.homeUserChaptersRead.text = Anilist.chapterRead.toString()
|
binding.homeUserChaptersRead.text = Anilist.chapterRead.toString()
|
||||||
binding.homeUserAvatar.loadImage(Anilist.avatar)
|
binding.homeUserAvatar.loadImage(Anilist.avatar)
|
||||||
val bannerAnimations: Boolean = PrefManager.getVal(PrefName.BannerAnimations)
|
val bannerAnimations: Boolean = PrefManager.getVal(PrefName.BannerAnimations)
|
||||||
blurImage(if (bannerAnimations) binding.homeUserBg else binding.homeUserBgNoKen, Anilist.bg)
|
blurImage(
|
||||||
|
if (bannerAnimations) binding.homeUserBg else binding.homeUserBgNoKen,
|
||||||
|
Anilist.bg
|
||||||
|
)
|
||||||
binding.homeUserDataProgressBar.visibility = View.GONE
|
binding.homeUserDataProgressBar.visibility = View.GONE
|
||||||
binding.homeNotificationCount.isVisible = Anilist.unreadNotificationCount > 0
|
binding.homeNotificationCount.isVisible = Anilist.unreadNotificationCount > 0
|
||||||
binding.homeNotificationCount.text = Anilist.unreadNotificationCount.toString()
|
binding.homeNotificationCount.text = Anilist.unreadNotificationCount.toString()
|
||||||
|
@ -128,7 +131,7 @@ class HomeFragment : Fragment() {
|
||||||
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
requireContext(), Intent(requireContext(), ProfileActivity::class.java)
|
requireContext(), Intent(requireContext(), ProfileActivity::class.java)
|
||||||
.putExtra("userId", Anilist.userid),null
|
.putExtra("userId", Anilist.userid), null
|
||||||
)
|
)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -376,6 +379,7 @@ class HomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
if (!model.loaded) Refresh.activity[1]!!.postValue(true)
|
if (!model.loaded) Refresh.activity[1]!!.postValue(true)
|
||||||
if (_binding != null) {
|
if (_binding != null) {
|
||||||
|
|
|
@ -172,7 +172,13 @@ class MangaFragment : Fragment() {
|
||||||
}
|
}
|
||||||
model.getPopularManhwa().observe(viewLifecycleOwner) {
|
model.getPopularManhwa().observe(viewLifecycleOwner) {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
mangaPageAdapter.updateTrendingManhwa(MediaAdaptor(0, it, requireActivity()))
|
mangaPageAdapter.updateTrendingManhwa(
|
||||||
|
MediaAdaptor(
|
||||||
|
0,
|
||||||
|
it,
|
||||||
|
requireActivity()
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
model.getTopRated().observe(viewLifecycleOwner) {
|
model.getTopRated().observe(viewLifecycleOwner) {
|
||||||
|
|
|
@ -101,7 +101,7 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
view.context,
|
view.context,
|
||||||
Intent(view.context, ProfileActivity::class.java)
|
Intent(view.context, ProfileActivity::class.java)
|
||||||
.putExtra("userId", Anilist.userid),null
|
.putExtra("userId", Anilist.userid), null
|
||||||
)
|
)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,8 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||||
trendingBinding.trendingProgressBar.visibility = View.GONE
|
trendingBinding.trendingProgressBar.visibility = View.GONE
|
||||||
trendingBinding.trendingViewPager.adapter = adaptor
|
trendingBinding.trendingViewPager.adapter = adaptor
|
||||||
trendingBinding.trendingViewPager.offscreenPageLimit = 3
|
trendingBinding.trendingViewPager.offscreenPageLimit = 3
|
||||||
trendingBinding.trendingViewPager.getChildAt(0).overScrollMode = RecyclerView.OVER_SCROLL_NEVER
|
trendingBinding.trendingViewPager.getChildAt(0).overScrollMode =
|
||||||
|
RecyclerView.OVER_SCROLL_NEVER
|
||||||
trendingBinding.trendingViewPager.setPageTransformer(MediaPageTransformer())
|
trendingBinding.trendingViewPager.setPageTransformer(MediaPageTransformer())
|
||||||
trendHandler = Handler(Looper.getMainLooper())
|
trendHandler = Handler(Looper.getMainLooper())
|
||||||
trendRun = Runnable {
|
trendRun = Runnable {
|
||||||
|
@ -191,6 +192,7 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateTrendingManhwa(adaptor: MediaAdaptor) {
|
fun updateTrendingManhwa(adaptor: MediaAdaptor) {
|
||||||
binding.apply {
|
binding.apply {
|
||||||
init(
|
init(
|
||||||
|
@ -201,6 +203,7 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateNovel(adaptor: MediaAdaptor) {
|
fun updateNovel(adaptor: MediaAdaptor) {
|
||||||
binding.apply {
|
binding.apply {
|
||||||
init(
|
init(
|
||||||
|
@ -212,6 +215,7 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateTopRated(adaptor: MediaAdaptor) {
|
fun updateTopRated(adaptor: MediaAdaptor) {
|
||||||
binding.apply {
|
binding.apply {
|
||||||
init(
|
init(
|
||||||
|
@ -222,6 +226,7 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateMostFav(adaptor: MediaAdaptor) {
|
fun updateMostFav(adaptor: MediaAdaptor) {
|
||||||
binding.apply {
|
binding.apply {
|
||||||
init(
|
init(
|
||||||
|
@ -234,7 +239,8 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
|
||||||
mangaPopular.startAnimation(setSlideUp())
|
mangaPopular.startAnimation(setSlideUp())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun init(adaptor: MediaAdaptor,recyclerView: RecyclerView, progress: View, title: View){
|
|
||||||
|
fun init(adaptor: MediaAdaptor, recyclerView: RecyclerView, progress: View, title: View) {
|
||||||
progress.visibility = View.GONE
|
progress.visibility = View.GONE
|
||||||
recyclerView.adapter = adaptor
|
recyclerView.adapter = adaptor
|
||||||
recyclerView.layoutManager =
|
recyclerView.layoutManager =
|
||||||
|
|
|
@ -95,8 +95,10 @@ class AuthorActivity : AppCompatActivity() {
|
||||||
|
|
||||||
binding.charactersRecycler.visibility = View.VISIBLE
|
binding.charactersRecycler.visibility = View.VISIBLE
|
||||||
binding.charactersText.visibility = View.VISIBLE
|
binding.charactersText.visibility = View.VISIBLE
|
||||||
binding.charactersRecycler.adapter = CharacterAdapter(author!!.character ?: arrayListOf())
|
binding.charactersRecycler.adapter =
|
||||||
binding.charactersRecycler.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
|
CharacterAdapter(author!!.character ?: arrayListOf())
|
||||||
|
binding.charactersRecycler.layoutManager =
|
||||||
|
LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
|
||||||
if (author!!.character.isNullOrEmpty()) {
|
if (author!!.character.isNullOrEmpty()) {
|
||||||
binding.charactersRecycler.visibility = View.GONE
|
binding.charactersRecycler.visibility = View.GONE
|
||||||
binding.charactersText.visibility = View.GONE
|
binding.charactersText.visibility = View.GONE
|
||||||
|
@ -108,7 +110,7 @@ class AuthorActivity : AppCompatActivity() {
|
||||||
if (it) {
|
if (it) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
if (author != null)
|
if (author != null)
|
||||||
withContext(Dispatchers.IO) { model.loadAuthor(author!!)}
|
withContext(Dispatchers.IO) { model.loadAuthor(author!!) }
|
||||||
live.postValue(false)
|
live.postValue(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ class AuthorAdapter(
|
||||||
return AuthorViewHolder(binding)
|
return AuthorViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder:AuthorViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: AuthorViewHolder, position: Int) {
|
||||||
val binding = holder.binding
|
val binding = holder.binding
|
||||||
setAnimation(binding.root.context, holder.binding.root)
|
setAnimation(binding.root.context, holder.binding.root)
|
||||||
val author = authorList[position]
|
val author = authorList[position]
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package ani.dantotsu.media
|
package ani.dantotsu.media
|
||||||
|
|
||||||
import ani.dantotsu.connections.anilist.api.FuzzyDate
|
import ani.dantotsu.connections.anilist.api.FuzzyDate
|
||||||
import ani.dantotsu.connections.anilist.api.Query
|
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
data class Character(
|
data class Character(
|
||||||
|
|
|
@ -95,7 +95,8 @@ class CharacterDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChang
|
||||||
}
|
}
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
character.isFav = Anilist.query.isUserFav(AnilistMutations.FavType.CHARACTER, character.id)
|
character.isFav =
|
||||||
|
Anilist.query.isUserFav(AnilistMutations.FavType.CHARACTER, character.id)
|
||||||
}
|
}
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
binding.characterFav.setImageResource(
|
binding.characterFav.setImageResource(
|
||||||
|
|
|
@ -29,8 +29,14 @@ class CharacterDetailsAdapter(private val character: Character, private val acti
|
||||||
"${currActivity()!!.getString(R.string.birthday)} ${character.dateOfBirth.toString()}" else "") +
|
"${currActivity()!!.getString(R.string.birthday)} ${character.dateOfBirth.toString()}" else "") +
|
||||||
(if (character.gender != "null")
|
(if (character.gender != "null")
|
||||||
currActivity()!!.getString(R.string.gender) + " " + when (character.gender) {
|
currActivity()!!.getString(R.string.gender) + " " + when (character.gender) {
|
||||||
currActivity()!!.getString(R.string.male) -> currActivity()!!.getString(R.string.male)
|
currActivity()!!.getString(R.string.male) -> currActivity()!!.getString(
|
||||||
currActivity()!!.getString(R.string.female) -> currActivity()!!.getString(R.string.female)
|
R.string.male
|
||||||
|
)
|
||||||
|
|
||||||
|
currActivity()!!.getString(R.string.female) -> currActivity()!!.getString(
|
||||||
|
R.string.female
|
||||||
|
)
|
||||||
|
|
||||||
else -> character.gender
|
else -> character.gender
|
||||||
} else "") + "\n" + character.description
|
} else "") + "\n" + character.description
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ data class Media(
|
||||||
startDate = apiMedia.startDate,
|
startDate = apiMedia.startDate,
|
||||||
endDate = apiMedia.endDate,
|
endDate = apiMedia.endDate,
|
||||||
favourites = apiMedia.favourites,
|
favourites = apiMedia.favourites,
|
||||||
timeUntilAiring = apiMedia.nextAiringEpisode?.timeUntilAiring?.let { it.toLong() * 1000},
|
timeUntilAiring = apiMedia.nextAiringEpisode?.timeUntilAiring?.let { it.toLong() * 1000 },
|
||||||
anime = if (apiMedia.type == MediaType.ANIME) Anime(
|
anime = if (apiMedia.type == MediaType.ANIME) Anime(
|
||||||
totalEpisodes = apiMedia.episodes,
|
totalEpisodes = apiMedia.episodes,
|
||||||
nextAiringEpisode = apiMedia.nextAiringEpisode?.episode?.minus(1)
|
nextAiringEpisode = apiMedia.nextAiringEpisode?.episode?.minus(1)
|
||||||
|
@ -115,7 +115,8 @@ data class Media(
|
||||||
this.userScore = mediaList.score?.toInt() ?: 0
|
this.userScore = mediaList.score?.toInt() ?: 0
|
||||||
this.userStatus = mediaList.status?.toString()
|
this.userStatus = mediaList.status?.toString()
|
||||||
this.userUpdatedAt = mediaList.updatedAt?.toLong()
|
this.userUpdatedAt = mediaList.updatedAt?.toLong()
|
||||||
this.genres = mediaList.media?.genres?.toMutableList() as? ArrayList<String>? ?: arrayListOf()
|
this.genres =
|
||||||
|
mediaList.media?.genres?.toMutableList() as? ArrayList<String>? ?: arrayListOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(mediaEdge: MediaEdge) : this(mediaEdge.node!!) {
|
constructor(mediaEdge: MediaEdge) : this(mediaEdge.node!!) {
|
||||||
|
|
|
@ -149,14 +149,22 @@ class MediaAdaptor(
|
||||||
(if (media.userScore != 0) R.drawable.item_user_score else R.drawable.item_score)
|
(if (media.userScore != 0) R.drawable.item_user_score else R.drawable.item_score)
|
||||||
)
|
)
|
||||||
if (media.anime != null) {
|
if (media.anime != null) {
|
||||||
val itemTotal = " " + if ((media.anime.totalEpisodes ?: 0) != 1) currActivity()!!.getString(R.string.episode_plural) else currActivity()!!.getString(R.string.episode_singular)
|
val itemTotal = " " + if ((media.anime.totalEpisodes
|
||||||
|
?: 0) != 1
|
||||||
|
) currActivity()!!.getString(R.string.episode_plural) else currActivity()!!.getString(
|
||||||
|
R.string.episode_singular
|
||||||
|
)
|
||||||
b.itemTotal.text = itemTotal
|
b.itemTotal.text = itemTotal
|
||||||
b.itemCompactTotal.text =
|
b.itemCompactTotal.text =
|
||||||
if (media.anime.nextAiringEpisode != null) (media.anime.nextAiringEpisode.toString() + " / " + (media.anime.totalEpisodes
|
if (media.anime.nextAiringEpisode != null) (media.anime.nextAiringEpisode.toString() + " / " + (media.anime.totalEpisodes
|
||||||
?: "??").toString()) else (media.anime.totalEpisodes
|
?: "??").toString()) else (media.anime.totalEpisodes
|
||||||
?: "??").toString()
|
?: "??").toString()
|
||||||
} else if (media.manga != null) {
|
} else if (media.manga != null) {
|
||||||
val itemTotal = " " + if ((media.manga.totalChapters ?: 0) != 1) currActivity()!!.getString(R.string.chapter_plural) else currActivity()!!.getString(R.string.chapter_singular)
|
val itemTotal = " " + if ((media.manga.totalChapters
|
||||||
|
?: 0) != 1
|
||||||
|
) currActivity()!!.getString(R.string.chapter_plural) else currActivity()!!.getString(
|
||||||
|
R.string.chapter_singular
|
||||||
|
)
|
||||||
b.itemTotal.text = itemTotal
|
b.itemTotal.text = itemTotal
|
||||||
b.itemCompactTotal.text = "${media.manga.totalChapters ?: "??"}"
|
b.itemCompactTotal.text = "${media.manga.totalChapters ?: "??"}"
|
||||||
}
|
}
|
||||||
|
@ -183,7 +191,10 @@ class MediaAdaptor(
|
||||||
AccelerateDecelerateInterpolator()
|
AccelerateDecelerateInterpolator()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
blurImage(if (bannerAnimations) b.itemCompactBanner else b.itemCompactBannerNoKen , media.banner ?: media.cover)
|
blurImage(
|
||||||
|
if (bannerAnimations) b.itemCompactBanner else b.itemCompactBannerNoKen,
|
||||||
|
media.banner ?: media.cover
|
||||||
|
)
|
||||||
b.itemCompactOngoing.isVisible =
|
b.itemCompactOngoing.isVisible =
|
||||||
media.status == currActivity()!!.getString(R.string.status_releasing)
|
media.status == currActivity()!!.getString(R.string.status_releasing)
|
||||||
b.itemCompactTitle.text = media.userPreferredName
|
b.itemCompactTitle.text = media.userPreferredName
|
||||||
|
@ -232,7 +243,10 @@ class MediaAdaptor(
|
||||||
AccelerateDecelerateInterpolator()
|
AccelerateDecelerateInterpolator()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
blurImage(if (bannerAnimations) b.itemCompactBanner else b.itemCompactBannerNoKen , media.banner ?: media.cover)
|
blurImage(
|
||||||
|
if (bannerAnimations) b.itemCompactBanner else b.itemCompactBannerNoKen,
|
||||||
|
media.banner ?: media.cover
|
||||||
|
)
|
||||||
b.itemCompactOngoing.isVisible =
|
b.itemCompactOngoing.isVisible =
|
||||||
media.status == currActivity()!!.getString(R.string.status_releasing)
|
media.status == currActivity()!!.getString(R.string.status_releasing)
|
||||||
b.itemCompactTitle.text = media.userPreferredName
|
b.itemCompactTitle.text = media.userPreferredName
|
||||||
|
|
|
@ -109,7 +109,9 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
// Ui init
|
// Ui init
|
||||||
|
|
||||||
initActivity(this)
|
initActivity(this)
|
||||||
binding.mediaViewPager.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin = navBarHeight }
|
binding.mediaViewPager.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
bottomMargin = navBarHeight
|
||||||
|
}
|
||||||
val oldMargin = binding.mediaViewPager.marginBottom
|
val oldMargin = binding.mediaViewPager.marginBottom
|
||||||
AndroidBug5497Workaround.assistActivity(this) {
|
AndroidBug5497Workaround.assistActivity(this) {
|
||||||
if (it) {
|
if (it) {
|
||||||
|
@ -125,9 +127,11 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val navBarRightMargin = if (resources.configuration.orientation ==
|
val navBarRightMargin = if (resources.configuration.orientation ==
|
||||||
Configuration.ORIENTATION_LANDSCAPE) navBarHeight else 0
|
Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
) navBarHeight else 0
|
||||||
val navBarBottomMargin = if (resources.configuration.orientation ==
|
val navBarBottomMargin = if (resources.configuration.orientation ==
|
||||||
Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
|
Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
) 0 else navBarHeight
|
||||||
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
rightMargin = navBarRightMargin
|
rightMargin = navBarRightMargin
|
||||||
bottomMargin = navBarBottomMargin
|
bottomMargin = navBarBottomMargin
|
||||||
|
@ -345,7 +349,13 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
adult = media.isAdult
|
adult = media.isAdult
|
||||||
if (media.anime != null) {
|
if (media.anime != null) {
|
||||||
viewPager.adapter =
|
viewPager.adapter =
|
||||||
ViewPagerAdapter(supportFragmentManager, lifecycle, SupportedMedia.ANIME, media, intent.getIntExtra("commentId", -1))
|
ViewPagerAdapter(
|
||||||
|
supportFragmentManager,
|
||||||
|
lifecycle,
|
||||||
|
SupportedMedia.ANIME,
|
||||||
|
media,
|
||||||
|
intent.getIntExtra("commentId", -1)
|
||||||
|
)
|
||||||
} else if (media.manga != null) {
|
} else if (media.manga != null) {
|
||||||
viewPager.adapter = ViewPagerAdapter(
|
viewPager.adapter = ViewPagerAdapter(
|
||||||
supportFragmentManager,
|
supportFragmentManager,
|
||||||
|
@ -368,7 +378,8 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
} else {
|
} else {
|
||||||
navBar.createTab(R.drawable.ic_round_import_contacts_24, R.string.read, R.id.read)
|
navBar.createTab(R.drawable.ic_round_import_contacts_24, R.string.read, R.id.read)
|
||||||
}
|
}
|
||||||
val commentTab = navBar.createTab(R.drawable.ic_round_comment_24, R.string.comments, R.id.comment)
|
val commentTab =
|
||||||
|
navBar.createTab(R.drawable.ic_round_comment_24, R.string.comments, R.id.comment)
|
||||||
navBar.addTab(infoTab)
|
navBar.addTab(infoTab)
|
||||||
navBar.addTab(watchTab)
|
navBar.addTab(watchTab)
|
||||||
navBar.addTab(commentTab)
|
navBar.addTab(commentTab)
|
||||||
|
@ -412,10 +423,12 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
super.onConfigurationChanged(newConfig)
|
super.onConfigurationChanged(newConfig)
|
||||||
val rightMargin = if (resources.configuration.orientation ==
|
val rightMargin = if (resources.configuration.orientation ==
|
||||||
Configuration.ORIENTATION_LANDSCAPE) navBarHeight else 0
|
Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
) navBarHeight else 0
|
||||||
val bottomMargin = if (resources.configuration.orientation ==
|
val bottomMargin = if (resources.configuration.orientation ==
|
||||||
Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
|
Configuration.ORIENTATION_LANDSCAPE
|
||||||
val params : ViewGroup.MarginLayoutParams =
|
) 0 else navBarHeight
|
||||||
|
val params: ViewGroup.MarginLayoutParams =
|
||||||
navBar.layoutParams as ViewGroup.MarginLayoutParams
|
navBar.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
params.updateMargins(right = rightMargin, bottom = bottomMargin)
|
params.updateMargins(right = rightMargin, bottom = bottomMargin)
|
||||||
}
|
}
|
||||||
|
@ -448,6 +461,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
|
||||||
SupportedMedia.MANGA -> MangaReadFragment()
|
SupportedMedia.MANGA -> MangaReadFragment()
|
||||||
SupportedMedia.NOVEL -> NovelReadFragment()
|
SupportedMedia.NOVEL -> NovelReadFragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
2 -> {
|
2 -> {
|
||||||
val fragment = CommentsFragment()
|
val fragment = CommentsFragment()
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
|
|
|
@ -56,9 +56,11 @@ class MediaDetailsViewModel : ViewModel() {
|
||||||
media.anime != null -> {
|
media.anime != null -> {
|
||||||
AnimeSources.list.size - 1
|
AnimeSources.list.size - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
media.format == "MANGA" || media.format == "ONE_SHOT" -> {
|
media.format == "MANGA" || media.format == "ONE_SHOT" -> {
|
||||||
MangaSources.list.size - 1
|
MangaSources.list.size - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
NovelSources.list.size - 1
|
NovelSources.list.size - 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,8 @@ class MediaInfoFragment : Fragment() {
|
||||||
}
|
}
|
||||||
binding.mediaInfoDurationContainer.visibility = View.VISIBLE
|
binding.mediaInfoDurationContainer.visibility = View.VISIBLE
|
||||||
binding.mediaInfoSeasonContainer.visibility = View.VISIBLE
|
binding.mediaInfoSeasonContainer.visibility = View.VISIBLE
|
||||||
val seasonInfo = "${(media.anime.season ?: "??")} ${(media.anime.seasonYear ?: "??")}"
|
val seasonInfo =
|
||||||
|
"${(media.anime.season ?: "??")} ${(media.anime.seasonYear ?: "??")}"
|
||||||
binding.mediaInfoSeason.text = seasonInfo
|
binding.mediaInfoSeason.text = seasonInfo
|
||||||
|
|
||||||
if (media.anime.mainStudio != null) {
|
if (media.anime.mainStudio != null) {
|
||||||
|
@ -213,7 +214,8 @@ class MediaInfoFragment : Fragment() {
|
||||||
(media.description ?: "null").replace("\\n", "<br>").replace("\\\"", "\""),
|
(media.description ?: "null").replace("\\n", "<br>").replace("\\\"", "\""),
|
||||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||||
)
|
)
|
||||||
val infoDesc = tripleTab + if (desc.toString() != "null") desc else getString(R.string.no_description_available)
|
val infoDesc =
|
||||||
|
tripleTab + if (desc.toString() != "null") desc else getString(R.string.no_description_available)
|
||||||
binding.mediaInfoDescription.text = infoDesc
|
binding.mediaInfoDescription.text = infoDesc
|
||||||
|
|
||||||
binding.mediaInfoDescription.setOnClickListener {
|
binding.mediaInfoDescription.setOnClickListener {
|
||||||
|
@ -570,7 +572,7 @@ class MediaInfoFragment : Fragment() {
|
||||||
parent.addView(root)
|
parent.addView(root)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!media.users.isNullOrEmpty() && !offline){
|
if (!media.users.isNullOrEmpty() && !offline) {
|
||||||
ItemTitleRecyclerBinding.inflate(
|
ItemTitleRecyclerBinding.inflate(
|
||||||
LayoutInflater.from(context),
|
LayoutInflater.from(context),
|
||||||
parent,
|
parent,
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package ani.dantotsu.media
|
package ani.dantotsu.media
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
|
@ -4,7 +4,7 @@ interface Type {
|
||||||
fun asText(): String
|
fun asText(): String
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class MediaType: Type {
|
enum class MediaType : Type {
|
||||||
ANIME,
|
ANIME,
|
||||||
MANGA,
|
MANGA,
|
||||||
NOVEL;
|
NOVEL;
|
||||||
|
@ -18,18 +18,20 @@ enum class MediaType: Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromText(string : String): MediaType? {
|
fun fromText(string: String): MediaType? {
|
||||||
return when (string) {
|
return when (string) {
|
||||||
"Anime" -> ANIME
|
"Anime" -> ANIME
|
||||||
"Manga" -> MANGA
|
"Manga" -> MANGA
|
||||||
"Novel" -> NOVEL
|
"Novel" -> NOVEL
|
||||||
else -> { null }
|
else -> {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class AddonType: Type {
|
enum class AddonType : Type {
|
||||||
TORRENT,
|
TORRENT,
|
||||||
DOWNLOAD;
|
DOWNLOAD;
|
||||||
|
|
||||||
|
@ -41,11 +43,13 @@ enum class AddonType: Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromText(string : String): AddonType? {
|
fun fromText(string: String): AddonType? {
|
||||||
return when (string) {
|
return when (string) {
|
||||||
"Torrent" -> TORRENT
|
"Torrent" -> TORRENT
|
||||||
"Download" -> DOWNLOAD
|
"Download" -> DOWNLOAD
|
||||||
else -> { null }
|
else -> {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,8 +78,10 @@ class SearchActivity : AppCompatActivity() {
|
||||||
source = intent.getStringExtra("source"),
|
source = intent.getStringExtra("source"),
|
||||||
countryOfOrigin = intent.getStringExtra("country"),
|
countryOfOrigin = intent.getStringExtra("country"),
|
||||||
season = intent.getStringExtra("season"),
|
season = intent.getStringExtra("season"),
|
||||||
seasonYear = if (intent.getStringExtra("type") == "ANIME") intent.getStringExtra("seasonYear")?.toIntOrNull() else null,
|
seasonYear = if (intent.getStringExtra("type") == "ANIME") intent.getStringExtra("seasonYear")
|
||||||
startYear = if (intent.getStringExtra("type") == "MANGA") intent.getStringExtra("seasonYear")?.toIntOrNull() else null,
|
?.toIntOrNull() else null,
|
||||||
|
startYear = if (intent.getStringExtra("type") == "MANGA") intent.getStringExtra("seasonYear")
|
||||||
|
?.toIntOrNull() else null,
|
||||||
results = mutableListOf(),
|
results = mutableListOf(),
|
||||||
hasNextPage = false
|
hasNextPage = false
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,7 +13,6 @@ import android.view.animation.AlphaAnimation
|
||||||
import android.view.animation.Animation
|
import android.view.animation.Animation
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
|
@ -60,6 +59,7 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
||||||
}
|
}
|
||||||
binding.filterTextView.setCompoundDrawablesWithIntrinsicBounds(filterDrawable, 0, 0, 0)
|
binding.filterTextView.setCompoundDrawablesWithIntrinsicBounds(filterDrawable, 0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchHeaderViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchHeaderViewHolder {
|
||||||
val binding =
|
val binding =
|
||||||
ItemSearchHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
ItemSearchHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
@ -129,36 +129,42 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
||||||
activity.search()
|
activity.search()
|
||||||
updateFilterTextViewDrawable()
|
updateFilterTextViewDrawable()
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.sort_by_popular -> {
|
R.id.sort_by_popular -> {
|
||||||
activity.result.sort = Anilist.sortBy[1]
|
activity.result.sort = Anilist.sortBy[1]
|
||||||
activity.updateChips.invoke()
|
activity.updateChips.invoke()
|
||||||
activity.search()
|
activity.search()
|
||||||
updateFilterTextViewDrawable()
|
updateFilterTextViewDrawable()
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.sort_by_trending -> {
|
R.id.sort_by_trending -> {
|
||||||
activity.result.sort = Anilist.sortBy[2]
|
activity.result.sort = Anilist.sortBy[2]
|
||||||
activity.updateChips.invoke()
|
activity.updateChips.invoke()
|
||||||
activity.search()
|
activity.search()
|
||||||
updateFilterTextViewDrawable()
|
updateFilterTextViewDrawable()
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.sort_by_recent -> {
|
R.id.sort_by_recent -> {
|
||||||
activity.result.sort = Anilist.sortBy[3]
|
activity.result.sort = Anilist.sortBy[3]
|
||||||
activity.updateChips.invoke()
|
activity.updateChips.invoke()
|
||||||
activity.search()
|
activity.search()
|
||||||
updateFilterTextViewDrawable()
|
updateFilterTextViewDrawable()
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.sort_by_a_z -> {
|
R.id.sort_by_a_z -> {
|
||||||
activity.result.sort = Anilist.sortBy[4]
|
activity.result.sort = Anilist.sortBy[4]
|
||||||
activity.updateChips.invoke()
|
activity.updateChips.invoke()
|
||||||
activity.search()
|
activity.search()
|
||||||
updateFilterTextViewDrawable()
|
updateFilterTextViewDrawable()
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.sort_by_z_a -> {
|
R.id.sort_by_z_a -> {
|
||||||
activity.result.sort = Anilist.sortBy[5]
|
activity.result.sort = Anilist.sortBy[5]
|
||||||
activity.updateChips.invoke()
|
activity.updateChips.invoke()
|
||||||
activity.search()
|
activity.search()
|
||||||
updateFilterTextViewDrawable()
|
updateFilterTextViewDrawable()
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.sort_by_pure_pain -> {
|
R.id.sort_by_pure_pain -> {
|
||||||
activity.result.sort = Anilist.sortBy[6]
|
activity.result.sort = Anilist.sortBy[6]
|
||||||
activity.updateChips.invoke()
|
activity.updateChips.invoke()
|
||||||
|
@ -325,7 +331,10 @@ class SearchAdapter(private val activity: SearchActivity, private val type: Stri
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SearchChipAdapter(val activity: SearchActivity, private val searchAdapter: SearchAdapter) :
|
class SearchChipAdapter(
|
||||||
|
val activity: SearchActivity,
|
||||||
|
private val searchAdapter: SearchAdapter
|
||||||
|
) :
|
||||||
RecyclerView.Adapter<SearchChipAdapter.SearchChipViewHolder>() {
|
RecyclerView.Adapter<SearchChipAdapter.SearchChipViewHolder>() {
|
||||||
private var chips = activity.result.toChipList()
|
private var chips = activity.result.toChipList()
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,8 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
||||||
setSortByFilterImage()
|
setSortByFilterImage()
|
||||||
|
|
||||||
binding.resetSearchFilter.setOnClickListener {
|
binding.resetSearchFilter.setOnClickListener {
|
||||||
val rotateAnimation = ObjectAnimator.ofFloat(binding.resetSearchFilter, "rotation", 180f, 540f)
|
val rotateAnimation =
|
||||||
|
ObjectAnimator.ofFloat(binding.resetSearchFilter, "rotation", 180f, 540f)
|
||||||
rotateAnimation.duration = 500
|
rotateAnimation.duration = 500
|
||||||
rotateAnimation.interpolator = AccelerateDecelerateInterpolator()
|
rotateAnimation.interpolator = AccelerateDecelerateInterpolator()
|
||||||
rotateAnimation.start()
|
rotateAnimation.start()
|
||||||
|
@ -113,7 +114,8 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.resetSearchFilter.setOnLongClickListener {
|
binding.resetSearchFilter.setOnLongClickListener {
|
||||||
val rotateAnimation = ObjectAnimator.ofFloat(binding.resetSearchFilter, "rotation", 180f, 540f)
|
val rotateAnimation =
|
||||||
|
ObjectAnimator.ofFloat(binding.resetSearchFilter, "rotation", 180f, 540f)
|
||||||
rotateAnimation.duration = 500
|
rotateAnimation.duration = 500
|
||||||
rotateAnimation.interpolator = AccelerateDecelerateInterpolator()
|
rotateAnimation.interpolator = AccelerateDecelerateInterpolator()
|
||||||
rotateAnimation.start()
|
rotateAnimation.start()
|
||||||
|
@ -125,8 +127,10 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
activity.result.apply {
|
activity.result.apply {
|
||||||
status = binding.searchStatus.text.toString().replace(" ", "_").ifBlank { null }
|
status =
|
||||||
source = binding.searchSource.text.toString().replace(" ", "_").ifBlank { null }
|
binding.searchStatus.text.toString().replace(" ", "_").ifBlank { null }
|
||||||
|
source =
|
||||||
|
binding.searchSource.text.toString().replace(" ", "_").ifBlank { null }
|
||||||
format = binding.searchFormat.text.toString().ifBlank { null }
|
format = binding.searchFormat.text.toString().ifBlank { null }
|
||||||
season = binding.searchSeason.text.toString().ifBlank { null }
|
season = binding.searchSeason.text.toString().ifBlank { null }
|
||||||
startYear = binding.searchYear.text.toString().toIntOrNull()
|
startYear = binding.searchYear.text.toString().toIntOrNull()
|
||||||
|
@ -206,21 +210,25 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
||||||
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_search_googlefonts)
|
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_search_googlefonts)
|
||||||
startBounceZoomAnimation(binding.countryFilter)
|
startBounceZoomAnimation(binding.countryFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.country_china -> {
|
R.id.country_china -> {
|
||||||
activity.result.countryOfOrigin = "CN"
|
activity.result.countryOfOrigin = "CN"
|
||||||
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_china_googlefonts)
|
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_china_googlefonts)
|
||||||
startBounceZoomAnimation(binding.countryFilter)
|
startBounceZoomAnimation(binding.countryFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.country_south_korea -> {
|
R.id.country_south_korea -> {
|
||||||
activity.result.countryOfOrigin = "KR"
|
activity.result.countryOfOrigin = "KR"
|
||||||
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_south_korea_googlefonts)
|
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_south_korea_googlefonts)
|
||||||
startBounceZoomAnimation(binding.countryFilter)
|
startBounceZoomAnimation(binding.countryFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.country_japan -> {
|
R.id.country_japan -> {
|
||||||
activity.result.countryOfOrigin = "JP"
|
activity.result.countryOfOrigin = "JP"
|
||||||
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_japan_googlefonts)
|
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_japan_googlefonts)
|
||||||
startBounceZoomAnimation(binding.countryFilter)
|
startBounceZoomAnimation(binding.countryFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.country_taiwan -> {
|
R.id.country_taiwan -> {
|
||||||
activity.result.countryOfOrigin = "TW"
|
activity.result.countryOfOrigin = "TW"
|
||||||
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_taiwan_googlefonts)
|
binding.countryFilter.setImageResource(R.drawable.ic_round_globe_taiwan_googlefonts)
|
||||||
|
@ -257,7 +265,8 @@ class SearchFilterBottomDialog : BottomSheetDialogFragment() {
|
||||||
binding.searchFilterCancel.setOnClickListener {
|
binding.searchFilterCancel.setOnClickListener {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
val format = if (activity.result.type == "ANIME") Anilist.animeStatus else Anilist.mangaStatus
|
val format =
|
||||||
|
if (activity.result.type == "ANIME") Anilist.animeStatus else Anilist.mangaStatus
|
||||||
binding.searchStatus.setText(activity.result.status?.replace("_", " "))
|
binding.searchStatus.setText(activity.result.status?.replace("_", " "))
|
||||||
binding.searchStatus.setAdapter(
|
binding.searchStatus.setAdapter(
|
||||||
ArrayAdapter(
|
ArrayAdapter(
|
||||||
|
|
|
@ -12,7 +12,6 @@ import kotlinx.coroutines.withContext
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class SubtitleDownloader {
|
class SubtitleDownloader {
|
||||||
|
|
||||||
|
|
|
@ -330,6 +330,7 @@ class AnimeWatchAdapter(
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val chipText = "${names[limit * (position)]} - ${names[last - 1]}"
|
val chipText = "${names[limit * (position)]} - ${names[last - 1]}"
|
||||||
chip.text = chipText
|
chip.text = chipText
|
||||||
chip.setTextColor(
|
chip.setTextColor(
|
||||||
|
@ -412,10 +413,12 @@ class AnimeWatchAdapter(
|
||||||
if (ep.filler) binding.itemEpisodeFillerView.visibility = View.VISIBLE
|
if (ep.filler) binding.itemEpisodeFillerView.visibility = View.VISIBLE
|
||||||
|
|
||||||
binding.animeSourceContinueText.text =
|
binding.animeSourceContinueText.text =
|
||||||
currActivity()!!.getString(R.string.continue_episode, ep.number, if (ep.filler)
|
currActivity()!!.getString(
|
||||||
|
R.string.continue_episode, ep.number, if (ep.filler)
|
||||||
currActivity()!!.getString(R.string.filler_tag)
|
currActivity()!!.getString(R.string.filler_tag)
|
||||||
else
|
else
|
||||||
"", cleanedTitle)
|
"", cleanedTitle
|
||||||
|
)
|
||||||
binding.animeSourceContinue.setOnClickListener {
|
binding.animeSourceContinue.setOnClickListener {
|
||||||
fragment.onEpisodeClick(continueEp)
|
fragment.onEpisodeClick(continueEp)
|
||||||
}
|
}
|
||||||
|
@ -441,11 +444,14 @@ class AnimeWatchAdapter(
|
||||||
if (!sourceFound && PrefManager.getVal(PrefName.SearchSources) && autoSelect) {
|
if (!sourceFound && PrefManager.getVal(PrefName.SearchSources) && autoSelect) {
|
||||||
if (binding.animeSource.adapter.count > media.selected!!.sourceIndex + 1) {
|
if (binding.animeSource.adapter.count > media.selected!!.sourceIndex + 1) {
|
||||||
val nextIndex = media.selected!!.sourceIndex + 1
|
val nextIndex = media.selected!!.sourceIndex + 1
|
||||||
binding.animeSource.setText(binding.animeSource.adapter
|
binding.animeSource.setText(
|
||||||
.getItem(nextIndex).toString(), false)
|
binding.animeSource.adapter
|
||||||
|
.getItem(nextIndex).toString(), false
|
||||||
|
)
|
||||||
fragment.onSourceChange(nextIndex).apply {
|
fragment.onSourceChange(nextIndex).apply {
|
||||||
binding.animeSourceTitle.text = showUserText
|
binding.animeSourceTitle.text = showUserText
|
||||||
showUserTextListener = { MainScope().launch { binding.animeSourceTitle.text = it } }
|
showUserTextListener =
|
||||||
|
{ MainScope().launch { binding.animeSourceTitle.text = it } }
|
||||||
binding.animeSourceDubbed.isChecked = selectDub
|
binding.animeSourceDubbed.isChecked = selectDub
|
||||||
binding.animeSourceDubbedCont.isVisible = isDubAvailableSeparately()
|
binding.animeSourceDubbedCont.isVisible = isDubAvailableSeparately()
|
||||||
setLanguageList(0, nextIndex)
|
setLanguageList(0, nextIndex)
|
||||||
|
|
|
@ -199,7 +199,8 @@ class AnimeWatchFragment : Fragment() {
|
||||||
ConcatAdapter(headerAdapter, episodeAdapter)
|
ConcatAdapter(headerAdapter, episodeAdapter)
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val offline = !isOnline(binding.root.context) || PrefManager.getVal(PrefName.OfflineMode)
|
val offline =
|
||||||
|
!isOnline(binding.root.context) || PrefManager.getVal(PrefName.OfflineMode)
|
||||||
if (offline) {
|
if (offline) {
|
||||||
media.selected!!.sourceIndex = model.watchSources!!.list.lastIndex
|
media.selected!!.sourceIndex = model.watchSources!!.list.lastIndex
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -486,12 +486,14 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
||||||
}
|
}
|
||||||
rotation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
rotation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
||||||
}
|
}
|
||||||
|
|
||||||
in 225..315 -> {
|
in 225..315 -> {
|
||||||
if (rotation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
|
if (rotation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
|
||||||
exoRotate.visibility = View.VISIBLE
|
exoRotate.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
rotation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
rotation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||||
}
|
}
|
||||||
|
|
||||||
in 315..360, in 0..45 -> {
|
in 315..360, in 0..45 -> {
|
||||||
if (rotation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
|
if (rotation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
|
||||||
exoRotate.visibility = View.VISIBLE
|
exoRotate.visibility = View.VISIBLE
|
||||||
|
@ -1396,7 +1398,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
||||||
subClick()
|
subClick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val sub: MutableList<MediaItem.SubtitleConfiguration> = emptyList<MediaItem.SubtitleConfiguration>().toMutableList()
|
val sub: MutableList<MediaItem.SubtitleConfiguration> =
|
||||||
|
emptyList<MediaItem.SubtitleConfiguration>().toMutableList()
|
||||||
ext.subtitles.forEach { subtitle ->
|
ext.subtitles.forEach { subtitle ->
|
||||||
val subtitleUrl = if (!hasExtSubtitles) video!!.file.url else subtitle.file.url
|
val subtitleUrl = if (!hasExtSubtitles) video!!.file.url else subtitle.file.url
|
||||||
//var localFile: String? = null
|
//var localFile: String? = null
|
||||||
|
@ -1865,7 +1868,10 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
||||||
exoPlayer.seekTo((new.interval.endTime * 1000).toLong())
|
exoPlayer.seekTo((new.interval.endTime * 1000).toLong())
|
||||||
skippedTimeStamps.add(new)
|
skippedTimeStamps.add(new)
|
||||||
}
|
}
|
||||||
if (PrefManager.getVal(PrefName.AutoSkipRecap) && new.skipType == "recap" && !skippedTimeStamps.contains(new)) {
|
if (PrefManager.getVal(PrefName.AutoSkipRecap) && new.skipType == "recap" && !skippedTimeStamps.contains(
|
||||||
|
new
|
||||||
|
)
|
||||||
|
) {
|
||||||
exoPlayer.seekTo((new.interval.endTime * 1000).toLong())
|
exoPlayer.seekTo((new.interval.endTime * 1000).toLong())
|
||||||
skippedTimeStamps.add(new)
|
skippedTimeStamps.add(new)
|
||||||
}
|
}
|
||||||
|
@ -1910,12 +1916,15 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
||||||
val audioTracks: ArrayList<Tracks.Group> = arrayListOf()
|
val audioTracks: ArrayList<Tracks.Group> = arrayListOf()
|
||||||
val subTracks: ArrayList<Tracks.Group> = arrayListOf(dummyTrack)
|
val subTracks: ArrayList<Tracks.Group> = arrayListOf(dummyTrack)
|
||||||
tracks.groups.forEach {
|
tracks.groups.forEach {
|
||||||
println("Track__: $it\nTrack__: ${it.length}\nTrack__: ${it.isSelected}\n" +
|
println(
|
||||||
"Track__: ${it.type}\nTrack__: ${it.mediaTrackGroup.id}")
|
"Track__: $it\nTrack__: ${it.length}\nTrack__: ${it.isSelected}\n" +
|
||||||
|
"Track__: ${it.type}\nTrack__: ${it.mediaTrackGroup.id}"
|
||||||
|
)
|
||||||
when (it.type) {
|
when (it.type) {
|
||||||
TRACK_TYPE_AUDIO -> {
|
TRACK_TYPE_AUDIO -> {
|
||||||
if (it.isSupported(true)) audioTracks.add(it)
|
if (it.isSupported(true)) audioTracks.add(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACK_TYPE_TEXT -> {
|
TRACK_TYPE_TEXT -> {
|
||||||
if (!hasExtSubtitles) {
|
if (!hasExtSubtitles) {
|
||||||
if (it.isSupported(true)) subTracks.add(it)
|
if (it.isSupported(true)) subTracks.add(it)
|
||||||
|
@ -1951,7 +1960,8 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
||||||
onSetTrackGroupOverride(dummyTrack, TRACK_TYPE_TEXT)
|
onSetTrackGroupOverride(dummyTrack, TRACK_TYPE_TEXT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> { }
|
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1966,6 +1976,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
||||||
isPlayerPlaying = true
|
isPlayerPlaying = true
|
||||||
sourceClick()
|
sourceClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
toast("Player Error ${error.errorCode} (${error.errorCodeName}) : ${error.message}")
|
toast("Player Error ${error.errorCode} (${error.errorCodeName}) : ${error.message}")
|
||||||
Injekt.get<CrashlyticsInterface>().logException(error)
|
Injekt.get<CrashlyticsInterface>().logException(error)
|
||||||
|
|
|
@ -24,6 +24,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import ani.dantotsu.BottomSheetDialogFragment
|
import ani.dantotsu.BottomSheetDialogFragment
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
|
import ani.dantotsu.addons.torrent.TorrentAddonManager
|
||||||
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||||
import ani.dantotsu.copyToClipboard
|
import ani.dantotsu.copyToClipboard
|
||||||
import ani.dantotsu.currActivity
|
import ani.dantotsu.currActivity
|
||||||
|
@ -32,7 +33,6 @@ import ani.dantotsu.databinding.ItemStreamBinding
|
||||||
import ani.dantotsu.databinding.ItemUrlBinding
|
import ani.dantotsu.databinding.ItemUrlBinding
|
||||||
import ani.dantotsu.download.DownloadedType
|
import ani.dantotsu.download.DownloadedType
|
||||||
import ani.dantotsu.download.video.Helper
|
import ani.dantotsu.download.video.Helper
|
||||||
import ani.dantotsu.addons.torrent.TorrentAddonManager
|
|
||||||
import ani.dantotsu.hideSystemBars
|
import ani.dantotsu.hideSystemBars
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.MediaDetailsViewModel
|
import ani.dantotsu.media.MediaDetailsViewModel
|
||||||
|
@ -233,11 +233,12 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private val externalPlayerResult = registerForActivityResult(
|
private val externalPlayerResult = registerForActivityResult(
|
||||||
ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { result: ActivityResult ->
|
||||||
Logger.log(result.data.toString())
|
Logger.log(result.data.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun exportMagnetIntent(episode: Episode, video: Video) : Intent {
|
private fun exportMagnetIntent(episode: Episode, video: Video): Intent {
|
||||||
val amnis = "com.amnis"
|
val amnis = "com.amnis"
|
||||||
return Intent(Intent.ACTION_VIEW).apply {
|
return Intent(Intent.ACTION_VIEW).apply {
|
||||||
component = ComponentName(amnis, "$amnis.gui.player.PlayerActivity")
|
component = ComponentName(amnis, "$amnis.gui.player.PlayerActivity")
|
||||||
|
@ -445,7 +446,11 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||||
SubtitleDownloader.downloadSubtitle(
|
SubtitleDownloader.downloadSubtitle(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
subtitleToDownload!!.file.url,
|
subtitleToDownload!!.file.url,
|
||||||
DownloadedType(media!!.mainName(), media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!!.number, MediaType.ANIME)
|
DownloadedType(
|
||||||
|
media!!.mainName(),
|
||||||
|
media!!.anime!!.episodes!![media!!.anime!!.selectedEpisode!!]!!.number,
|
||||||
|
MediaType.ANIME
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -477,7 +482,7 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||||
if (extractor.videos.size > episode.selectedVideo) extractor.videos[episode.selectedVideo] else null
|
if (extractor.videos.size > episode.selectedVideo) extractor.videos[episode.selectedVideo] else null
|
||||||
val subtitleNames = subtitles.map { it.language }
|
val subtitleNames = subtitles.map { it.language }
|
||||||
var subtitleToDownload: Subtitle? = null
|
var subtitleToDownload: Subtitle? = null
|
||||||
val activity = currActivity()?:requireActivity()
|
val activity = currActivity() ?: requireActivity()
|
||||||
if (subtitles.isNotEmpty()) {
|
if (subtitles.isNotEmpty()) {
|
||||||
val alertDialog = AlertDialog.Builder(context, R.style.MyPopup)
|
val alertDialog = AlertDialog.Builder(context, R.style.MyPopup)
|
||||||
.setTitle("Download Subtitle")
|
.setTitle("Download Subtitle")
|
||||||
|
@ -551,9 +556,13 @@ class SelectorDialogFragment : BottomSheetDialogFragment() {
|
||||||
if (video.format == VideoType.CONTAINER) {
|
if (video.format == VideoType.CONTAINER) {
|
||||||
binding.urlSize.isVisible = video.size != null
|
binding.urlSize.isVisible = video.size != null
|
||||||
// if video size is null or 0, show "Unknown Size" else show the size in MB
|
// if video size is null or 0, show "Unknown Size" else show the size in MB
|
||||||
val sizeText = getString(R.string.mb_size, "${if (video.extraNote != null) " : " else ""}${
|
val sizeText = getString(
|
||||||
if (video.size == 0.0) getString(R.string.size_unknown) else DecimalFormat("#.##").format(video.size ?: 0)
|
R.string.mb_size, "${if (video.extraNote != null) " : " else ""}${
|
||||||
}")
|
if (video.size == 0.0) getString(R.string.size_unknown) else DecimalFormat("#.##").format(
|
||||||
|
video.size ?: 0
|
||||||
|
)
|
||||||
|
}"
|
||||||
|
)
|
||||||
binding.urlSize.text = sizeText
|
binding.urlSize.text = sizeText
|
||||||
}
|
}
|
||||||
binding.urlNote.visibility = View.VISIBLE
|
binding.urlNote.visibility = View.VISIBLE
|
||||||
|
|
|
@ -67,7 +67,11 @@ class SubtitleDialogFragment : BottomSheetDialogFragment() {
|
||||||
binding.subtitleTitle.setText(R.string.none)
|
binding.subtitleTitle.setText(R.string.none)
|
||||||
model.getMedia().observe(viewLifecycleOwner) { media ->
|
model.getMedia().observe(viewLifecycleOwner) { media ->
|
||||||
val mediaID: Int = media.id
|
val mediaID: Int = media.id
|
||||||
val selSubs = PrefManager.getNullableCustomVal("subLang_${mediaID}", null, String::class.java)
|
val selSubs = PrefManager.getNullableCustomVal(
|
||||||
|
"subLang_${mediaID}",
|
||||||
|
null,
|
||||||
|
String::class.java
|
||||||
|
)
|
||||||
if (episode.selectedSubtitle != null && selSubs != "None") {
|
if (episode.selectedSubtitle != null && selSubs != "None") {
|
||||||
binding.root.setCardBackgroundColor(TRANSPARENT)
|
binding.root.setCardBackgroundColor(TRANSPARENT)
|
||||||
}
|
}
|
||||||
|
@ -107,7 +111,11 @@ class SubtitleDialogFragment : BottomSheetDialogFragment() {
|
||||||
model.getMedia().observe(viewLifecycleOwner) { media ->
|
model.getMedia().observe(viewLifecycleOwner) { media ->
|
||||||
val mediaID: Int = media.id
|
val mediaID: Int = media.id
|
||||||
val selSubs: String? =
|
val selSubs: String? =
|
||||||
PrefManager.getNullableCustomVal("subLang_${mediaID}", null, String::class.java)
|
PrefManager.getNullableCustomVal(
|
||||||
|
"subLang_${mediaID}",
|
||||||
|
null,
|
||||||
|
String::class.java
|
||||||
|
)
|
||||||
if (episode.selectedSubtitle != position - 1 && selSubs != subtitles[position - 1].language) {
|
if (episode.selectedSubtitle != position - 1 && selSubs != subtitles[position - 1].language) {
|
||||||
binding.root.setCardBackgroundColor(TRANSPARENT)
|
binding.root.setCardBackgroundColor(TRANSPARENT)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.media3.common.C.TRACK_TYPE_AUDIO
|
import androidx.media3.common.C.TRACK_TYPE_AUDIO
|
||||||
import androidx.media3.common.C.TrackType
|
import androidx.media3.common.C.TrackType
|
||||||
import androidx.media3.common.Tracks
|
import androidx.media3.common.Tracks
|
||||||
|
@ -20,7 +19,7 @@ import java.util.Locale
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
class TrackGroupDialogFragment(
|
class TrackGroupDialogFragment(
|
||||||
instance: ExoplayerView, trackGroups: ArrayList<Tracks.Group>, type : @TrackType Int
|
instance: ExoplayerView, trackGroups: ArrayList<Tracks.Group>, type: @TrackType Int
|
||||||
) : BottomSheetDialogFragment() {
|
) : BottomSheetDialogFragment() {
|
||||||
private var _binding: BottomSheetSubtitlesBinding? = null
|
private var _binding: BottomSheetSubtitlesBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
@ -70,21 +69,28 @@ class TrackGroupDialogFragment(
|
||||||
trackGroups[position].let { trackGroup ->
|
trackGroups[position].let { trackGroup ->
|
||||||
when (val language = trackGroup.getTrackFormat(0).language?.lowercase()) {
|
when (val language = trackGroup.getTrackFormat(0).language?.lowercase()) {
|
||||||
null -> {
|
null -> {
|
||||||
binding.subtitleTitle.text = getString(R.string.unknown_track, "Track $position")
|
binding.subtitleTitle.text =
|
||||||
|
getString(R.string.unknown_track, "Track $position")
|
||||||
}
|
}
|
||||||
|
|
||||||
"none" -> {
|
"none" -> {
|
||||||
binding.subtitleTitle.text = getString(R.string.disabled_track)
|
binding.subtitleTitle.text = getString(R.string.disabled_track)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
val locale = if (language.contains("-")) {
|
val locale = if (language.contains("-")) {
|
||||||
val parts = language.split("-")
|
val parts = language.split("-")
|
||||||
try {
|
try {
|
||||||
Locale(parts[0], parts[1])
|
Locale(parts[0], parts[1])
|
||||||
} catch (ignored: Exception) { null }
|
} catch (ignored: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
Locale(language)
|
Locale(language)
|
||||||
} catch (ignored: Exception) { null }
|
} catch (ignored: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
binding.subtitleTitle.text = locale?.let {
|
binding.subtitleTitle.text = locale?.let {
|
||||||
"[${it.language}] ${it.displayName}"
|
"[${it.language}] ${it.displayName}"
|
||||||
|
|
|
@ -60,7 +60,8 @@ class CommentItem(
|
||||||
override fun bind(viewBinding: ItemCommentsBinding, position: Int) {
|
override fun bind(viewBinding: ItemCommentsBinding, position: Int) {
|
||||||
binding = viewBinding
|
binding = viewBinding
|
||||||
setAnimation(binding.root.context, binding.root)
|
setAnimation(binding.root.context, binding.root)
|
||||||
viewBinding.commentRepliesList.layoutManager = LinearLayoutManager(commentsFragment.activity)
|
viewBinding.commentRepliesList.layoutManager =
|
||||||
|
LinearLayoutManager(commentsFragment.activity)
|
||||||
viewBinding.commentRepliesList.adapter = adapter
|
viewBinding.commentRepliesList.adapter = adapter
|
||||||
val isUserComment = CommentsAPI.userId == comment.userId
|
val isUserComment = CommentsAPI.userId == comment.userId
|
||||||
val levelColor = getAvatarColor(comment.totalVotes, backgroundColor)
|
val levelColor = getAvatarColor(comment.totalVotes, backgroundColor)
|
||||||
|
@ -112,16 +113,20 @@ class CommentItem(
|
||||||
|
|
||||||
viewBinding.commentUserName.setOnClickListener {
|
viewBinding.commentUserName.setOnClickListener {
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
commentsFragment.activity, Intent(commentsFragment.activity, ProfileActivity::class.java)
|
commentsFragment.activity,
|
||||||
|
Intent(commentsFragment.activity, ProfileActivity::class.java)
|
||||||
.putExtra("userId", comment.userId.toInt())
|
.putExtra("userId", comment.userId.toInt())
|
||||||
.putExtra("userLVL","[${levelColor.second}]"), null
|
.putExtra("userLVL", "[${levelColor.second}]"),
|
||||||
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
viewBinding.commentUserAvatar.setOnClickListener {
|
viewBinding.commentUserAvatar.setOnClickListener {
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
commentsFragment.activity, Intent(commentsFragment.activity, ProfileActivity::class.java)
|
commentsFragment.activity,
|
||||||
|
Intent(commentsFragment.activity, ProfileActivity::class.java)
|
||||||
.putExtra("userId", comment.userId.toInt())
|
.putExtra("userId", comment.userId.toInt())
|
||||||
.putExtra("userLVL","[${levelColor.second}]"), null
|
.putExtra("userLVL", "[${levelColor.second}]"),
|
||||||
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
viewBinding.commentText.setOnLongClickListener {
|
viewBinding.commentText.setOnLongClickListener {
|
||||||
|
@ -143,8 +148,10 @@ class CommentItem(
|
||||||
viewBinding.commentInfo.setOnClickListener {
|
viewBinding.commentInfo.setOnClickListener {
|
||||||
val popup = PopupMenu(commentsFragment.requireContext(), viewBinding.commentInfo)
|
val popup = PopupMenu(commentsFragment.requireContext(), viewBinding.commentInfo)
|
||||||
popup.menuInflater.inflate(R.menu.profile_details_menu, popup.menu)
|
popup.menuInflater.inflate(R.menu.profile_details_menu, popup.menu)
|
||||||
popup.menu.findItem(R.id.commentDelete)?.isVisible = isUserComment || CommentsAPI.isAdmin || CommentsAPI.isMod
|
popup.menu.findItem(R.id.commentDelete)?.isVisible =
|
||||||
popup.menu.findItem(R.id.commentBanUser)?.isVisible = (CommentsAPI.isAdmin || CommentsAPI.isMod) && !isUserComment
|
isUserComment || CommentsAPI.isAdmin || CommentsAPI.isMod
|
||||||
|
popup.menu.findItem(R.id.commentBanUser)?.isVisible =
|
||||||
|
(CommentsAPI.isAdmin || CommentsAPI.isMod) && !isUserComment
|
||||||
popup.menu.findItem(R.id.commentReport)?.isVisible = !isUserComment
|
popup.menu.findItem(R.id.commentReport)?.isVisible = !isUserComment
|
||||||
popup.setOnMenuItemClickListener { item ->
|
popup.setOnMenuItemClickListener { item ->
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
|
@ -273,12 +280,16 @@ class CommentItem(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun replying(isReplying: Boolean) {
|
fun replying(isReplying: Boolean) {
|
||||||
binding.commentReply.text = if (isReplying) commentsFragment.activity.getString(R.string.cancel) else "Reply"
|
binding.commentReply.text =
|
||||||
|
if (isReplying) commentsFragment.activity.getString(R.string.cancel) else "Reply"
|
||||||
this.isReplying = isReplying
|
this.isReplying = isReplying
|
||||||
}
|
}
|
||||||
|
|
||||||
fun editing(isEditing: Boolean) {
|
fun editing(isEditing: Boolean) {
|
||||||
binding.commentEdit.text = if (isEditing) commentsFragment.activity.getString(R.string.cancel) else commentsFragment.activity.getString(R.string.edit)
|
binding.commentEdit.text =
|
||||||
|
if (isEditing) commentsFragment.activity.getString(R.string.cancel) else commentsFragment.activity.getString(
|
||||||
|
R.string.edit
|
||||||
|
)
|
||||||
this.isEditing = isEditing
|
this.isEditing = isEditing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +297,7 @@ class CommentItem(
|
||||||
subCommentIds.add(id)
|
subCommentIds.add(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSubCommentIds(){
|
private fun removeSubCommentIds() {
|
||||||
subCommentIds.forEach { id ->
|
subCommentIds.forEach { id ->
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val parentComments = parentSection.groups as? List<CommentItem> ?: emptyList()
|
val parentComments = parentSection.groups as? List<CommentItem> ?: emptyList()
|
||||||
|
@ -306,11 +317,13 @@ class CommentItem(
|
||||||
viewBinding.commentUpVote.alpha = 1f
|
viewBinding.commentUpVote.alpha = 1f
|
||||||
viewBinding.commentDownVote.setImageResource(R.drawable.ic_round_upvote_inactive_24)
|
viewBinding.commentDownVote.setImageResource(R.drawable.ic_round_upvote_inactive_24)
|
||||||
}
|
}
|
||||||
|
|
||||||
-1 -> {
|
-1 -> {
|
||||||
viewBinding.commentUpVote.setImageResource(R.drawable.ic_round_upvote_inactive_24)
|
viewBinding.commentUpVote.setImageResource(R.drawable.ic_round_upvote_inactive_24)
|
||||||
viewBinding.commentDownVote.setImageResource(R.drawable.ic_round_upvote_active_24)
|
viewBinding.commentDownVote.setImageResource(R.drawable.ic_round_upvote_active_24)
|
||||||
viewBinding.commentDownVote.alpha = 1f
|
viewBinding.commentDownVote.alpha = 1f
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
viewBinding.commentUpVote.setImageResource(R.drawable.ic_round_upvote_inactive_24)
|
viewBinding.commentUpVote.setImageResource(R.drawable.ic_round_upvote_inactive_24)
|
||||||
viewBinding.commentDownVote.setImageResource(R.drawable.ic_round_upvote_inactive_24)
|
viewBinding.commentDownVote.setImageResource(R.drawable.ic_round_upvote_inactive_24)
|
||||||
|
@ -355,7 +368,8 @@ class CommentItem(
|
||||||
|
|
||||||
private fun getAvatarColor(voteCount: Int, backgroundColor: Int): Pair<Int, Int> {
|
private fun getAvatarColor(voteCount: Int, backgroundColor: Int): Pair<Int, Int> {
|
||||||
val level = if (voteCount < 0) 0 else sqrt(abs(voteCount.toDouble()) / 0.8).toInt()
|
val level = if (voteCount < 0) 0 else sqrt(abs(voteCount.toDouble()) / 0.8).toInt()
|
||||||
val colorString = if (level > usernameColors.size - 1) usernameColors[usernameColors.size - 1] else usernameColors[level]
|
val colorString =
|
||||||
|
if (level > usernameColors.size - 1) usernameColors[usernameColors.size - 1] else usernameColors[level]
|
||||||
var color = Color.parseColor(colorString)
|
var color = Color.parseColor(colorString)
|
||||||
val ratio = getContrastRatio(color, backgroundColor)
|
val ratio = getContrastRatio(color, backgroundColor)
|
||||||
if (ratio < 4.5) {
|
if (ratio < 4.5) {
|
||||||
|
@ -373,7 +387,8 @@ class CommentItem(
|
||||||
* @param callback the callback to call when the user clicks yes
|
* @param callback the callback to call when the user clicks yes
|
||||||
*/
|
*/
|
||||||
private fun dialogBuilder(title: String, message: String, callback: () -> Unit) {
|
private fun dialogBuilder(title: String, message: String, callback: () -> Unit) {
|
||||||
val alertDialog = android.app.AlertDialog.Builder(commentsFragment.activity, R.style.MyPopup)
|
val alertDialog =
|
||||||
|
android.app.AlertDialog.Builder(commentsFragment.activity, R.style.MyPopup)
|
||||||
.setTitle(title)
|
.setTitle(title)
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setPositiveButton("Yes") { dialog, _ ->
|
.setPositiveButton("Yes") { dialog, _ ->
|
||||||
|
|
|
@ -75,7 +75,10 @@ class CommentsFragment : Fragment() {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
activity = requireActivity() as MediaDetailsActivity
|
activity = requireActivity() as MediaDetailsActivity
|
||||||
|
|
||||||
binding.commentsListContainer.setBaseline(activity.navBar, activity.binding.commentInputLayout)
|
binding.commentsListContainer.setBaseline(
|
||||||
|
activity.navBar,
|
||||||
|
activity.binding.commentInputLayout
|
||||||
|
)
|
||||||
|
|
||||||
//get the media id from the intent
|
//get the media id from the intent
|
||||||
val mediaId = arguments?.getInt("mediaId") ?: -1
|
val mediaId = arguments?.getInt("mediaId") ?: -1
|
||||||
|
@ -301,7 +304,7 @@ class CommentsFragment : Fragment() {
|
||||||
|
|
||||||
activity.binding.commentLabel.setOnClickListener {
|
activity.binding.commentLabel.setOnClickListener {
|
||||||
//alert dialog to enter a number, with a cancel and ok button
|
//alert dialog to enter a number, with a cancel and ok button
|
||||||
val alertDialog = android.app.AlertDialog.Builder(activity, R.style.MyPopup)
|
val alertDialog = AlertDialog.Builder(activity, R.style.MyPopup)
|
||||||
.setTitle("Enter a chapter/episode number tag")
|
.setTitle("Enter a chapter/episode number tag")
|
||||||
.setView(R.layout.dialog_edittext)
|
.setView(R.layout.dialog_edittext)
|
||||||
.setPositiveButton("OK") { dialog, _ ->
|
.setPositiveButton("OK") { dialog, _ ->
|
||||||
|
@ -577,7 +580,7 @@ class CommentsFragment : Fragment() {
|
||||||
* Called when the user tries to comment for the first time
|
* Called when the user tries to comment for the first time
|
||||||
*/
|
*/
|
||||||
private fun showCommentRulesDialog() {
|
private fun showCommentRulesDialog() {
|
||||||
val alertDialog = android.app.AlertDialog.Builder(activity, R.style.MyPopup)
|
val alertDialog = AlertDialog.Builder(activity, R.style.MyPopup)
|
||||||
.setTitle("Commenting Rules")
|
.setTitle("Commenting Rules")
|
||||||
.setMessage(
|
.setMessage(
|
||||||
"I WILL BAN YOU WITHOUT HESITATION\n" +
|
"I WILL BAN YOU WITHOUT HESITATION\n" +
|
||||||
|
|
|
@ -343,6 +343,7 @@ class MangaChapterAdapter(
|
||||||
fun updateType(t: Int) {
|
fun updateType(t: Int) {
|
||||||
type = t
|
type = t
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun formatDate(timestamp: Long?): String {
|
private fun formatDate(timestamp: Long?): String {
|
||||||
timestamp ?: return "" // Return empty string if timestamp is null
|
timestamp ?: return "" // Return empty string if timestamp is null
|
||||||
|
|
||||||
|
@ -366,6 +367,7 @@ class MangaChapterAdapter(
|
||||||
else -> "Just now"
|
else -> "Just now"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
1L -> "1 day ago"
|
1L -> "1 day ago"
|
||||||
in 2..6 -> "$daysDifference days ago"
|
in 2..6 -> "$daysDifference days ago"
|
||||||
else -> SimpleDateFormat("dd MMM yyyy", Locale.getDefault()).format(targetDate)
|
else -> SimpleDateFormat("dd MMM yyyy", Locale.getDefault()).format(targetDate)
|
||||||
|
|
|
@ -229,7 +229,7 @@ class MangaReadAdapter(
|
||||||
refresh = true
|
refresh = true
|
||||||
val intent = Intent(fragment.requireContext(), CookieCatcher::class.java)
|
val intent = Intent(fragment.requireContext(), CookieCatcher::class.java)
|
||||||
.putExtra("url", url)
|
.putExtra("url", url)
|
||||||
ContextCompat.startActivity(fragment.requireContext(), intent, null)
|
startActivity(fragment.requireContext(), intent, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,8 +258,10 @@ class MangaReadAdapter(
|
||||||
dialogBinding.animeScanlatorContainer.isVisible = options.count() > 1
|
dialogBinding.animeScanlatorContainer.isVisible = options.count() > 1
|
||||||
dialogBinding.scanlatorNo.text = "${options.count()}"
|
dialogBinding.scanlatorNo.text = "${options.count()}"
|
||||||
dialogBinding.animeScanlatorTop.setOnClickListener {
|
dialogBinding.animeScanlatorTop.setOnClickListener {
|
||||||
val dialogView2 = LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null)
|
val dialogView2 =
|
||||||
val checkboxContainer = dialogView2.findViewById<LinearLayout>(R.id.checkboxContainer)
|
LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null)
|
||||||
|
val checkboxContainer =
|
||||||
|
dialogView2.findViewById<LinearLayout>(R.id.checkboxContainer)
|
||||||
val tickAllButton = dialogView2.findViewById<ImageButton>(R.id.toggleButton)
|
val tickAllButton = dialogView2.findViewById<ImageButton>(R.id.toggleButton)
|
||||||
|
|
||||||
// Function to get the right image resource for the toggle button
|
// Function to get the right image resource for the toggle button
|
||||||
|
@ -441,7 +443,11 @@ class MangaReadAdapter(
|
||||||
if (media.manga?.chapters != null) {
|
if (media.manga?.chapters != null) {
|
||||||
val chapters = media.manga.chapters!!.keys.toTypedArray()
|
val chapters = media.manga.chapters!!.keys.toTypedArray()
|
||||||
val anilistEp = (media.userProgress ?: 0).plus(1)
|
val anilistEp = (media.userProgress ?: 0).plus(1)
|
||||||
val appEp = PrefManager.getNullableCustomVal("${media.id}_current_chp", null, String::class.java)
|
val appEp = PrefManager.getNullableCustomVal(
|
||||||
|
"${media.id}_current_chp",
|
||||||
|
null,
|
||||||
|
String::class.java
|
||||||
|
)
|
||||||
?.toIntOrNull() ?: 1
|
?.toIntOrNull() ?: 1
|
||||||
var continueEp = (if (anilistEp > appEp) anilistEp else appEp).toString()
|
var continueEp = (if (anilistEp > appEp) anilistEp else appEp).toString()
|
||||||
val filteredChapters = chapters.filter { chapterKey ->
|
val filteredChapters = chapters.filter { chapterKey ->
|
||||||
|
@ -470,7 +476,11 @@ class MangaReadAdapter(
|
||||||
val ep = media.manga.chapters!![continueEp]!!
|
val ep = media.manga.chapters!![continueEp]!!
|
||||||
binding.itemEpisodeImage.loadImage(media.banner ?: media.cover)
|
binding.itemEpisodeImage.loadImage(media.banner ?: media.cover)
|
||||||
binding.animeSourceContinueText.text =
|
binding.animeSourceContinueText.text =
|
||||||
currActivity()!!.getString(R.string.continue_chapter, ep.number, if (!ep.title.isNullOrEmpty()) ep.title else "")
|
currActivity()!!.getString(
|
||||||
|
R.string.continue_chapter,
|
||||||
|
ep.number,
|
||||||
|
if (!ep.title.isNullOrEmpty()) ep.title else ""
|
||||||
|
)
|
||||||
binding.animeSourceContinue.setOnClickListener {
|
binding.animeSourceContinue.setOnClickListener {
|
||||||
fragment.onMangaChapterClick(continueEp)
|
fragment.onMangaChapterClick(continueEp)
|
||||||
}
|
}
|
||||||
|
@ -491,11 +501,14 @@ class MangaReadAdapter(
|
||||||
if (!sourceFound && PrefManager.getVal(PrefName.SearchSources)) {
|
if (!sourceFound && PrefManager.getVal(PrefName.SearchSources)) {
|
||||||
if (binding.animeSource.adapter.count > media.selected!!.sourceIndex + 1) {
|
if (binding.animeSource.adapter.count > media.selected!!.sourceIndex + 1) {
|
||||||
val nextIndex = media.selected!!.sourceIndex + 1
|
val nextIndex = media.selected!!.sourceIndex + 1
|
||||||
binding.animeSource.setText(binding.animeSource.adapter
|
binding.animeSource.setText(
|
||||||
.getItem(nextIndex).toString(), false)
|
binding.animeSource.adapter
|
||||||
|
.getItem(nextIndex).toString(), false
|
||||||
|
)
|
||||||
fragment.onSourceChange(nextIndex).apply {
|
fragment.onSourceChange(nextIndex).apply {
|
||||||
binding.animeSourceTitle.text = showUserText
|
binding.animeSourceTitle.text = showUserText
|
||||||
showUserTextListener = { MainScope().launch { binding.animeSourceTitle.text = it } }
|
showUserTextListener =
|
||||||
|
{ MainScope().launch { binding.animeSourceTitle.text = it } }
|
||||||
setLanguageList(0, nextIndex)
|
setLanguageList(0, nextIndex)
|
||||||
}
|
}
|
||||||
subscribeButton(false)
|
subscribeButton(false)
|
||||||
|
|
|
@ -42,8 +42,8 @@ import ani.dantotsu.isOnline
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.MediaDetailsActivity
|
import ani.dantotsu.media.MediaDetailsActivity
|
||||||
import ani.dantotsu.media.MediaDetailsViewModel
|
import ani.dantotsu.media.MediaDetailsViewModel
|
||||||
import ani.dantotsu.media.MediaType
|
|
||||||
import ani.dantotsu.media.MediaNameAdapter
|
import ani.dantotsu.media.MediaNameAdapter
|
||||||
|
import ani.dantotsu.media.MediaType
|
||||||
import ani.dantotsu.media.manga.mangareader.ChapterLoaderDialog
|
import ani.dantotsu.media.manga.mangareader.ChapterLoaderDialog
|
||||||
import ani.dantotsu.navBarHeight
|
import ani.dantotsu.navBarHeight
|
||||||
import ani.dantotsu.notifications.subscription.SubscriptionHelper
|
import ani.dantotsu.notifications.subscription.SubscriptionHelper
|
||||||
|
@ -203,8 +203,10 @@ open class MangaReadFragment : Fragment(), ScanlatorSelectionListener {
|
||||||
ConcatAdapter(headerAdapter, chapterAdapter)
|
ConcatAdapter(headerAdapter, chapterAdapter)
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val offline = !isOnline(binding.root.context) || PrefManager.getVal(PrefName.OfflineMode)
|
val offline =
|
||||||
if (offline) media.selected!!.sourceIndex = model.mangaReadSources!!.list.lastIndex
|
!isOnline(binding.root.context) || PrefManager.getVal(PrefName.OfflineMode)
|
||||||
|
if (offline) media.selected!!.sourceIndex =
|
||||||
|
model.mangaReadSources!!.list.lastIndex
|
||||||
model.loadMangaChapters(media, media.selected!!.sourceIndex)
|
model.loadMangaChapters(media, media.selected!!.sourceIndex)
|
||||||
}
|
}
|
||||||
loaded = true
|
loaded = true
|
||||||
|
|
|
@ -42,7 +42,8 @@ abstract class BaseImageAdapter(
|
||||||
|
|
||||||
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
||||||
images = if (settings.layout == CurrentReaderSettings.Layouts.PAGED
|
images = if (settings.layout == CurrentReaderSettings.Layouts.PAGED
|
||||||
&& settings.direction == CurrentReaderSettings.Directions.BOTTOM_TO_TOP) {
|
&& settings.direction == CurrentReaderSettings.Directions.BOTTOM_TO_TOP
|
||||||
|
) {
|
||||||
chapterImages.reversed()
|
chapterImages.reversed()
|
||||||
} else {
|
} else {
|
||||||
chapterImages
|
chapterImages
|
||||||
|
|
|
@ -56,8 +56,8 @@ import ani.dantotsu.isOnline
|
||||||
import ani.dantotsu.logError
|
import ani.dantotsu.logError
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.MediaDetailsViewModel
|
import ani.dantotsu.media.MediaDetailsViewModel
|
||||||
import ani.dantotsu.media.MediaSingleton
|
|
||||||
import ani.dantotsu.media.MediaNameAdapter
|
import ani.dantotsu.media.MediaNameAdapter
|
||||||
|
import ani.dantotsu.media.MediaSingleton
|
||||||
import ani.dantotsu.media.manga.MangaCache
|
import ani.dantotsu.media.manga.MangaCache
|
||||||
import ani.dantotsu.media.manga.MangaChapter
|
import ani.dantotsu.media.manga.MangaChapter
|
||||||
import ani.dantotsu.others.ImageViewDialog
|
import ani.dantotsu.others.ImageViewDialog
|
||||||
|
@ -129,9 +129,11 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
var sliding = false
|
var sliding = false
|
||||||
var isAnimating = false
|
var isAnimating = false
|
||||||
|
|
||||||
private val directionRLBT get() = defaultSettings.direction == RIGHT_TO_LEFT
|
private val directionRLBT
|
||||||
|
get() = defaultSettings.direction == RIGHT_TO_LEFT
|
||||||
|| defaultSettings.direction == BOTTOM_TO_TOP
|
|| defaultSettings.direction == BOTTOM_TO_TOP
|
||||||
private val directionPagedBT get() = defaultSettings.layout == CurrentReaderSettings.Layouts.PAGED
|
private val directionPagedBT
|
||||||
|
get() = defaultSettings.layout == CurrentReaderSettings.Layouts.PAGED
|
||||||
&& defaultSettings.direction == CurrentReaderSettings.Directions.BOTTOM_TO_TOP
|
&& defaultSettings.direction == CurrentReaderSettings.Directions.BOTTOM_TO_TOP
|
||||||
|
|
||||||
override fun onAttachedToWindow() {
|
override fun onAttachedToWindow() {
|
||||||
|
@ -229,7 +231,7 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
binding.mangaReaderRecycler.scrollToPosition((value.toInt() - 1) / (dualPage { 2 }
|
binding.mangaReaderRecycler.scrollToPosition((value.toInt() - 1) / (dualPage { 2 }
|
||||||
?: 1))
|
?: 1))
|
||||||
else
|
else
|
||||||
if (defaultSettings.direction == CurrentReaderSettings.Directions.BOTTOM_TO_TOP ) {
|
if (defaultSettings.direction == CurrentReaderSettings.Directions.BOTTOM_TO_TOP) {
|
||||||
binding.mangaReaderPager.currentItem =
|
binding.mangaReaderPager.currentItem =
|
||||||
(maxChapterPage.toInt() - value.toInt()) / (dualPage { 2 } ?: 1)
|
(maxChapterPage.toInt() - value.toInt()) / (dualPage { 2 } ?: 1)
|
||||||
} else {
|
} else {
|
||||||
|
@ -345,7 +347,11 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
if (currentChapterIndex > 0) change(currentChapterIndex - 1)
|
if (currentChapterIndex > 0) change(currentChapterIndex - 1)
|
||||||
else snackString(getString(R.string.first_chapter))
|
else snackString(getString(R.string.first_chapter))
|
||||||
} else {
|
} else {
|
||||||
if (chaptersArr.size > currentChapterIndex + 1) progress { change(currentChapterIndex + 1) }
|
if (chaptersArr.size > currentChapterIndex + 1) progress {
|
||||||
|
change(
|
||||||
|
currentChapterIndex + 1
|
||||||
|
)
|
||||||
|
}
|
||||||
else snackString(getString(R.string.next_chapter_not_found))
|
else snackString(getString(R.string.next_chapter_not_found))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,7 +361,11 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
binding.mangaReaderPreviousChapter.setOnClickListener {
|
binding.mangaReaderPreviousChapter.setOnClickListener {
|
||||||
if (directionRLBT) {
|
if (directionRLBT) {
|
||||||
if (chaptersArr.size > currentChapterIndex + 1) progress { change(currentChapterIndex + 1) }
|
if (chaptersArr.size > currentChapterIndex + 1) progress {
|
||||||
|
change(
|
||||||
|
currentChapterIndex + 1
|
||||||
|
)
|
||||||
|
}
|
||||||
else snackString(getString(R.string.next_chapter_not_found))
|
else snackString(getString(R.string.next_chapter_not_found))
|
||||||
} else {
|
} else {
|
||||||
if (currentChapterIndex > 0) change(currentChapterIndex - 1)
|
if (currentChapterIndex > 0) change(currentChapterIndex - 1)
|
||||||
|
@ -372,11 +382,15 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
currentChapterIndex = chaptersArr.indexOf(chap.number)
|
currentChapterIndex = chaptersArr.indexOf(chap.number)
|
||||||
binding.mangaReaderChapterSelect.setSelection(currentChapterIndex)
|
binding.mangaReaderChapterSelect.setSelection(currentChapterIndex)
|
||||||
if (directionRLBT) {
|
if (directionRLBT) {
|
||||||
binding.mangaReaderNextChap.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
|
binding.mangaReaderNextChap.text =
|
||||||
binding.mangaReaderPrevChap.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
|
chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
|
||||||
|
binding.mangaReaderPrevChap.text =
|
||||||
|
chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
|
||||||
} else {
|
} else {
|
||||||
binding.mangaReaderNextChap.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
|
binding.mangaReaderNextChap.text =
|
||||||
binding.mangaReaderPrevChap.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
|
chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
|
||||||
|
binding.mangaReaderPrevChap.text =
|
||||||
|
chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
|
||||||
}
|
}
|
||||||
applySettings()
|
applySettings()
|
||||||
val context = this
|
val context = this
|
||||||
|
@ -389,10 +403,12 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
"nothing" -> mutableListOf(
|
"nothing" -> mutableListOf(
|
||||||
RPC.Link(getString(R.string.view_manga), media.shareLink ?: ""),
|
RPC.Link(getString(R.string.view_manga), media.shareLink ?: ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
"dantotsu" -> mutableListOf(
|
"dantotsu" -> mutableListOf(
|
||||||
RPC.Link(getString(R.string.view_manga), media.shareLink ?: ""),
|
RPC.Link(getString(R.string.view_manga), media.shareLink ?: ""),
|
||||||
RPC.Link("Read on Dantotsu", getString(R.string.dantotsu))
|
RPC.Link("Read on Dantotsu", getString(R.string.dantotsu))
|
||||||
)
|
)
|
||||||
|
|
||||||
"anilist" -> {
|
"anilist" -> {
|
||||||
val userId = PrefManager.getVal<String>(PrefName.AnilistUserId)
|
val userId = PrefManager.getVal<String>(PrefName.AnilistUserId)
|
||||||
val anilistLink = "https://anilist.co/user/$userId/"
|
val anilistLink = "https://anilist.co/user/$userId/"
|
||||||
|
@ -401,6 +417,7 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
RPC.Link("View My AniList", anilistLink)
|
RPC.Link("View My AniList", anilistLink)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> mutableListOf()
|
else -> mutableListOf()
|
||||||
}
|
}
|
||||||
val presence = RPC.createPresence(
|
val presence = RPC.createPresence(
|
||||||
|
@ -411,7 +428,12 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
details = chap.title?.takeIf { it.isNotEmpty() }
|
details = chap.title?.takeIf { it.isNotEmpty() }
|
||||||
?: getString(R.string.chapter_num, chap.number),
|
?: getString(R.string.chapter_num, chap.number),
|
||||||
state = "${chap.number}/${media.manga?.totalChapters ?: "??"}",
|
state = "${chap.number}/${media.manga?.totalChapters ?: "??"}",
|
||||||
largeImage = media.cover?.let { cover -> RPC.Link(media.userPreferredName, cover) },
|
largeImage = media.cover?.let { cover ->
|
||||||
|
RPC.Link(
|
||||||
|
media.userPreferredName,
|
||||||
|
cover
|
||||||
|
)
|
||||||
|
},
|
||||||
buttons = buttons
|
buttons = buttons
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -918,7 +940,12 @@ class MangaReaderActivity : AppCompatActivity() {
|
||||||
isAnimating = true
|
isAnimating = true
|
||||||
ObjectAnimator.ofFloat(binding.mangaReaderCont, "alpha", 1f, 0f)
|
ObjectAnimator.ofFloat(binding.mangaReaderCont, "alpha", 1f, 0f)
|
||||||
.setDuration(controllerDuration).start()
|
.setDuration(controllerDuration).start()
|
||||||
ObjectAnimator.ofFloat(binding.mangaReaderBottomLayout, "translationY", 0f, 128f)
|
ObjectAnimator.ofFloat(
|
||||||
|
binding.mangaReaderBottomLayout,
|
||||||
|
"translationY",
|
||||||
|
0f,
|
||||||
|
128f
|
||||||
|
)
|
||||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||||
ObjectAnimator.ofFloat(binding.mangaReaderTopLayout, "translationY", 0f, -128f)
|
ObjectAnimator.ofFloat(binding.mangaReaderTopLayout, "translationY", 0f, -128f)
|
||||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||||
|
|
|
@ -113,7 +113,12 @@ class NovelReadFragment : Fragment(),
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
val directory =
|
val directory =
|
||||||
DownloadsManager.getSubDirectory(context?:currContext()!!, MediaType.NOVEL, false, novel.name)
|
DownloadsManager.getSubDirectory(
|
||||||
|
context ?: currContext()!!,
|
||||||
|
MediaType.NOVEL,
|
||||||
|
false,
|
||||||
|
novel.name
|
||||||
|
)
|
||||||
val file = directory?.findFile(novel.name)
|
val file = directory?.findFile(novel.name)
|
||||||
if (file?.exists() == false) return false
|
if (file?.exists() == false) return false
|
||||||
val fileUri = file?.uri ?: return false
|
val fileUri = file?.uri ?: return false
|
||||||
|
|
|
@ -181,7 +181,7 @@ class NovelResponseAdapter(
|
||||||
if (position != -1) {
|
if (position != -1) {
|
||||||
list[position].extra?.remove("0")
|
list[position].extra?.remove("0")
|
||||||
list[position].extra?.set("0", "Downloading: $progress%")
|
list[position].extra?.set("0", "Downloading: $progress%")
|
||||||
Logger.log( "updateDownloadProgress: $progress, position: $position")
|
Logger.log("updateDownloadProgress: $progress, position: $position")
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -292,7 +292,11 @@ class NovelReaderActivity : AppCompatActivity(), EbookReaderEventListener {
|
||||||
applySettings()
|
applySettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
val cfi = PrefManager.getNullableCustomVal("${sanitizedBookId}_progress", null, String::class.java)
|
val cfi = PrefManager.getNullableCustomVal(
|
||||||
|
"${sanitizedBookId}_progress",
|
||||||
|
null,
|
||||||
|
String::class.java
|
||||||
|
)
|
||||||
|
|
||||||
cfi?.let { binding.bookReader.goto(it) }
|
cfi?.let { binding.bookReader.goto(it) }
|
||||||
binding.progress.visibility = View.GONE
|
binding.progress.visibility = View.GONE
|
||||||
|
|
|
@ -70,8 +70,10 @@ class ListActivity : AppCompatActivity() {
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
val anime = intent.getBooleanExtra("anime", true)
|
val anime = intent.getBooleanExtra("anime", true)
|
||||||
binding.listTitle.text = getString(R.string.user_list, intent.getStringExtra("username"),
|
binding.listTitle.text = getString(
|
||||||
if (anime) getString(R.string.anime) else getString(R.string.manga))
|
R.string.user_list, intent.getStringExtra("username"),
|
||||||
|
if (anime) getString(R.string.anime) else getString(R.string.manga)
|
||||||
|
)
|
||||||
binding.listTabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
binding.listTabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||||
this@ListActivity.selectedTabIdx = tab?.position ?: 0
|
this@ListActivity.selectedTabIdx = tab?.position ?: 0
|
||||||
|
@ -158,7 +160,8 @@ class ListActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.filter.setOnClickListener {
|
binding.filter.setOnClickListener {
|
||||||
val genres = PrefManager.getVal<Set<String>>(PrefName.GenresList).toMutableSet().sorted()
|
val genres =
|
||||||
|
PrefManager.getVal<Set<String>>(PrefName.GenresList).toMutableSet().sorted()
|
||||||
val popup = PopupMenu(this, it)
|
val popup = PopupMenu(this, it)
|
||||||
popup.menu.add("All")
|
popup.menu.add("All")
|
||||||
genres.forEach { genre ->
|
genres.forEach { genre ->
|
||||||
|
|
|
@ -5,7 +5,10 @@ import android.graphics.Rect
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
|
||||||
class AndroidBug5497Workaround private constructor(activity: Activity, private val callback: (Boolean) -> Unit) {
|
class AndroidBug5497Workaround private constructor(
|
||||||
|
activity: Activity,
|
||||||
|
private val callback: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
private val mChildOfContent: View
|
private val mChildOfContent: View
|
||||||
private var usableHeightPrevious = 0
|
private var usableHeightPrevious = 0
|
||||||
private val frameLayoutParams: FrameLayout.LayoutParams
|
private val frameLayoutParams: FrameLayout.LayoutParams
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package ani.dantotsu.others
|
package ani.dantotsu.others
|
||||||
|
|
||||||
import android.app.DownloadManager
|
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
@ -8,7 +7,6 @@ import android.content.pm.PackageManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import ani.dantotsu.FileUrl
|
import ani.dantotsu.FileUrl
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
|
@ -19,9 +17,6 @@ import ani.dantotsu.parsers.Book
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.toast
|
import ani.dantotsu.toast
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object Download {
|
object Download {
|
||||||
|
|
|
@ -2,10 +2,10 @@ package ani.dantotsu.others
|
||||||
|
|
||||||
import ani.dantotsu.FileUrl
|
import ani.dantotsu.FileUrl
|
||||||
import ani.dantotsu.client
|
import ani.dantotsu.client
|
||||||
import ani.dantotsu.util.Logger
|
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.anime.Episode
|
import ani.dantotsu.media.anime.Episode
|
||||||
import ani.dantotsu.tryWithSuspend
|
import ani.dantotsu.tryWithSuspend
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.lagradost.nicehttp.NiceResponse
|
import com.lagradost.nicehttp.NiceResponse
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
|
|
@ -56,7 +56,8 @@ class OutlineTextView : AppCompatTextView {
|
||||||
setStrokeWidth(strokeWidth)
|
setStrokeWidth(strokeWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val Float.toPx get() = TypedValue.applyDimension(
|
private val Float.toPx
|
||||||
|
get() = TypedValue.applyDimension(
|
||||||
TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics
|
TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ class Xpandable @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
postDelayed({
|
postDelayed({
|
||||||
listeners.forEach{
|
listeners.forEach {
|
||||||
it.onRetract()
|
it.onRetract()
|
||||||
}
|
}
|
||||||
}, 300)
|
}, 300)
|
||||||
|
@ -66,7 +66,7 @@ class Xpandable @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
postDelayed({
|
postDelayed({
|
||||||
listeners.forEach{
|
listeners.forEach {
|
||||||
it.onExpand()
|
it.onExpand()
|
||||||
}
|
}
|
||||||
}, 300)
|
}, 300)
|
||||||
|
|
|
@ -24,7 +24,8 @@ class CookieCatcher : AppCompatActivity() {
|
||||||
|
|
||||||
//get url from intent
|
//get url from intent
|
||||||
val url = intent.getStringExtra("url") ?: getString(R.string.cursed_yt)
|
val url = intent.getStringExtra("url") ?: getString(R.string.cursed_yt)
|
||||||
val headers: Map<String, String> = intent.getSerializableExtraCompat("headers") as? Map<String, String> ?: emptyMap()
|
val headers: Map<String, String> =
|
||||||
|
intent.getSerializableExtraCompat("headers") as? Map<String, String> ?: emptyMap()
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
val process = Application.getProcessName()
|
val process = Application.getProcessName()
|
||||||
|
|
|
@ -5,8 +5,8 @@ import ani.dantotsu.currContext
|
||||||
import ani.dantotsu.download.DownloadsManager
|
import ani.dantotsu.download.DownloadsManager
|
||||||
import ani.dantotsu.download.DownloadsManager.Companion.getSubDirectory
|
import ani.dantotsu.download.DownloadsManager.Companion.getSubDirectory
|
||||||
import ani.dantotsu.download.anime.AnimeDownloaderService.AnimeDownloadTask.Companion.getTaskName
|
import ani.dantotsu.download.anime.AnimeDownloaderService.AnimeDownloadTask.Companion.getTaskName
|
||||||
import ani.dantotsu.media.MediaType
|
|
||||||
import ani.dantotsu.media.MediaNameAdapter
|
import ani.dantotsu.media.MediaNameAdapter
|
||||||
|
import ani.dantotsu.media.MediaType
|
||||||
import ani.dantotsu.tryWithSuspend
|
import ani.dantotsu.tryWithSuspend
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||||
|
@ -43,7 +43,7 @@ class OfflineAnimeParser : AnimeParser() {
|
||||||
if (it.isDirectory) {
|
if (it.isDirectory) {
|
||||||
val episode = Episode(
|
val episode = Episode(
|
||||||
it.name!!,
|
it.name!!,
|
||||||
getTaskName(animeLink,it.name!!),
|
getTaskName(animeLink, it.name!!),
|
||||||
it.name,
|
it.name,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
|
|
@ -28,7 +28,7 @@ class OfflineNovelParser : NovelParser() {
|
||||||
directory.listFiles().forEach {
|
directory.listFiles().forEach {
|
||||||
if (it.isDirectory) {
|
if (it.isDirectory) {
|
||||||
val chapter = Book(
|
val chapter = Book(
|
||||||
it.name?:"Unknown",
|
it.name ?: "Unknown",
|
||||||
it.uri.toString(),
|
it.uri.toString(),
|
||||||
null,
|
null,
|
||||||
listOf(it.uri.toString())
|
listOf(it.uri.toString())
|
||||||
|
@ -63,7 +63,7 @@ class OfflineNovelParser : NovelParser() {
|
||||||
if (directory?.exists() == true) {
|
if (directory?.exists() == true) {
|
||||||
directory.listFiles().forEach {
|
directory.listFiles().forEach {
|
||||||
if (it.isDirectory) {
|
if (it.isDirectory) {
|
||||||
names.add(it.name?: "Unknown")
|
names.add(it.name ?: "Unknown")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,8 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
* @param url The url of the apk.
|
* @param url The url of the apk.
|
||||||
* @param extension The extension to install.
|
* @param extension The extension to install.
|
||||||
*/
|
*/
|
||||||
fun downloadAndInstall(url: String, extension: NovelExtension): Observable<InstallStep> = Observable.defer {
|
fun downloadAndInstall(url: String, extension: NovelExtension): Observable<InstallStep> =
|
||||||
|
Observable.defer {
|
||||||
val pkgName = extension.pkgName
|
val pkgName = extension.pkgName
|
||||||
|
|
||||||
val oldDownload = activeDownloads[pkgName]
|
val oldDownload = activeDownloads[pkgName]
|
||||||
|
@ -70,7 +71,8 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
||||||
deleteDownload(pkgName)
|
deleteDownload(pkgName)
|
||||||
}
|
}
|
||||||
|
|
||||||
val sourcePath = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.absolutePath
|
val sourcePath =
|
||||||
|
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.absolutePath
|
||||||
//if the file is already downloaded, remove it
|
//if the file is already downloaded, remove it
|
||||||
val fileToDelete = File("$sourcePath/${url.toUri().lastPathSegment}")
|
val fileToDelete = File("$sourcePath/${url.toUri().lastPathSegment}")
|
||||||
if (fileToDelete.exists()) {
|
if (fileToDelete.exists()) {
|
||||||
|
|
|
@ -15,7 +15,8 @@ import com.xwray.groupie.viewbinding.GroupieViewHolder
|
||||||
class ChartItem(
|
class ChartItem(
|
||||||
private val title: String,
|
private val title: String,
|
||||||
private val aaOptions: AAOptions,
|
private val aaOptions: AAOptions,
|
||||||
private val activity: ProfileActivity): BindableItem<ItemChartBinding>() {
|
private val activity: ProfileActivity
|
||||||
|
) : BindableItem<ItemChartBinding>() {
|
||||||
private lateinit var binding: ItemChartBinding
|
private lateinit var binding: ItemChartBinding
|
||||||
override fun bind(viewBinding: ItemChartBinding, position: Int) {
|
override fun bind(viewBinding: ItemChartBinding, position: Int) {
|
||||||
binding = viewBinding
|
binding = viewBinding
|
||||||
|
@ -78,6 +79,7 @@ class ChartItem(
|
||||||
viewHolder.setIsRecyclable(false)
|
viewHolder.setIsRecyclable(false)
|
||||||
super.bind(viewHolder, position, payloads, onItemClickListener, onItemLongClickListener)
|
super.bind(viewHolder, position, payloads, onItemClickListener, onItemLongClickListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getViewType(): Int {
|
override fun getViewType(): Int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
class FollowActivity : AppCompatActivity(){
|
class FollowActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: ActivityFollowBinding
|
private lateinit var binding: ActivityFollowBinding
|
||||||
val adapter = GroupieAdapter()
|
val adapter = GroupieAdapter()
|
||||||
var users: List<User>? = null
|
var users: List<User>? = null
|
||||||
|
@ -37,7 +37,9 @@ class FollowActivity : AppCompatActivity(){
|
||||||
initActivity(this)
|
initActivity(this)
|
||||||
binding = ActivityFollowBinding.inflate(layoutInflater)
|
binding = ActivityFollowBinding.inflate(layoutInflater)
|
||||||
binding.listToolbar.updateLayoutParams<MarginLayoutParams> { topMargin = statusBarHeight }
|
binding.listToolbar.updateLayoutParams<MarginLayoutParams> { topMargin = statusBarHeight }
|
||||||
binding.listFrameLayout.updateLayoutParams<MarginLayoutParams> { bottomMargin = navBarHeight }
|
binding.listFrameLayout.updateLayoutParams<MarginLayoutParams> {
|
||||||
|
bottomMargin = navBarHeight
|
||||||
|
}
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
val layoutType = PrefManager.getVal<Int>(PrefName.FollowerLayout)
|
val layoutType = PrefManager.getVal<Int>(PrefName.FollowerLayout)
|
||||||
selected = getSelected(layoutType)
|
selected = getSelected(layoutType)
|
||||||
|
@ -54,7 +56,7 @@ class FollowActivity : AppCompatActivity(){
|
||||||
binding.listBack.setOnClickListener { finish() }
|
binding.listBack.setOnClickListener { finish() }
|
||||||
|
|
||||||
val title = intent.getStringExtra("title")
|
val title = intent.getStringExtra("title")
|
||||||
val userID= intent.getIntExtra("userId", 0)
|
val userID = intent.getIntExtra("userId", 0)
|
||||||
binding.listTitle.text = title
|
binding.listTitle.text = title
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
@ -93,9 +95,20 @@ class FollowActivity : AppCompatActivity(){
|
||||||
}
|
}
|
||||||
users?.forEach { user ->
|
users?.forEach { user ->
|
||||||
if (getLayoutType(selected) == 0) {
|
if (getLayoutType(selected) == 0) {
|
||||||
adapter.add(FollowerItem(user.id, user.name ?: "Unknown", user.avatar?.medium, user.bannerImage ?: user.avatar?.medium ) { onUserClick(it) })
|
adapter.add(
|
||||||
|
FollowerItem(
|
||||||
|
user.id,
|
||||||
|
user.name ?: "Unknown",
|
||||||
|
user.avatar?.medium,
|
||||||
|
user.bannerImage ?: user.avatar?.medium
|
||||||
|
) { onUserClick(it) })
|
||||||
} else {
|
} else {
|
||||||
adapter.add(GridFollowerItem(user.id, user.name ?: "Unknown", user.avatar?.medium) { onUserClick(it) })
|
adapter.add(
|
||||||
|
GridFollowerItem(
|
||||||
|
user.id,
|
||||||
|
user.name ?: "Unknown",
|
||||||
|
user.avatar?.medium
|
||||||
|
) { onUserClick(it) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ class FollowerItem(
|
||||||
private val avatar: String?,
|
private val avatar: String?,
|
||||||
private val banner: String?,
|
private val banner: String?,
|
||||||
val clickCallback: (Int) -> Unit
|
val clickCallback: (Int) -> Unit
|
||||||
): BindableItem<ItemFollowerBinding>() {
|
) : BindableItem<ItemFollowerBinding>() {
|
||||||
private lateinit var binding: ItemFollowerBinding
|
private lateinit var binding: ItemFollowerBinding
|
||||||
|
|
||||||
override fun bind(viewBinding: ItemFollowerBinding, position: Int) {
|
override fun bind(viewBinding: ItemFollowerBinding, position: Int) {
|
||||||
|
|
|
@ -6,12 +6,12 @@ import ani.dantotsu.databinding.ItemFollowerGridBinding
|
||||||
import ani.dantotsu.loadImage
|
import ani.dantotsu.loadImage
|
||||||
import com.xwray.groupie.viewbinding.BindableItem
|
import com.xwray.groupie.viewbinding.BindableItem
|
||||||
|
|
||||||
class GridFollowerItem (
|
class GridFollowerItem(
|
||||||
private val id: Int,
|
private val id: Int,
|
||||||
private val name: String,
|
private val name: String,
|
||||||
private val avatar: String?,
|
private val avatar: String?,
|
||||||
val clickCallback: (Int) -> Unit
|
val clickCallback: (Int) -> Unit
|
||||||
): BindableItem<ItemFollowerGridBinding>() {
|
) : BindableItem<ItemFollowerGridBinding>() {
|
||||||
private lateinit var binding: ItemFollowerGridBinding
|
private lateinit var binding: ItemFollowerGridBinding
|
||||||
|
|
||||||
override fun bind(viewBinding: ItemFollowerGridBinding, position: Int) {
|
override fun bind(viewBinding: ItemFollowerGridBinding, position: Int) {
|
||||||
|
|
|
@ -59,9 +59,11 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
|
||||||
screenWidth = resources.displayMetrics.widthPixels.toFloat()
|
screenWidth = resources.displayMetrics.widthPixels.toFloat()
|
||||||
navBar = binding.profileNavBar
|
navBar = binding.profileNavBar
|
||||||
val navBarRightMargin = if (resources.configuration.orientation ==
|
val navBarRightMargin = if (resources.configuration.orientation ==
|
||||||
Configuration.ORIENTATION_LANDSCAPE) navBarHeight else 0
|
Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
) navBarHeight else 0
|
||||||
val navBarBottomMargin = if (resources.configuration.orientation ==
|
val navBarBottomMargin = if (resources.configuration.orientation ==
|
||||||
Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
|
Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
) 0 else navBarHeight
|
||||||
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
rightMargin = navBarRightMargin
|
rightMargin = navBarRightMargin
|
||||||
bottomMargin = navBarBottomMargin
|
bottomMargin = navBarBottomMargin
|
||||||
|
@ -284,7 +286,7 @@ 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
|
||||||
|
|
||||||
with (bindingProfileAppBar) {
|
with(bindingProfileAppBar) {
|
||||||
profileUserAvatarContainer.visibility =
|
profileUserAvatarContainer.visibility =
|
||||||
if (profileUserAvatarContainer.scaleX == 0f) View.GONE else View.VISIBLE
|
if (profileUserAvatarContainer.scaleX == 0f) View.GONE else View.VISIBLE
|
||||||
val duration = (200 * (PrefManager.getVal(PrefName.AnimationSpeed) as Float)).toLong()
|
val duration = (200 * (PrefManager.getVal(PrefName.AnimationSpeed) as Float)).toLong()
|
||||||
|
@ -315,10 +317,12 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
super.onConfigurationChanged(newConfig)
|
super.onConfigurationChanged(newConfig)
|
||||||
val rightMargin = if (resources.configuration.orientation ==
|
val rightMargin = if (resources.configuration.orientation ==
|
||||||
Configuration.ORIENTATION_LANDSCAPE) navBarHeight else 0
|
Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
) navBarHeight else 0
|
||||||
val bottomMargin = if (resources.configuration.orientation ==
|
val bottomMargin = if (resources.configuration.orientation ==
|
||||||
Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
|
Configuration.ORIENTATION_LANDSCAPE
|
||||||
val params : ViewGroup.MarginLayoutParams =
|
) 0 else navBarHeight
|
||||||
|
val params: ViewGroup.MarginLayoutParams =
|
||||||
navBar.layoutParams as ViewGroup.MarginLayoutParams
|
navBar.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
params.updateMargins(right = rightMargin, bottom = bottomMargin)
|
params.updateMargins(right = rightMargin, bottom = bottomMargin)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package ani.dantotsu.profile
|
package ani.dantotsu.profile
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.TypedValue
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -22,19 +20,16 @@ import ani.dantotsu.R
|
||||||
import ani.dantotsu.connections.anilist.ProfileViewModel
|
import ani.dantotsu.connections.anilist.ProfileViewModel
|
||||||
import ani.dantotsu.connections.anilist.api.Query
|
import ani.dantotsu.connections.anilist.api.Query
|
||||||
import ani.dantotsu.databinding.FragmentProfileBinding
|
import ani.dantotsu.databinding.FragmentProfileBinding
|
||||||
import ani.dantotsu.loadImage
|
|
||||||
import ani.dantotsu.media.Author
|
import ani.dantotsu.media.Author
|
||||||
import ani.dantotsu.media.AuthorAdapter
|
import ani.dantotsu.media.AuthorAdapter
|
||||||
import ani.dantotsu.media.Character
|
import ani.dantotsu.media.Character
|
||||||
import ani.dantotsu.media.CharacterAdapter
|
import ani.dantotsu.media.CharacterAdapter
|
||||||
import ani.dantotsu.media.Media
|
import ani.dantotsu.media.Media
|
||||||
import ani.dantotsu.media.MediaAdaptor
|
import ani.dantotsu.media.MediaAdaptor
|
||||||
import ani.dantotsu.media.user.ListActivity
|
|
||||||
import ani.dantotsu.setBaseline
|
import ani.dantotsu.setBaseline
|
||||||
import ani.dantotsu.setSlideIn
|
import ani.dantotsu.setSlideIn
|
||||||
import ani.dantotsu.setSlideUp
|
import ani.dantotsu.setSlideUp
|
||||||
import ani.dantotsu.util.AniMarkdown.Companion.getFullAniHTML
|
import ani.dantotsu.util.AniMarkdown.Companion.getFullAniHTML
|
||||||
import ani.dantotsu.util.Logger
|
|
||||||
import eu.kanade.tachiyomi.util.system.getSerializableCompat
|
import eu.kanade.tachiyomi.util.system.getSerializableCompat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -137,7 +132,7 @@ class ProfileFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
user.favourites?.staff?.nodes?.forEach { i ->
|
user.favourites?.staff?.nodes?.forEach { i ->
|
||||||
favStaff.add(Author(i.id, i.name.full, i.image.large , "" ))
|
favStaff.add(Author(i.id, i.name.full, i.image.large, ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
setFavPeople()
|
setFavPeople()
|
||||||
|
@ -159,7 +154,8 @@ class ProfileFragment : Fragment() {
|
||||||
binding.profileFavStaffRecycler.layoutManager = LinearLayoutManager(
|
binding.profileFavStaffRecycler.layoutManager = LinearLayoutManager(
|
||||||
activity, LinearLayoutManager.HORIZONTAL, false
|
activity, LinearLayoutManager.HORIZONTAL, false
|
||||||
)
|
)
|
||||||
binding.profileFavStaffRecycler.layoutAnimation = LayoutAnimationController(setSlideIn(), 0.25f)
|
binding.profileFavStaffRecycler.layoutAnimation =
|
||||||
|
LayoutAnimationController(setSlideIn(), 0.25f)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (favCharacter.isEmpty()) {
|
if (favCharacter.isEmpty()) {
|
||||||
|
@ -169,7 +165,8 @@ class ProfileFragment : Fragment() {
|
||||||
binding.profileFavCharactersRecycler.layoutManager = LinearLayoutManager(
|
binding.profileFavCharactersRecycler.layoutManager = LinearLayoutManager(
|
||||||
activity, LinearLayoutManager.HORIZONTAL, false
|
activity, LinearLayoutManager.HORIZONTAL, false
|
||||||
)
|
)
|
||||||
binding.profileFavCharactersRecycler.layoutAnimation = LayoutAnimationController(setSlideIn(), 0.25f)
|
binding.profileFavCharactersRecycler.layoutAnimation =
|
||||||
|
LayoutAnimationController(setSlideIn(), 0.25f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +186,7 @@ class ProfileFragment : Fragment() {
|
||||||
recyclerView.visibility = View.GONE
|
recyclerView.visibility = View.GONE
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
if (it.isNotEmpty()) {
|
if (it.isNotEmpty()) {
|
||||||
recyclerView.adapter = MediaAdaptor(0, it, activity, fav=true)
|
recyclerView.adapter = MediaAdaptor(0, it, activity, fav = true)
|
||||||
recyclerView.layoutManager = LinearLayoutManager(
|
recyclerView.layoutManager = LinearLayoutManager(
|
||||||
activity,
|
activity,
|
||||||
LinearLayoutManager.HORIZONTAL,
|
LinearLayoutManager.HORIZONTAL,
|
||||||
|
|
|
@ -10,8 +10,7 @@ import ani.dantotsu.themes.ThemeManager
|
||||||
import ani.dantotsu.toast
|
import ani.dantotsu.toast
|
||||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAOptions
|
import com.github.aachartmodel.aainfographics.aachartcreator.AAOptions
|
||||||
|
|
||||||
class SingleStatActivity : AppCompatActivity()
|
class SingleStatActivity : AppCompatActivity() {
|
||||||
{
|
|
||||||
private lateinit var binding: ActivitySingleStatBinding
|
private lateinit var binding: ActivitySingleStatBinding
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
|
@ -58,10 +58,13 @@ class StatsFragment :
|
||||||
binding.statisticList.adapter = adapter
|
binding.statisticList.adapter = adapter
|
||||||
binding.statisticList.recycledViewPool.setMaxRecycledViews(0, 0)
|
binding.statisticList.recycledViewPool.setMaxRecycledViews(0, 0)
|
||||||
binding.statisticList.isNestedScrollingEnabled = true
|
binding.statisticList.isNestedScrollingEnabled = true
|
||||||
binding.statisticList.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
binding.statisticList.layoutManager =
|
||||||
|
LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||||
binding.statisticProgressBar.visibility = View.VISIBLE
|
binding.statisticProgressBar.visibility = View.VISIBLE
|
||||||
binding.compare.visibility = if (user.id == Anilist.userid) View.GONE else View.VISIBLE
|
binding.compare.visibility = if (user.id == Anilist.userid) View.GONE else View.VISIBLE
|
||||||
binding.filterContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin = statusBarHeight }
|
binding.filterContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
topMargin = statusBarHeight
|
||||||
|
}
|
||||||
|
|
||||||
binding.sourceType.setAdapter(
|
binding.sourceType.setAdapter(
|
||||||
ArrayAdapter(
|
ArrayAdapter(
|
||||||
|
|
|
@ -12,8 +12,8 @@ data class User(
|
||||||
val status: String? = null,
|
val status: String? = null,
|
||||||
val score: Float? = null,
|
val score: Float? = null,
|
||||||
val progress: Int? = null,
|
val progress: Int? = null,
|
||||||
val totalEpisodes : Int? = null,
|
val totalEpisodes: Int? = null,
|
||||||
val nextAiringEpisode : Int? = null,
|
val nextAiringEpisode: Int? = null,
|
||||||
) : java.io.Serializable {
|
) : java.io.Serializable {
|
||||||
companion object {
|
companion object {
|
||||||
private const val serialVersionUID: Long = 1
|
private const val serialVersionUID: Long = 1
|
||||||
|
|
|
@ -5,13 +5,13 @@ import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import ani.dantotsu.blurImage
|
|
||||||
import ani.dantotsu.databinding.ItemFollowerBinding
|
import ani.dantotsu.databinding.ItemFollowerBinding
|
||||||
import ani.dantotsu.loadImage
|
import ani.dantotsu.loadImage
|
||||||
import ani.dantotsu.setAnimation
|
import ani.dantotsu.setAnimation
|
||||||
|
|
||||||
|
|
||||||
class UsersAdapter(private val user: ArrayList<User>) : RecyclerView.Adapter<UsersAdapter.UsersViewHolder>() {
|
class UsersAdapter(private val user: ArrayList<User>) :
|
||||||
|
RecyclerView.Adapter<UsersAdapter.UsersViewHolder>() {
|
||||||
|
|
||||||
inner class UsersViewHolder(val binding: ItemFollowerBinding) :
|
inner class UsersViewHolder(val binding: ItemFollowerBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
|
@ -14,9 +14,10 @@ class UsersDialogFragment : BottomSheetDialogFragment() {
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private var userList = arrayListOf<User>()
|
private var userList = arrayListOf<User>()
|
||||||
fun userList(user: ArrayList<User>){
|
fun userList(user: ArrayList<User>) {
|
||||||
userList = user
|
userList = user
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
|
@ -25,6 +26,7 @@ class UsersDialogFragment : BottomSheetDialogFragment() {
|
||||||
_binding = BottomSheetUsersBinding.inflate(inflater, container, false)
|
_binding = BottomSheetUsersBinding.inflate(inflater, container, false)
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package ani.dantotsu.profile.activity
|
package ani.dantotsu.profile.activity
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
@ -18,13 +17,8 @@ import ani.dantotsu.profile.UsersDialogFragment
|
||||||
import ani.dantotsu.setAnimation
|
import ani.dantotsu.setAnimation
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
import ani.dantotsu.util.AniMarkdown.Companion.getBasicAniHTML
|
import ani.dantotsu.util.AniMarkdown.Companion.getBasicAniHTML
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
|
||||||
import com.bumptech.glide.load.model.GlideUrl
|
|
||||||
import com.bumptech.glide.request.RequestOptions
|
|
||||||
import com.xwray.groupie.GroupieAdapter
|
import com.xwray.groupie.GroupieAdapter
|
||||||
import com.xwray.groupie.viewbinding.BindableItem
|
import com.xwray.groupie.viewbinding.BindableItem
|
||||||
import jp.wasabeef.glide.transformations.BlurTransformation
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
@ -108,11 +102,12 @@ class ActivityItem(
|
||||||
}
|
}
|
||||||
val context = binding.root.context
|
val context = binding.root.context
|
||||||
val userList = arrayListOf<User>()
|
val userList = arrayListOf<User>()
|
||||||
activity.likes?.forEach{ i ->
|
activity.likes?.forEach { i ->
|
||||||
userList.add(User(i.id, i.name.toString(), i.avatar?.medium, i.bannerImage))
|
userList.add(User(i.id, i.name.toString(), i.avatar?.medium, i.bannerImage))
|
||||||
}
|
}
|
||||||
binding.activityLike.setOnLongClickListener{
|
binding.activityLike.setOnLongClickListener {
|
||||||
UsersDialogFragment().apply { userList(userList)
|
UsersDialogFragment().apply {
|
||||||
|
userList(userList)
|
||||||
show(fragActivity.supportFragmentManager, "dialog")
|
show(fragActivity.supportFragmentManager, "dialog")
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -126,8 +121,10 @@ class ActivityItem(
|
||||||
binding.activityContent.visibility = View.GONE
|
binding.activityContent.visibility = View.GONE
|
||||||
binding.activityBannerContainer.visibility = View.VISIBLE
|
binding.activityBannerContainer.visibility = View.VISIBLE
|
||||||
binding.activityMediaName.text = activity.media?.title?.userPreferred
|
binding.activityMediaName.text = activity.media?.title?.userPreferred
|
||||||
val activityText = "${activity.user!!.name} ${activity.status} ${activity.progress
|
val activityText = "${activity.user!!.name} ${activity.status} ${
|
||||||
?: activity.media?.title?.userPreferred}"
|
activity.progress
|
||||||
|
?: activity.media?.title?.userPreferred
|
||||||
|
}"
|
||||||
binding.activityText.text = activityText
|
binding.activityText.text = activityText
|
||||||
binding.activityCover.loadImage(cover)
|
binding.activityCover.loadImage(cover)
|
||||||
blurImage(binding.activityBannerImage, banner ?: cover)
|
blurImage(binding.activityBannerImage, banner ?: cover)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ani.dantotsu.connections.anilist.api.NotificationType
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class ActivityItemBuilder {
|
class ActivityItemBuilder {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -109,6 +110,7 @@ class ActivityItemBuilder {
|
||||||
else -> "Just now"
|
else -> "Just now"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
1L -> "1 day ago"
|
1L -> "1 day ago"
|
||||||
in 2..6 -> "$daysDifference days ago"
|
in 2..6 -> "$daysDifference days ago"
|
||||||
else -> SimpleDateFormat("dd MMM yyyy", Locale.getDefault()).format(targetDate)
|
else -> SimpleDateFormat("dd MMM yyyy", Locale.getDefault()).format(targetDate)
|
||||||
|
|
|
@ -31,7 +31,8 @@ class FeedActivity : AppCompatActivity() {
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
navBar = binding.feedNavBar
|
navBar = binding.feedNavBar
|
||||||
val navBarMargin = if (resources.configuration.orientation ==
|
val navBarMargin = if (resources.configuration.orientation ==
|
||||||
Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
|
Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
) 0 else navBarHeight
|
||||||
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin = navBarMargin }
|
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin = navBarMargin }
|
||||||
val personalTab = navBar.createTab(R.drawable.ic_round_person_24, "Following")
|
val personalTab = navBar.createTab(R.drawable.ic_round_person_24, "Following")
|
||||||
val globalTab = navBar.createTab(R.drawable.ic_globe_24, "Global")
|
val globalTab = navBar.createTab(R.drawable.ic_globe_24, "Global")
|
||||||
|
@ -67,10 +68,12 @@ class FeedActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
super.onConfigurationChanged(newConfig)
|
super.onConfigurationChanged(newConfig)
|
||||||
val margin = if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
|
val margin =
|
||||||
val params : ViewGroup.MarginLayoutParams =
|
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
|
||||||
|
val params: ViewGroup.MarginLayoutParams =
|
||||||
binding.feedViewPager.layoutParams as ViewGroup.MarginLayoutParams
|
binding.feedViewPager.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
val paramsNav : ViewGroup.MarginLayoutParams = navBar.layoutParams as ViewGroup.MarginLayoutParams
|
val paramsNav: ViewGroup.MarginLayoutParams =
|
||||||
|
navBar.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
params.updateMargins(bottom = margin)
|
params.updateMargins(bottom = margin)
|
||||||
paramsNav.updateMargins(bottom = margin)
|
paramsNav.updateMargins(bottom = margin)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ import ani.dantotsu.databinding.FragmentFeedBinding
|
||||||
import ani.dantotsu.media.MediaDetailsActivity
|
import ani.dantotsu.media.MediaDetailsActivity
|
||||||
import ani.dantotsu.profile.ProfileActivity
|
import ani.dantotsu.profile.ProfileActivity
|
||||||
import ani.dantotsu.setBaseline
|
import ani.dantotsu.setBaseline
|
||||||
import ani.dantotsu.snackString
|
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import com.xwray.groupie.GroupieAdapter
|
import com.xwray.groupie.GroupieAdapter
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -57,7 +56,7 @@ class FeedFragment : Fragment() {
|
||||||
|
|
||||||
val navBar = if (userId != null) {
|
val navBar = if (userId != null) {
|
||||||
(activity as ProfileActivity).navBar
|
(activity as ProfileActivity).navBar
|
||||||
}else{
|
} else {
|
||||||
(activity as FeedActivity).navBar
|
(activity as FeedActivity).navBar
|
||||||
}
|
}
|
||||||
binding.listRecyclerView.setBaseline(navBar)
|
binding.listRecyclerView.setBaseline(navBar)
|
||||||
|
@ -74,7 +73,7 @@ class FeedFragment : Fragment() {
|
||||||
binding.root.requestLayout()
|
binding.root.requestLayout()
|
||||||
val navBar = if (userId != null) {
|
val navBar = if (userId != null) {
|
||||||
(activity as ProfileActivity).navBar
|
(activity as ProfileActivity).navBar
|
||||||
}else{
|
} else {
|
||||||
(activity as FeedActivity).navBar
|
(activity as FeedActivity).navBar
|
||||||
}
|
}
|
||||||
binding.listRecyclerView.setBaseline(navBar)
|
binding.listRecyclerView.setBaseline(navBar)
|
||||||
|
@ -85,10 +84,17 @@ class FeedFragment : Fragment() {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
res?.data?.page?.activities?.let { activities ->
|
res?.data?.page?.activities?.let { activities ->
|
||||||
activityList = activities
|
activityList = activities
|
||||||
val filtered = activityList.filterNot { //filter out messages that are not directed to the user
|
val filtered =
|
||||||
|
activityList.filterNot { //filter out messages that are not directed to the user
|
||||||
it.recipient?.id != null && it.recipient.id != Anilist.userid
|
it.recipient?.id != null && it.recipient.id != Anilist.userid
|
||||||
}
|
}
|
||||||
adapter.update(filtered.map { ActivityItem(it, ::onActivityClick,requireActivity()) })
|
adapter.update(filtered.map {
|
||||||
|
ActivityItem(
|
||||||
|
it,
|
||||||
|
::onActivityClick,
|
||||||
|
requireActivity()
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
binding.listProgressBar.visibility = ViewGroup.GONE
|
binding.listProgressBar.visibility = ViewGroup.GONE
|
||||||
val scrollView = binding.listRecyclerView
|
val scrollView = binding.listRecyclerView
|
||||||
|
@ -134,7 +140,13 @@ class FeedFragment : Fragment() {
|
||||||
val filtered = activities.filterNot {
|
val filtered = activities.filterNot {
|
||||||
it.recipient?.id != null && it.recipient.id != Anilist.userid
|
it.recipient?.id != null && it.recipient.id != Anilist.userid
|
||||||
}
|
}
|
||||||
adapter.addAll(filtered.map { ActivityItem(it, ::onActivityClick,requireActivity()) })
|
adapter.addAll(filtered.map {
|
||||||
|
ActivityItem(
|
||||||
|
it,
|
||||||
|
::onActivityClick,
|
||||||
|
requireActivity()
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
binding.feedSwipeRefresh.isRefreshing = false
|
binding.feedSwipeRefresh.isRefreshing = false
|
||||||
onFinish()
|
onFinish()
|
||||||
|
@ -150,6 +162,7 @@ class FeedFragment : Fragment() {
|
||||||
.putExtra("userId", id), null
|
.putExtra("userId", id), null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"MEDIA" -> {
|
"MEDIA" -> {
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
activity, Intent(activity, MediaDetailsActivity::class.java)
|
activity, Intent(activity, MediaDetailsActivity::class.java)
|
||||||
|
|
|
@ -22,7 +22,6 @@ import ani.dantotsu.notifications.comment.CommentStore
|
||||||
import ani.dantotsu.profile.ProfileActivity
|
import ani.dantotsu.profile.ProfileActivity
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.snackString
|
|
||||||
import ani.dantotsu.statusBarHeight
|
import ani.dantotsu.statusBarHeight
|
||||||
import ani.dantotsu.themes.ThemeManager
|
import ani.dantotsu.themes.ThemeManager
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package ani.dantotsu.profile.activity
|
package ani.dantotsu.profile.activity
|
||||||
|
|
||||||
import android.util.TypedValue
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.blurImage
|
import ani.dantotsu.blurImage
|
||||||
import ani.dantotsu.connections.anilist.api.Notification
|
import ani.dantotsu.connections.anilist.api.Notification
|
||||||
|
@ -60,7 +58,8 @@ class NotificationItem(
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.layoutParams.height = userHeight
|
binding.notificationBannerImage.layoutParams.height = userHeight
|
||||||
binding.notificationGradiant.layoutParams.height = userHeight
|
binding.notificationGradiant.layoutParams.height = userHeight
|
||||||
(binding.notificationTextContainer.layoutParams as ViewGroup.MarginLayoutParams).marginStart = userHeight
|
(binding.notificationTextContainer.layoutParams as ViewGroup.MarginLayoutParams).marginStart =
|
||||||
|
userHeight
|
||||||
} else {
|
} else {
|
||||||
binding.notificationCover.visibility = View.VISIBLE
|
binding.notificationCover.visibility = View.VISIBLE
|
||||||
binding.notificationCoverUser.visibility = View.VISIBLE
|
binding.notificationCoverUser.visibility = View.VISIBLE
|
||||||
|
@ -68,7 +67,8 @@ class NotificationItem(
|
||||||
binding.notificationCover.loadImage(notification.media?.coverImage?.large)
|
binding.notificationCover.loadImage(notification.media?.coverImage?.large)
|
||||||
binding.notificationBannerImage.layoutParams.height = defaultHeight
|
binding.notificationBannerImage.layoutParams.height = defaultHeight
|
||||||
binding.notificationGradiant.layoutParams.height = defaultHeight
|
binding.notificationGradiant.layoutParams.height = defaultHeight
|
||||||
(binding.notificationTextContainer.layoutParams as ViewGroup.MarginLayoutParams).marginStart = textMarginStart
|
(binding.notificationTextContainer.layoutParams as ViewGroup.MarginLayoutParams).marginStart =
|
||||||
|
textMarginStart
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +308,9 @@ class NotificationItem(
|
||||||
if (notification.commentId != null && notification.mediaId != null) {
|
if (notification.commentId != null && notification.mediaId != null) {
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.mediaId, notification.commentId, NotificationClickType.COMMENT
|
notification.mediaId,
|
||||||
|
notification.commentId,
|
||||||
|
NotificationClickType.COMMENT
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,10 @@ import ani.dantotsu.setAnimation
|
||||||
class SettingsAdapter(private val settings: ArrayList<Settings>) :
|
class SettingsAdapter(private val settings: ArrayList<Settings>) :
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
inner class SettingsViewHolder(val binding: ItemSettingsBinding) :
|
inner class SettingsViewHolder(val binding: ItemSettingsBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {}
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
inner class SettingsSwitchViewHolder(val binding: ItemSettingsSwitchBinding) :
|
inner class SettingsSwitchViewHolder(val binding: ItemSettingsSwitchBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {}
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
|
@ -82,7 +82,7 @@ class SettingsAdapter(private val settings: ArrayList<Settings>) :
|
||||||
b.settingsButton.setOnCheckedChangeListener { _, isChecked ->
|
b.settingsButton.setOnCheckedChangeListener { _, isChecked ->
|
||||||
settings.switch?.invoke(isChecked, b)
|
settings.switch?.invoke(isChecked, b)
|
||||||
}
|
}
|
||||||
b.settingsLayout.setOnLongClickListener() {
|
b.settingsLayout.setOnLongClickListener {
|
||||||
settings.onLongClick?.invoke()
|
settings.onLongClick?.invoke()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package ani.dantotsu.util
|
package ani.dantotsu.util
|
||||||
|
|
||||||
import ani.dantotsu.util.ColorEditor.Companion.toCssColor
|
import ani.dantotsu.util.ColorEditor.Companion.toCssColor
|
||||||
import ani.dantotsu.util.ColorEditor.Companion.toHexColor
|
|
||||||
|
|
||||||
class AniMarkdown { //istg anilist has the worst api
|
class AniMarkdown { //istg anilist has the worst api
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -133,7 +133,11 @@ object Logger {
|
||||||
shareIntent.type = "text/plain"
|
shareIntent.type = "text/plain"
|
||||||
shareIntent.putExtra(
|
shareIntent.putExtra(
|
||||||
Intent.EXTRA_STREAM,
|
Intent.EXTRA_STREAM,
|
||||||
FileProvider.getUriForFile(context, "${BuildConfig.APPLICATION_ID}.provider", fileToUse!!)
|
FileProvider.getUriForFile(
|
||||||
|
context,
|
||||||
|
"${BuildConfig.APPLICATION_ID}.provider",
|
||||||
|
fileToUse!!
|
||||||
|
)
|
||||||
)
|
)
|
||||||
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Log file")
|
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Log file")
|
||||||
shareIntent.putExtra(Intent.EXTRA_TEXT, "Log file")
|
shareIntent.putExtra(Intent.EXTRA_TEXT, "Log file")
|
||||||
|
|
|
@ -62,7 +62,8 @@ class StoragePermissions {
|
||||||
return hasDirAccess(context, path)
|
return hasDirAccess(context, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AppCompatActivity.accessAlertDialog(launcher: LauncherWrapper,
|
fun AppCompatActivity.accessAlertDialog(
|
||||||
|
launcher: LauncherWrapper,
|
||||||
force: Boolean = false,
|
force: Boolean = false,
|
||||||
complete: (Boolean) -> Unit
|
complete: (Boolean) -> Unit
|
||||||
) {
|
) {
|
||||||
|
@ -97,11 +98,12 @@ class StoragePermissions {
|
||||||
|
|
||||||
class LauncherWrapper(
|
class LauncherWrapper(
|
||||||
activity: AppCompatActivity,
|
activity: AppCompatActivity,
|
||||||
contract: ActivityResultContracts.OpenDocumentTree)
|
contract: ActivityResultContracts.OpenDocumentTree
|
||||||
{
|
) {
|
||||||
private var launcher: ActivityResultLauncher<Uri?>
|
private var launcher: ActivityResultLauncher<Uri?>
|
||||||
var complete: (Boolean) -> Unit = {}
|
var complete: (Boolean) -> Unit = {}
|
||||||
init{
|
|
||||||
|
init {
|
||||||
launcher = activity.registerForActivityResult(contract) { uri ->
|
launcher = activity.registerForActivityResult(contract) { uri ->
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
activity.contentResolver.takePersistableUriPermission(
|
activity.contentResolver.takePersistableUriPermission(
|
||||||
|
|
|
@ -59,7 +59,8 @@ class ProfileStatsWidget : AppWidgetProvider() {
|
||||||
appWidgetId: Int
|
appWidgetId: Int
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val prefs = context.getSharedPreferences(getPrefsName(appWidgetId), Context.MODE_PRIVATE)
|
val prefs =
|
||||||
|
context.getSharedPreferences(getPrefsName(appWidgetId), Context.MODE_PRIVATE)
|
||||||
val backgroundColor =
|
val backgroundColor =
|
||||||
prefs.getInt(PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
|
prefs.getInt(PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
|
||||||
val backgroundFade = prefs.getInt(PREF_BACKGROUND_FADE, Color.parseColor("#00000000"))
|
val backgroundFade = prefs.getInt(PREF_BACKGROUND_FADE, Color.parseColor("#00000000"))
|
||||||
|
@ -87,7 +88,8 @@ class ProfileStatsWidget : AppWidgetProvider() {
|
||||||
val respond = Anilist.query.getUserProfile(userPref.toInt())
|
val respond = Anilist.query.getUserProfile(userPref.toInt())
|
||||||
respond?.data?.user?.let { user ->
|
respond?.data?.user?.let { user ->
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val views = RemoteViews(context.packageName, R.layout.statistics_widget).apply {
|
val views =
|
||||||
|
RemoteViews(context.packageName, R.layout.statistics_widget).apply {
|
||||||
setImageViewBitmap(
|
setImageViewBitmap(
|
||||||
R.id.backgroundView,
|
R.id.backgroundView,
|
||||||
gradientDrawable.toBitmap(
|
gradientDrawable.toBitmap(
|
||||||
|
@ -100,8 +102,14 @@ class ProfileStatsWidget : AppWidgetProvider() {
|
||||||
PendingIntent.getActivity(
|
PendingIntent.getActivity(
|
||||||
context,
|
context,
|
||||||
1,
|
1,
|
||||||
Intent(context, ProfileStatsConfigure::class.java).apply {
|
Intent(
|
||||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
context,
|
||||||
|
ProfileStatsConfigure::class.java
|
||||||
|
).apply {
|
||||||
|
putExtra(
|
||||||
|
AppWidgetManager.EXTRA_APPWIDGET_ID,
|
||||||
|
appWidgetId
|
||||||
|
)
|
||||||
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
|
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
|
||||||
},
|
},
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||||
|
@ -221,6 +229,7 @@ class ProfileStatsWidget : AppWidgetProvider() {
|
||||||
fun getPrefsName(appWidgetId: Int): String {
|
fun getPrefsName(appWidgetId: Int): String {
|
||||||
return "ani.dantotsu.widgets.Statistics.${appWidgetId}"
|
return "ani.dantotsu.widgets.Statistics.${appWidgetId}"
|
||||||
}
|
}
|
||||||
|
|
||||||
const val PREF_BACKGROUND_COLOR = "background_color"
|
const val PREF_BACKGROUND_COLOR = "background_color"
|
||||||
const val PREF_BACKGROUND_FADE = "background_fade"
|
const val PREF_BACKGROUND_FADE = "background_fade"
|
||||||
const val PREF_TITLE_TEXT_COLOR = "title_text_color"
|
const val PREF_TITLE_TEXT_COLOR = "title_text_color"
|
||||||
|
|
|
@ -48,8 +48,10 @@ class UpcomingWidgetConfigure : AppCompatActivity(),
|
||||||
binding = UpcomingWidgetConfigureBinding.inflate(layoutInflater)
|
binding = UpcomingWidgetConfigureBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
val prefs = getSharedPreferences(UpcomingWidget.PREFS_NAME, Context.MODE_PRIVATE)
|
val prefs = getSharedPreferences(UpcomingWidget.PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
val topBackground = prefs.getInt(UpcomingWidget.PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
|
val topBackground =
|
||||||
(binding.topBackgroundButton as MaterialButton).iconTint = ColorStateList.valueOf(topBackground)
|
prefs.getInt(UpcomingWidget.PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
|
||||||
|
(binding.topBackgroundButton as MaterialButton).iconTint =
|
||||||
|
ColorStateList.valueOf(topBackground)
|
||||||
binding.topBackgroundButton.setOnClickListener {
|
binding.topBackgroundButton.setOnClickListener {
|
||||||
val tag = UpcomingWidget.PREF_BACKGROUND_COLOR
|
val tag = UpcomingWidget.PREF_BACKGROUND_COLOR
|
||||||
SimpleColorDialog().title(R.string.custom_theme)
|
SimpleColorDialog().title(R.string.custom_theme)
|
||||||
|
@ -66,8 +68,10 @@ class UpcomingWidgetConfigure : AppCompatActivity(),
|
||||||
.neg()
|
.neg()
|
||||||
.show(this@UpcomingWidgetConfigure, tag)
|
.show(this@UpcomingWidgetConfigure, tag)
|
||||||
}
|
}
|
||||||
val bottomBackground = prefs.getInt(UpcomingWidget.PREF_BACKGROUND_FADE, Color.parseColor("#00000000"))
|
val bottomBackground =
|
||||||
(binding.bottomBackgroundButton as MaterialButton).iconTint = ColorStateList.valueOf(bottomBackground)
|
prefs.getInt(UpcomingWidget.PREF_BACKGROUND_FADE, Color.parseColor("#00000000"))
|
||||||
|
(binding.bottomBackgroundButton as MaterialButton).iconTint =
|
||||||
|
ColorStateList.valueOf(bottomBackground)
|
||||||
binding.bottomBackgroundButton.setOnClickListener {
|
binding.bottomBackgroundButton.setOnClickListener {
|
||||||
val tag = UpcomingWidget.PREF_BACKGROUND_FADE
|
val tag = UpcomingWidget.PREF_BACKGROUND_FADE
|
||||||
SimpleColorDialog().title(R.string.custom_theme)
|
SimpleColorDialog().title(R.string.custom_theme)
|
||||||
|
@ -85,7 +89,8 @@ class UpcomingWidgetConfigure : AppCompatActivity(),
|
||||||
.show(this@UpcomingWidgetConfigure, tag)
|
.show(this@UpcomingWidgetConfigure, tag)
|
||||||
}
|
}
|
||||||
val titleTextColor = prefs.getInt(UpcomingWidget.PREF_TITLE_TEXT_COLOR, Color.WHITE)
|
val titleTextColor = prefs.getInt(UpcomingWidget.PREF_TITLE_TEXT_COLOR, Color.WHITE)
|
||||||
(binding.titleColorButton as MaterialButton).iconTint = ColorStateList.valueOf(titleTextColor)
|
(binding.titleColorButton as MaterialButton).iconTint =
|
||||||
|
ColorStateList.valueOf(titleTextColor)
|
||||||
binding.titleColorButton.setOnClickListener {
|
binding.titleColorButton.setOnClickListener {
|
||||||
val tag = UpcomingWidget.PREF_TITLE_TEXT_COLOR
|
val tag = UpcomingWidget.PREF_TITLE_TEXT_COLOR
|
||||||
SimpleColorDialog().title(R.string.custom_theme)
|
SimpleColorDialog().title(R.string.custom_theme)
|
||||||
|
@ -102,7 +107,8 @@ class UpcomingWidgetConfigure : AppCompatActivity(),
|
||||||
.show(this@UpcomingWidgetConfigure, tag)
|
.show(this@UpcomingWidgetConfigure, tag)
|
||||||
}
|
}
|
||||||
val countdownTextColor = prefs.getInt(UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR, Color.WHITE)
|
val countdownTextColor = prefs.getInt(UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR, Color.WHITE)
|
||||||
(binding.countdownColorButton as MaterialButton).iconTint = ColorStateList.valueOf(countdownTextColor)
|
(binding.countdownColorButton as MaterialButton).iconTint =
|
||||||
|
ColorStateList.valueOf(countdownTextColor)
|
||||||
binding.countdownColorButton.setOnClickListener {
|
binding.countdownColorButton.setOnClickListener {
|
||||||
val tag = UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR
|
val tag = UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR
|
||||||
SimpleColorDialog().title(R.string.custom_theme)
|
SimpleColorDialog().title(R.string.custom_theme)
|
||||||
|
@ -152,15 +158,27 @@ class UpcomingWidgetConfigure : AppCompatActivity(),
|
||||||
|
|
||||||
private fun themeColors() {
|
private fun themeColors() {
|
||||||
val typedValueSurface = TypedValue()
|
val typedValueSurface = TypedValue()
|
||||||
theme.resolveAttribute(com.google.android.material.R.attr.colorSurface, typedValueSurface, true)
|
theme.resolveAttribute(
|
||||||
|
com.google.android.material.R.attr.colorSurface,
|
||||||
|
typedValueSurface,
|
||||||
|
true
|
||||||
|
)
|
||||||
val backgroundColor = typedValueSurface.data
|
val backgroundColor = typedValueSurface.data
|
||||||
|
|
||||||
val typedValuePrimary = TypedValue()
|
val typedValuePrimary = TypedValue()
|
||||||
theme.resolveAttribute(com.google.android.material.R.attr.colorPrimary, typedValuePrimary, true)
|
theme.resolveAttribute(
|
||||||
|
com.google.android.material.R.attr.colorPrimary,
|
||||||
|
typedValuePrimary,
|
||||||
|
true
|
||||||
|
)
|
||||||
val textColor = typedValuePrimary.data
|
val textColor = typedValuePrimary.data
|
||||||
|
|
||||||
val typedValueOutline = TypedValue()
|
val typedValueOutline = TypedValue()
|
||||||
theme.resolveAttribute(com.google.android.material.R.attr.colorOutline, typedValueOutline, true)
|
theme.resolveAttribute(
|
||||||
|
com.google.android.material.R.attr.colorOutline,
|
||||||
|
typedValueOutline,
|
||||||
|
true
|
||||||
|
)
|
||||||
val subTextColor = typedValueOutline.data
|
val subTextColor = typedValueOutline.data
|
||||||
|
|
||||||
getSharedPreferences(UpcomingWidget.PREFS_NAME, Context.MODE_PRIVATE).edit().apply {
|
getSharedPreferences(UpcomingWidget.PREFS_NAME, Context.MODE_PRIVATE).edit().apply {
|
||||||
|
|
|
@ -23,7 +23,6 @@ import uy.kohesive.injekt.injectLazy
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URISyntaxException
|
import java.net.URISyntaxException
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple implementation for sources from a website.
|
* A simple implementation for sources from a website.
|
||||||
|
@ -89,14 +88,15 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
||||||
protected fun generateId(name: String, lang: String, versionId: Int): Long {
|
protected fun generateId(name: String, lang: String, versionId: Int): Long {
|
||||||
val key = "${name.lowercase()}/$lang/$versionId"
|
val key = "${name.lowercase()}/$lang/$versionId"
|
||||||
val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
|
val bytes = MessageDigest.getInstance("MD5").digest(key.toByteArray())
|
||||||
return (0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }.reduce(Long::or) and Long.MAX_VALUE
|
return (0..7).map { bytes[it].toLong() and 0xff shl 8 * (7 - it) }
|
||||||
|
.reduce(Long::or) and Long.MAX_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Headers builder for requests. Implementations can override this method for custom headers.
|
* Headers builder for requests. Implementations can override this method for custom headers.
|
||||||
*/
|
*/
|
||||||
protected open fun headersBuilder() = Headers.Builder().apply {
|
protected open fun headersBuilder() = Headers.Builder().apply {
|
||||||
add("User-Agent", NetworkHelper.defaultUserAgentProvider())
|
add("User-Agent", defaultUserAgentProvider())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,7 +148,11 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
||||||
"Use the non-RxJava API instead",
|
"Use the non-RxJava API instead",
|
||||||
ReplaceWith("getSearchAnime"),
|
ReplaceWith("getSearchAnime"),
|
||||||
)
|
)
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
override fun fetchSearchAnime(
|
||||||
|
page: Int,
|
||||||
|
query: String,
|
||||||
|
filters: AnimeFilterList
|
||||||
|
): Observable<AnimesPage> {
|
||||||
return Observable.defer {
|
return Observable.defer {
|
||||||
try {
|
try {
|
||||||
client.newCall(searchAnimeRequest(page, query, filters)).asObservableSuccess()
|
client.newCall(searchAnimeRequest(page, query, filters)).asObservableSuccess()
|
||||||
|
@ -170,7 +174,11 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
||||||
* @param query the search query.
|
* @param query the search query.
|
||||||
* @param filters the list of filters to apply.
|
* @param filters the list of filters to apply.
|
||||||
*/
|
*/
|
||||||
protected abstract fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request
|
protected abstract fun searchAnimeRequest(
|
||||||
|
page: Int,
|
||||||
|
query: String,
|
||||||
|
filters: AnimeFilterList
|
||||||
|
): Request
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the response from the site and returns a [AnimesPage] object.
|
* Parses the response from the site and returns a [AnimesPage] object.
|
||||||
|
@ -403,7 +411,8 @@ abstract class AnimeHttpSource : AnimeCatalogueSource {
|
||||||
video: Video,
|
video: Video,
|
||||||
tries: Int,
|
tries: Int,
|
||||||
): Long {
|
): Long {
|
||||||
val headers = Headers.Builder().addAll(video.headers ?: headers).add("Range", "bytes=0-1").build()
|
val headers =
|
||||||
|
Headers.Builder().addAll(video.headers ?: headers).add("Range", "bytes=0-1").build()
|
||||||
val request = GET(video.videoUrl!!, headers)
|
val request = GET(video.videoUrl!!, headers)
|
||||||
val response = client.newCall(request).execute()
|
val response = client.newCall(request).execute()
|
||||||
// parse the response headers to get the size of the video, in particular the content-range header
|
// parse the response headers to get the size of the video, in particular the content-range header
|
||||||
|
|
|
@ -207,8 +207,10 @@ class AnimeExtensionManager(
|
||||||
* @param extension The anime extension to be installed.
|
* @param extension The anime extension to be installed.
|
||||||
*/
|
*/
|
||||||
fun installExtension(extension: AnimeExtension.Available): Observable<InstallStep> {
|
fun installExtension(extension: AnimeExtension.Available): Observable<InstallStep> {
|
||||||
return installer.downloadAndInstall(api.getAnimeApkUrl(extension), extension.pkgName,
|
return installer.downloadAndInstall(
|
||||||
extension.name, MediaType.ANIME)
|
api.getAnimeApkUrl(extension), extension.pkgName,
|
||||||
|
extension.name, MediaType.ANIME
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -28,7 +28,8 @@ class PackageInstallerInstaller(private val service: Service) : Installer(servic
|
||||||
PackageInstaller.STATUS_FAILURE
|
PackageInstaller.STATUS_FAILURE
|
||||||
)) {
|
)) {
|
||||||
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
||||||
val userAction = intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)?.run {
|
val userAction =
|
||||||
|
intent.getParcelableExtraCompat<Intent>(Intent.EXTRA_INTENT)?.run {
|
||||||
IntentSanitizer.Builder()
|
IntentSanitizer.Builder()
|
||||||
.allowAction(this.action!!)
|
.allowAction(this.action!!)
|
||||||
.allowExtra(PackageInstaller.EXTRA_SESSION_ID) { id -> id == activeSession?.second }
|
.allowExtra(PackageInstaller.EXTRA_SESSION_ID) { id -> id == activeSession?.second }
|
||||||
|
|
|
@ -204,8 +204,10 @@ class MangaExtensionManager(
|
||||||
* @param extension The extension to be installed.
|
* @param extension The extension to be installed.
|
||||||
*/
|
*/
|
||||||
fun installExtension(extension: MangaExtension.Available): Observable<InstallStep> {
|
fun installExtension(extension: MangaExtension.Available): Observable<InstallStep> {
|
||||||
return installer.downloadAndInstall(api.getMangaApkUrl(extension), extension.pkgName,
|
return installer.downloadAndInstall(
|
||||||
extension.name, MediaType.MANGA)
|
api.getMangaApkUrl(extension), extension.pkgName,
|
||||||
|
extension.name, MediaType.MANGA
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -41,9 +41,11 @@ class ExtensionInstallActivity : AppCompatActivity() {
|
||||||
ThemeManager(this).applyTheme()
|
ThemeManager(this).applyTheme()
|
||||||
|
|
||||||
if (intent.hasExtra(ExtensionInstaller.EXTRA_EXTENSION_TYPE))
|
if (intent.hasExtra(ExtensionInstaller.EXTRA_EXTENSION_TYPE))
|
||||||
mediaType = intent.getSerializableExtraCompat<MediaType>(ExtensionInstaller.EXTRA_EXTENSION_TYPE)
|
mediaType =
|
||||||
|
intent.getSerializableExtraCompat<MediaType>(ExtensionInstaller.EXTRA_EXTENSION_TYPE)
|
||||||
if (intent.hasExtra(ExtensionInstaller.EXTRA_ADDON_TYPE))
|
if (intent.hasExtra(ExtensionInstaller.EXTRA_ADDON_TYPE))
|
||||||
addonType = intent.getSerializableExtraCompat<AddonType>(ExtensionInstaller.EXTRA_ADDON_TYPE)
|
addonType =
|
||||||
|
intent.getSerializableExtraCompat<AddonType>(ExtensionInstaller.EXTRA_ADDON_TYPE)
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
|
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
|
||||||
|
|
|
@ -37,14 +37,14 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||||
ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_EXPORTED)
|
ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_EXPORTED)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setAnimeListener(listener: AnimeListener) : ExtensionInstallReceiver {
|
fun setAnimeListener(listener: AnimeListener): ExtensionInstallReceiver {
|
||||||
this.type = MediaType.ANIME
|
this.type = MediaType.ANIME
|
||||||
animeListener = listener
|
animeListener = listener
|
||||||
this.animeListener
|
this.animeListener
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setMangaListener(listener: MangaListener) : ExtensionInstallReceiver {
|
fun setMangaListener(listener: MangaListener): ExtensionInstallReceiver {
|
||||||
this.type = MediaType.MANGA
|
this.type = MediaType.MANGA
|
||||||
mangaListener = listener
|
mangaListener = listener
|
||||||
return this
|
return this
|
||||||
|
@ -66,21 +66,33 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||||
when (type) {
|
when (type) {
|
||||||
MediaType.ANIME -> {
|
MediaType.ANIME -> {
|
||||||
when (val result = getAnimeExtensionFromIntent(context, intent)) {
|
when (val result = getAnimeExtensionFromIntent(context, intent)) {
|
||||||
is AnimeLoadResult.Success -> animeListener?.onExtensionInstalled(result.extension)
|
is AnimeLoadResult.Success -> animeListener?.onExtensionInstalled(
|
||||||
|
result.extension
|
||||||
|
)
|
||||||
|
|
||||||
|
is AnimeLoadResult.Untrusted -> animeListener?.onExtensionUntrusted(
|
||||||
|
result.extension
|
||||||
|
)
|
||||||
|
|
||||||
is AnimeLoadResult.Untrusted -> animeListener?.onExtensionUntrusted(result.extension)
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaType.MANGA -> {
|
MediaType.MANGA -> {
|
||||||
when (val result = getMangaExtensionFromIntent(context, intent)) {
|
when (val result = getMangaExtensionFromIntent(context, intent)) {
|
||||||
is MangaLoadResult.Success -> mangaListener?.onExtensionInstalled(result.extension)
|
is MangaLoadResult.Success -> mangaListener?.onExtensionInstalled(
|
||||||
|
result.extension
|
||||||
|
)
|
||||||
|
|
||||||
|
is MangaLoadResult.Untrusted -> mangaListener?.onExtensionUntrusted(
|
||||||
|
result.extension
|
||||||
|
)
|
||||||
|
|
||||||
is MangaLoadResult.Untrusted -> mangaListener?.onExtensionUntrusted(result.extension)
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> { }
|
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,17 +102,25 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||||
when (type) {
|
when (type) {
|
||||||
MediaType.ANIME -> {
|
MediaType.ANIME -> {
|
||||||
when (val result = getAnimeExtensionFromIntent(context, intent)) {
|
when (val result = getAnimeExtensionFromIntent(context, intent)) {
|
||||||
is AnimeLoadResult.Success -> animeListener?.onExtensionUpdated(result.extension)
|
is AnimeLoadResult.Success -> animeListener?.onExtensionUpdated(
|
||||||
|
result.extension
|
||||||
|
)
|
||||||
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaType.MANGA -> {
|
MediaType.MANGA -> {
|
||||||
when (val result = getMangaExtensionFromIntent(context, intent)) {
|
when (val result = getMangaExtensionFromIntent(context, intent)) {
|
||||||
is MangaLoadResult.Success -> mangaListener?.onExtensionUpdated(result.extension)
|
is MangaLoadResult.Success -> mangaListener?.onExtensionUpdated(
|
||||||
|
result.extension
|
||||||
|
)
|
||||||
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> { }
|
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,10 +134,12 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||||
MediaType.ANIME -> {
|
MediaType.ANIME -> {
|
||||||
animeListener?.onPackageUninstalled(pkgName)
|
animeListener?.onPackageUninstalled(pkgName)
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaType.MANGA -> {
|
MediaType.MANGA -> {
|
||||||
mangaListener?.onPackageUninstalled(pkgName)
|
mangaListener?.onPackageUninstalled(pkgName)
|
||||||
}
|
}
|
||||||
else -> { }
|
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +153,10 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||||
* @param intent The intent containing the package name of the extension.
|
* @param intent The intent containing the package name of the extension.
|
||||||
*/
|
*/
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
private suspend fun getAnimeExtensionFromIntent(context: Context, intent: Intent?): AnimeLoadResult {
|
private suspend fun getAnimeExtensionFromIntent(
|
||||||
|
context: Context,
|
||||||
|
intent: Intent?
|
||||||
|
): AnimeLoadResult {
|
||||||
val pkgName = getPackageNameFromIntent(intent)
|
val pkgName = getPackageNameFromIntent(intent)
|
||||||
if (pkgName == null) {
|
if (pkgName == null) {
|
||||||
Logger.log("Package name not found")
|
Logger.log("Package name not found")
|
||||||
|
@ -146,7 +171,10 @@ internal class ExtensionInstallReceiver : BroadcastReceiver() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
private suspend fun getMangaExtensionFromIntent(context: Context, intent: Intent?): MangaLoadResult {
|
private suspend fun getMangaExtensionFromIntent(
|
||||||
|
context: Context,
|
||||||
|
intent: Intent?
|
||||||
|
): MangaLoadResult {
|
||||||
val pkgName = getPackageNameFromIntent(intent)
|
val pkgName = getPackageNameFromIntent(intent)
|
||||||
if (pkgName == null) {
|
if (pkgName == null) {
|
||||||
Logger.log("Package name not found")
|
Logger.log("Package name not found")
|
||||||
|
|
|
@ -14,8 +14,8 @@ import ani.dantotsu.media.Type
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.extension.installer.PackageInstallerInstaller
|
|
||||||
import eu.kanade.tachiyomi.extension.installer.Installer
|
import eu.kanade.tachiyomi.extension.installer.Installer
|
||||||
|
import eu.kanade.tachiyomi.extension.installer.PackageInstallerInstaller
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller.Companion.EXTRA_DOWNLOAD_ID
|
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller.Companion.EXTRA_DOWNLOAD_ID
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller.Companion.EXTRA_EXTENSION_TYPE
|
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller.Companion.EXTRA_EXTENSION_TYPE
|
||||||
import eu.kanade.tachiyomi.util.system.getSerializableExtraCompat
|
import eu.kanade.tachiyomi.util.system.getSerializableExtraCompat
|
||||||
|
@ -48,7 +48,8 @@ class ExtensionInstallService : Service() {
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
val uri = intent?.data
|
val uri = intent?.data
|
||||||
val mediaType = intent?.getSerializableExtraCompat<MediaType>(EXTRA_EXTENSION_TYPE)
|
val mediaType = intent?.getSerializableExtraCompat<MediaType>(EXTRA_EXTENSION_TYPE)
|
||||||
val addonType = intent?.getSerializableExtraCompat<AddonType>(ExtensionInstaller.EXTRA_ADDON_TYPE)
|
val addonType =
|
||||||
|
intent?.getSerializableExtraCompat<AddonType>(ExtensionInstaller.EXTRA_ADDON_TYPE)
|
||||||
val id = intent?.getLongExtra(EXTRA_DOWNLOAD_ID, -1)?.takeIf { it != -1L }
|
val id = intent?.getLongExtra(EXTRA_DOWNLOAD_ID, -1)?.takeIf { it != -1L }
|
||||||
val installerUsed = intent?.getSerializableExtraCompat<BasePreferences.ExtensionInstaller>(
|
val installerUsed = intent?.getSerializableExtraCompat<BasePreferences.ExtensionInstaller>(
|
||||||
EXTRA_INSTALLER
|
EXTRA_INSTALLER
|
||||||
|
|
|
@ -14,14 +14,11 @@ import androidx.core.net.toUri
|
||||||
import ani.dantotsu.media.AddonType
|
import ani.dantotsu.media.AddonType
|
||||||
import ani.dantotsu.media.MediaType
|
import ani.dantotsu.media.MediaType
|
||||||
import ani.dantotsu.media.Type
|
import ani.dantotsu.media.Type
|
||||||
import ani.dantotsu.parsers.novel.NovelExtension
|
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.tachiyomi.extension.InstallStep
|
import eu.kanade.tachiyomi.extension.InstallStep
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
|
||||||
import eu.kanade.tachiyomi.extension.installer.Installer
|
import eu.kanade.tachiyomi.extension.installer.Installer
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
|
||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
@ -67,7 +64,12 @@ class ExtensionInstaller(private val context: Context) {
|
||||||
* @param url The url of the apk.
|
* @param url The url of the apk.
|
||||||
* @param extension The extension to install.
|
* @param extension The extension to install.
|
||||||
*/
|
*/
|
||||||
fun <T : Type> downloadAndInstall(url: String, pkgName: String, name: String, type: T): Observable<InstallStep> = Observable.defer {
|
fun <T : Type> downloadAndInstall(
|
||||||
|
url: String,
|
||||||
|
pkgName: String,
|
||||||
|
name: String,
|
||||||
|
type: T
|
||||||
|
): Observable<InstallStep> = Observable.defer {
|
||||||
val oldDownload = activeDownloads[pkgName]
|
val oldDownload = activeDownloads[pkgName]
|
||||||
if (oldDownload != null) {
|
if (oldDownload != null) {
|
||||||
deleteDownload(pkgName)
|
deleteDownload(pkgName)
|
||||||
|
@ -264,11 +266,15 @@ class ExtensionInstaller(private val context: Context) {
|
||||||
val localUri = cursor.getString(
|
val localUri = cursor.getString(
|
||||||
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI),
|
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI),
|
||||||
).removePrefix(FILE_SCHEME)
|
).removePrefix(FILE_SCHEME)
|
||||||
val type = MediaType.fromText(cursor.getString(
|
val type = MediaType.fromText(
|
||||||
|
cursor.getString(
|
||||||
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_DESCRIPTION),
|
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_DESCRIPTION),
|
||||||
)) ?: AddonType.fromText(cursor.getString(
|
)
|
||||||
|
) ?: AddonType.fromText(
|
||||||
|
cursor.getString(
|
||||||
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_DESCRIPTION),
|
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_DESCRIPTION),
|
||||||
)) ?: return
|
)
|
||||||
|
) ?: return
|
||||||
|
|
||||||
installApk(type, id, File(localUri).getUriCompat(context))
|
installApk(type, id, File(localUri).getUriCompat(context))
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ internal object ExtensionLoader {
|
||||||
|
|
||||||
val PACKAGE_FLAGS = PackageManager.GET_CONFIGURATIONS or
|
val PACKAGE_FLAGS = PackageManager.GET_CONFIGURATIONS or
|
||||||
PackageManager.GET_META_DATA or
|
PackageManager.GET_META_DATA or
|
||||||
@Suppress ("DEPRECATION") PackageManager.GET_SIGNATURES or
|
@Suppress("DEPRECATION") PackageManager.GET_SIGNATURES or
|
||||||
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||||
PackageManager.GET_SIGNING_CERTIFICATES else 0)
|
PackageManager.GET_SIGNING_CERTIFICATES else 0)
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ internal object ExtensionLoader {
|
||||||
Logger.log(error)
|
Logger.log(error)
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
}
|
}
|
||||||
if (!isPackageAnExtension(MediaType.ANIME,pkgInfo)) {
|
if (!isPackageAnExtension(MediaType.ANIME, pkgInfo)) {
|
||||||
Logger.log("Tried to load a package that wasn't a extension ($pkgName)")
|
Logger.log("Tried to load a package that wasn't a extension ($pkgName)")
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,8 @@ internal object ExtensionLoader {
|
||||||
// Validate lib version
|
// Validate lib version
|
||||||
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
|
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
|
||||||
if (libVersion == null || libVersion < ANIME_LIB_VERSION_MIN || libVersion > ANIME_LIB_VERSION_MAX) {
|
if (libVersion == null || libVersion < ANIME_LIB_VERSION_MIN || libVersion > ANIME_LIB_VERSION_MAX) {
|
||||||
Logger.log("Lib version is $libVersion, while only versions " +
|
Logger.log(
|
||||||
|
"Lib version is $libVersion, while only versions " +
|
||||||
"$ANIME_LIB_VERSION_MIN to $ANIME_LIB_VERSION_MAX are allowed"
|
"$ANIME_LIB_VERSION_MIN to $ANIME_LIB_VERSION_MAX are allowed"
|
||||||
)
|
)
|
||||||
return AnimeLoadResult.Error
|
return AnimeLoadResult.Error
|
||||||
|
@ -232,7 +233,8 @@ internal object ExtensionLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasReadme = appInfo.metaData.getInt("$ANIME_PACKAGE$XX_METADATA_HAS_README", 0) == 1
|
val hasReadme = appInfo.metaData.getInt("$ANIME_PACKAGE$XX_METADATA_HAS_README", 0) == 1
|
||||||
val hasChangelog = appInfo.metaData.getInt("$ANIME_PACKAGE$XX_METADATA_HAS_CHANGELOG", 0) == 1
|
val hasChangelog =
|
||||||
|
appInfo.metaData.getInt("$ANIME_PACKAGE$XX_METADATA_HAS_CHANGELOG", 0) == 1
|
||||||
|
|
||||||
val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader)
|
val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader)
|
||||||
|
|
||||||
|
@ -248,7 +250,8 @@ internal object ExtensionLoader {
|
||||||
}
|
}
|
||||||
.flatMap {
|
.flatMap {
|
||||||
try {
|
try {
|
||||||
when (val obj = Class.forName(it, false, classLoader).getDeclaredConstructor().newInstance()) {
|
when (val obj = Class.forName(it, false, classLoader).getDeclaredConstructor()
|
||||||
|
.newInstance()) {
|
||||||
is AnimeSource -> listOf(obj)
|
is AnimeSource -> listOf(obj)
|
||||||
is AnimeSourceFactory -> obj.createSources()
|
is AnimeSourceFactory -> obj.createSources()
|
||||||
else -> throw Exception("Unknown source class type! ${obj.javaClass}")
|
else -> throw Exception("Unknown source class type! ${obj.javaClass}")
|
||||||
|
@ -314,7 +317,8 @@ internal object ExtensionLoader {
|
||||||
// Validate lib version
|
// Validate lib version
|
||||||
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
|
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
|
||||||
if (libVersion == null || libVersion < MANGA_LIB_VERSION_MIN || libVersion > MANGA_LIB_VERSION_MAX) {
|
if (libVersion == null || libVersion < MANGA_LIB_VERSION_MIN || libVersion > MANGA_LIB_VERSION_MAX) {
|
||||||
Logger.log("Lib version is $libVersion, while only versions " +
|
Logger.log(
|
||||||
|
"Lib version is $libVersion, while only versions " +
|
||||||
"$MANGA_LIB_VERSION_MIN to $MANGA_LIB_VERSION_MAX are allowed"
|
"$MANGA_LIB_VERSION_MIN to $MANGA_LIB_VERSION_MAX are allowed"
|
||||||
)
|
)
|
||||||
return MangaLoadResult.Error
|
return MangaLoadResult.Error
|
||||||
|
@ -340,7 +344,8 @@ internal object ExtensionLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasReadme = appInfo.metaData.getInt("$MANGA_PACKAGE$XX_METADATA_HAS_README", 0) == 1
|
val hasReadme = appInfo.metaData.getInt("$MANGA_PACKAGE$XX_METADATA_HAS_README", 0) == 1
|
||||||
val hasChangelog = appInfo.metaData.getInt("$MANGA_PACKAGE$XX_METADATA_HAS_CHANGELOG", 0) == 1
|
val hasChangelog =
|
||||||
|
appInfo.metaData.getInt("$MANGA_PACKAGE$XX_METADATA_HAS_CHANGELOG", 0) == 1
|
||||||
|
|
||||||
val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader)
|
val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader)
|
||||||
|
|
||||||
|
@ -401,11 +406,13 @@ internal object ExtensionLoader {
|
||||||
* @param pkgInfo The package info of the application.
|
* @param pkgInfo The package info of the application.
|
||||||
*/
|
*/
|
||||||
private fun isPackageAnExtension(type: MediaType, pkgInfo: PackageInfo): Boolean {
|
private fun isPackageAnExtension(type: MediaType, pkgInfo: PackageInfo): Boolean {
|
||||||
return pkgInfo.reqFeatures.orEmpty().any { it.name == when (type) {
|
return pkgInfo.reqFeatures.orEmpty().any {
|
||||||
|
it.name == when (type) {
|
||||||
MediaType.ANIME -> ANIME_PACKAGE
|
MediaType.ANIME -> ANIME_PACKAGE
|
||||||
MediaType.MANGA -> MANGA_PACKAGE
|
MediaType.MANGA -> MANGA_PACKAGE
|
||||||
else -> ""
|
else -> ""
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -417,7 +424,7 @@ internal object ExtensionLoader {
|
||||||
val signatures = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
val signatures = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||||
pkgInfo.signingInfo.signingCertificateHistory
|
pkgInfo.signingInfo.signingCertificateHistory
|
||||||
else
|
else
|
||||||
@Suppress ("DEPRECATION") pkgInfo.signatures
|
@Suppress("DEPRECATION") pkgInfo.signatures
|
||||||
return if (signatures != null && signatures.isNotEmpty()) {
|
return if (signatures != null && signatures.isNotEmpty()) {
|
||||||
Hash.sha256(signatures.first().toByteArray())
|
Hash.sha256(signatures.first().toByteArray())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,8 +11,8 @@ import eu.kanade.tachiyomi.network.interceptor.UncaughtExceptionInterceptor
|
||||||
import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor
|
import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor
|
||||||
import okhttp3.Cache
|
import okhttp3.Cache
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
|
||||||
import okhttp3.brotli.BrotliInterceptor
|
import okhttp3.brotli.BrotliInterceptor
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,10 @@ class LocalAnimeSource(
|
||||||
override suspend fun getLatestUpdates(page: Int) = getSearchAnime(page, "", LATEST_FILTERS)
|
override suspend fun getLatestUpdates(page: Int) = getSearchAnime(page, "", LATEST_FILTERS)
|
||||||
|
|
||||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getPopularAnime"))
|
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getPopularAnime"))
|
||||||
override fun fetchPopularAnime(page: Int) = fetchSearchAnime(page, "", POPULAR_FILTERS)
|
override fun fetchPopularAnime(page: Int) = getSearchAnime
|
||||||
|
|
||||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getLatestUpdates"))
|
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getLatestUpdates"))
|
||||||
override fun fetchLatestUpdates(page: Int) = fetchSearchAnime(page, "", LATEST_FILTERS)
|
override fun fetchLatestUpdates(page: Int) = getSearchAnime
|
||||||
|
|
||||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getSearchAnime"))
|
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getSearchAnime"))
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<scale xmlns:android="http://schemas.android.com/apk/res/android"
|
<scale xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:duration="1000"
|
||||||
android:fromXScale="0.3"
|
android:fromXScale="0.3"
|
||||||
android:toXScale="1.0"
|
|
||||||
android:fromYScale="0.3"
|
android:fromYScale="0.3"
|
||||||
android:toYScale="1.0"
|
android:interpolator="@android:anim/overshoot_interpolator"
|
||||||
android:pivotX="50%"
|
android:pivotX="50%"
|
||||||
android:pivotY="50%"
|
android:pivotY="50%"
|
||||||
android:duration="1000"
|
android:toXScale="1.0"
|
||||||
android:interpolator="@android:anim/overshoot_interpolator"/>
|
android:toYScale="1.0" />
|
|
@ -1,25 +1,27 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item>
|
<item>
|
||||||
<shape android:shape="rectangle">
|
<shape android:shape="rectangle">
|
||||||
<corners
|
<corners
|
||||||
android:topLeftRadius="28dp"
|
|
||||||
android:topRightRadius="28dp"
|
|
||||||
android:bottomLeftRadius="0dp"
|
android:bottomLeftRadius="0dp"
|
||||||
android:bottomRightRadius="0dp"/>
|
android:bottomRightRadius="0dp"
|
||||||
|
android:topLeftRadius="28dp"
|
||||||
|
android:topRightRadius="28dp" />
|
||||||
</shape>
|
</shape>
|
||||||
</item>
|
</item>
|
||||||
<item
|
<item
|
||||||
|
android:bottom="-50dp"
|
||||||
android:left="-3dp"
|
android:left="-3dp"
|
||||||
android:right="-3dp"
|
android:right="-3dp">
|
||||||
android:bottom="-50dp">
|
|
||||||
<shape>
|
<shape>
|
||||||
<stroke android:width="2dp" android:color="@color/bg_white" />
|
<stroke
|
||||||
|
android:width="2dp"
|
||||||
|
android:color="@color/bg_white" />
|
||||||
<corners
|
<corners
|
||||||
android:topLeftRadius="28dp"
|
|
||||||
android:topRightRadius="28dp"
|
|
||||||
android:bottomLeftRadius="0dp"
|
android:bottomLeftRadius="0dp"
|
||||||
android:bottomRightRadius="0dp"/>
|
android:bottomRightRadius="0dp"
|
||||||
|
android:topLeftRadius="28dp"
|
||||||
|
android:topRightRadius="28dp" />
|
||||||
</shape>
|
</shape>
|
||||||
</item>
|
</item>
|
||||||
</layer-list>
|
</layer-list>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
android:viewportWidth="960"
|
android:viewportWidth="960"
|
||||||
android:viewportHeight="960"
|
android:viewportHeight="960">
|
||||||
android:tint="?attr/colorControlNormal">
|
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white"
|
android:fillColor="@android:color/white"
|
||||||
android:pathData="M480,600Q530,600 565,565Q600,530 600,480Q600,430 565,395Q530,360 480,360Q430,360 395,395Q360,430 360,480Q360,530 395,565Q430,600 480,600ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
|
android:pathData="M480,600Q530,600 565,565Q600,530 600,480Q600,430 565,395Q530,360 480,360Q430,360 395,395Q360,430 360,480Q360,530 395,565Q430,600 480,600ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="960"
|
android:autoMirrored="true"
|
||||||
android:viewportHeight="960"
|
|
||||||
android:tint="?attr/colorControlNormal"
|
android:tint="?attr/colorControlNormal"
|
||||||
android:autoMirrored="true">
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white"
|
android:fillColor="@android:color/white"
|
||||||
android:pathData="M480,560Q447,560 423.5,536.5Q400,513 400,480Q400,447 423.5,423.5Q447,400 480,400Q513,400 536.5,423.5Q560,447 560,480Q560,513 536.5,536.5Q513,560 480,560ZM480,840Q341,840 239,748.5Q137,657 122,520L204,520Q218,624 296.5,692Q375,760 480,760Q597,760 678.5,678.5Q760,597 760,480Q760,363 678.5,281.5Q597,200 480,200Q411,200 351,232Q291,264 250,320L360,320L360,400L120,400L120,160L200,160L200,254Q251,190 324.5,155Q398,120 480,120Q555,120 620.5,148.5Q686,177 734.5,225.5Q783,274 811.5,339.5Q840,405 840,480Q840,555 811.5,620.5Q783,686 734.5,734.5Q686,783 620.5,811.5Q555,840 480,840Z"/>
|
android:pathData="M480,560Q447,560 423.5,536.5Q400,513 400,480Q400,447 423.5,423.5Q447,400 480,400Q513,400 536.5,423.5Q560,447 560,480Q560,513 536.5,536.5Q513,560 480,560ZM480,840Q341,840 239,748.5Q137,657 122,520L204,520Q218,624 296.5,692Q375,760 480,760Q597,760 678.5,678.5Q760,597 760,480Q760,363 678.5,281.5Q597,200 480,200Q411,200 351,232Q291,264 250,320L360,320L360,400L120,400L120,160L200,160L200,254Q251,190 324.5,155Q398,120 480,120Q555,120 620.5,148.5Q686,177 734.5,225.5Q783,274 811.5,339.5Q840,405 840,480Q840,555 811.5,620.5Q783,686 734.5,734.5Q686,783 620.5,811.5Q555,840 480,840Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
android:viewportWidth="960"
|
android:viewportWidth="960"
|
||||||
android:viewportHeight="960"
|
android:viewportHeight="960">
|
||||||
android:tint="?attr/colorControlNormal">
|
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white"
|
android:fillColor="@android:color/white"
|
||||||
android:pathData="M120,580Q112,580 106,574Q100,568 100,560Q100,552 106,546Q112,540 120,540Q128,540 134,546Q140,552 140,560Q140,568 134,574Q128,580 120,580ZM120,420Q112,420 106,414Q100,408 100,400Q100,392 106,386Q112,380 120,380Q128,380 134,386Q140,392 140,400Q140,408 134,414Q128,420 120,420ZM240,760Q223,760 211.5,748.5Q200,737 200,720Q200,703 211.5,691.5Q223,680 240,680Q257,680 268.5,691.5Q280,703 280,720Q280,737 268.5,748.5Q257,760 240,760ZM240,600Q223,600 211.5,588.5Q200,577 200,560Q200,543 211.5,531.5Q223,520 240,520Q257,520 268.5,531.5Q280,543 280,560Q280,577 268.5,588.5Q257,600 240,600ZM240,440Q223,440 211.5,428.5Q200,417 200,400Q200,383 211.5,371.5Q223,360 240,360Q257,360 268.5,371.5Q280,383 280,400Q280,417 268.5,428.5Q257,440 240,440ZM240,280Q223,280 211.5,268.5Q200,257 200,240Q200,223 211.5,211.5Q223,200 240,200Q257,200 268.5,211.5Q280,223 280,240Q280,257 268.5,268.5Q257,280 240,280ZM400,620Q375,620 357.5,602.5Q340,585 340,560Q340,535 357.5,517.5Q375,500 400,500Q425,500 442.5,517.5Q460,535 460,560Q460,585 442.5,602.5Q425,620 400,620ZM400,460Q375,460 357.5,442.5Q340,425 340,400Q340,375 357.5,357.5Q375,340 400,340Q425,340 442.5,357.5Q460,375 460,400Q460,425 442.5,442.5Q425,460 400,460ZM400,760Q383,760 371.5,748.5Q360,737 360,720Q360,703 371.5,691.5Q383,680 400,680Q417,680 428.5,691.5Q440,703 440,720Q440,737 428.5,748.5Q417,760 400,760ZM400,280Q383,280 371.5,268.5Q360,257 360,240Q360,223 371.5,211.5Q383,200 400,200Q417,200 428.5,211.5Q440,223 440,240Q440,257 428.5,268.5Q417,280 400,280ZM400,860Q392,860 386,854Q380,848 380,840Q380,832 386,826Q392,820 400,820Q408,820 414,826Q420,832 420,840Q420,848 414,854Q408,860 400,860ZM400,140Q392,140 386,134Q380,128 380,120Q380,112 386,106Q392,100 400,100Q408,100 414,106Q420,112 420,120Q420,128 414,134Q408,140 400,140ZM560,620Q535,620 517.5,602.5Q500,585 500,560Q500,535 517.5,517.5Q535,500 560,500Q585,500 602.5,517.5Q620,535 620,560Q620,585 602.5,602.5Q585,620 560,620ZM560,460Q535,460 517.5,442.5Q500,425 500,400Q500,375 517.5,357.5Q535,340 560,340Q585,340 602.5,357.5Q620,375 620,400Q620,425 602.5,442.5Q585,460 560,460ZM560,760Q543,760 531.5,748.5Q520,737 520,720Q520,703 531.5,691.5Q543,680 560,680Q577,680 588.5,691.5Q600,703 600,720Q600,737 588.5,748.5Q577,760 560,760ZM560,280Q543,280 531.5,268.5Q520,257 520,240Q520,223 531.5,211.5Q543,200 560,200Q577,200 588.5,211.5Q600,223 600,240Q600,257 588.5,268.5Q577,280 560,280ZM560,860Q552,860 546,854Q540,848 540,840Q540,832 546,826Q552,820 560,820Q568,820 574,826Q580,832 580,840Q580,848 574,854Q568,860 560,860ZM560,140Q552,140 546,134Q540,128 540,120Q540,112 546,106Q552,100 560,100Q568,100 574,106Q580,112 580,120Q580,128 574,134Q568,140 560,140ZM720,760Q703,760 691.5,748.5Q680,737 680,720Q680,703 691.5,691.5Q703,680 720,680Q737,680 748.5,691.5Q760,703 760,720Q760,737 748.5,748.5Q737,760 720,760ZM720,600Q703,600 691.5,588.5Q680,577 680,560Q680,543 691.5,531.5Q703,520 720,520Q737,520 748.5,531.5Q760,543 760,560Q760,577 748.5,588.5Q737,600 720,600ZM720,440Q703,440 691.5,428.5Q680,417 680,400Q680,383 691.5,371.5Q703,360 720,360Q737,360 748.5,371.5Q760,383 760,400Q760,417 748.5,428.5Q737,440 720,440ZM720,280Q703,280 691.5,268.5Q680,257 680,240Q680,223 691.5,211.5Q703,200 720,200Q737,200 748.5,211.5Q760,223 760,240Q760,257 748.5,268.5Q737,280 720,280ZM840,580Q832,580 826,574Q820,568 820,560Q820,552 826,546Q832,540 840,540Q848,540 854,546Q860,552 860,560Q860,568 854,574Q848,580 840,580ZM840,420Q832,420 826,414Q820,408 820,400Q820,392 826,386Q832,380 840,380Q848,380 854,386Q860,392 860,400Q860,408 854,414Q848,420 840,420Z"/>
|
android:pathData="M120,580Q112,580 106,574Q100,568 100,560Q100,552 106,546Q112,540 120,540Q128,540 134,546Q140,552 140,560Q140,568 134,574Q128,580 120,580ZM120,420Q112,420 106,414Q100,408 100,400Q100,392 106,386Q112,380 120,380Q128,380 134,386Q140,392 140,400Q140,408 134,414Q128,420 120,420ZM240,760Q223,760 211.5,748.5Q200,737 200,720Q200,703 211.5,691.5Q223,680 240,680Q257,680 268.5,691.5Q280,703 280,720Q280,737 268.5,748.5Q257,760 240,760ZM240,600Q223,600 211.5,588.5Q200,577 200,560Q200,543 211.5,531.5Q223,520 240,520Q257,520 268.5,531.5Q280,543 280,560Q280,577 268.5,588.5Q257,600 240,600ZM240,440Q223,440 211.5,428.5Q200,417 200,400Q200,383 211.5,371.5Q223,360 240,360Q257,360 268.5,371.5Q280,383 280,400Q280,417 268.5,428.5Q257,440 240,440ZM240,280Q223,280 211.5,268.5Q200,257 200,240Q200,223 211.5,211.5Q223,200 240,200Q257,200 268.5,211.5Q280,223 280,240Q280,257 268.5,268.5Q257,280 240,280ZM400,620Q375,620 357.5,602.5Q340,585 340,560Q340,535 357.5,517.5Q375,500 400,500Q425,500 442.5,517.5Q460,535 460,560Q460,585 442.5,602.5Q425,620 400,620ZM400,460Q375,460 357.5,442.5Q340,425 340,400Q340,375 357.5,357.5Q375,340 400,340Q425,340 442.5,357.5Q460,375 460,400Q460,425 442.5,442.5Q425,460 400,460ZM400,760Q383,760 371.5,748.5Q360,737 360,720Q360,703 371.5,691.5Q383,680 400,680Q417,680 428.5,691.5Q440,703 440,720Q440,737 428.5,748.5Q417,760 400,760ZM400,280Q383,280 371.5,268.5Q360,257 360,240Q360,223 371.5,211.5Q383,200 400,200Q417,200 428.5,211.5Q440,223 440,240Q440,257 428.5,268.5Q417,280 400,280ZM400,860Q392,860 386,854Q380,848 380,840Q380,832 386,826Q392,820 400,820Q408,820 414,826Q420,832 420,840Q420,848 414,854Q408,860 400,860ZM400,140Q392,140 386,134Q380,128 380,120Q380,112 386,106Q392,100 400,100Q408,100 414,106Q420,112 420,120Q420,128 414,134Q408,140 400,140ZM560,620Q535,620 517.5,602.5Q500,585 500,560Q500,535 517.5,517.5Q535,500 560,500Q585,500 602.5,517.5Q620,535 620,560Q620,585 602.5,602.5Q585,620 560,620ZM560,460Q535,460 517.5,442.5Q500,425 500,400Q500,375 517.5,357.5Q535,340 560,340Q585,340 602.5,357.5Q620,375 620,400Q620,425 602.5,442.5Q585,460 560,460ZM560,760Q543,760 531.5,748.5Q520,737 520,720Q520,703 531.5,691.5Q543,680 560,680Q577,680 588.5,691.5Q600,703 600,720Q600,737 588.5,748.5Q577,760 560,760ZM560,280Q543,280 531.5,268.5Q520,257 520,240Q520,223 531.5,211.5Q543,200 560,200Q577,200 588.5,211.5Q600,223 600,240Q600,257 588.5,268.5Q577,280 560,280ZM560,860Q552,860 546,854Q540,848 540,840Q540,832 546,826Q552,820 560,820Q568,820 574,826Q580,832 580,840Q580,848 574,854Q568,860 560,860ZM560,140Q552,140 546,134Q540,128 540,120Q540,112 546,106Q552,100 560,100Q568,100 574,106Q580,112 580,120Q580,128 574,134Q568,140 560,140ZM720,760Q703,760 691.5,748.5Q680,737 680,720Q680,703 691.5,691.5Q703,680 720,680Q737,680 748.5,691.5Q760,703 760,720Q760,737 748.5,748.5Q737,760 720,760ZM720,600Q703,600 691.5,588.5Q680,577 680,560Q680,543 691.5,531.5Q703,520 720,520Q737,520 748.5,531.5Q760,543 760,560Q760,577 748.5,588.5Q737,600 720,600ZM720,440Q703,440 691.5,428.5Q680,417 680,400Q680,383 691.5,371.5Q703,360 720,360Q737,360 748.5,371.5Q760,383 760,400Q760,417 748.5,428.5Q737,440 720,440ZM720,280Q703,280 691.5,268.5Q680,257 680,240Q680,223 691.5,211.5Q703,200 720,200Q737,200 748.5,211.5Q760,223 760,240Q760,257 748.5,268.5Q737,280 720,280ZM840,580Q832,580 826,574Q820,568 820,560Q820,552 826,546Q832,540 840,540Q848,540 854,546Q860,552 860,560Q860,568 854,574Q848,580 840,580ZM840,420Q832,420 826,414Q820,408 820,400Q820,392 826,386Q832,380 840,380Q848,380 854,386Q860,392 860,400Q860,408 854,414Q848,420 840,420Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
android:shape="rectangle">
|
android:shape="rectangle">
|
||||||
<solid android:color="?attr/colorSurface" />
|
<solid android:color="?attr/colorSurface" />
|
||||||
<corners
|
<corners
|
||||||
android:topLeftRadius="16dp"
|
|
||||||
android:topRightRadius="16dp"
|
|
||||||
android:bottomLeftRadius="0dp"
|
android:bottomLeftRadius="0dp"
|
||||||
android:bottomRightRadius="0dp"/>
|
android:bottomRightRadius="0dp"
|
||||||
|
android:topLeftRadius="16dp"
|
||||||
|
android:topRightRadius="16dp" />
|
||||||
</shape>
|
</shape>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue