mirror of
https://github.com/rebelonion/Dantotsu.git
synced 2026-01-23 00:31:02 +00:00
Update Functions.kt
This commit is contained in:
committed by
GitHub
parent
9d3d394c7d
commit
6e8cd1413c
@@ -17,9 +17,9 @@ import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.content.res.Resources.getSystem
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.media.MediaScannerConnection
|
||||
import android.net.ConnectivityManager
|
||||
@@ -45,15 +45,15 @@ import android.telephony.TelephonyManager
|
||||
import android.text.InputFilter
|
||||
import android.text.Spanned
|
||||
import android.util.AttributeSet
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.TypedValue
|
||||
import android.view.GestureDetector
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewAnimationUtils
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.view.WindowManager
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.view.animation.Animation
|
||||
@@ -64,16 +64,13 @@ import android.view.animation.TranslateAnimation
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.AutoCompleteTextView
|
||||
import android.widget.DatePicker
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.ContextCompat.getSystemService
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.math.MathUtils.clamp
|
||||
@@ -81,10 +78,11 @@ import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -93,10 +91,10 @@ import ani.dantotsu.BuildConfig.APPLICATION_ID
|
||||
import ani.dantotsu.connections.anilist.Genre
|
||||
import ani.dantotsu.connections.anilist.api.FuzzyDate
|
||||
import ani.dantotsu.connections.bakaupdates.MangaUpdates
|
||||
import ani.dantotsu.connections.crashlytics.CrashlyticsInterface
|
||||
import ani.dantotsu.databinding.ItemCountDownBinding
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.notifications.IncognitoNotificationClickReceiver
|
||||
import ani.dantotsu.others.CustomBottomDialog
|
||||
import ani.dantotsu.others.SpoilerPlugin
|
||||
import ani.dantotsu.parsers.ShowResponse
|
||||
import ani.dantotsu.settings.saving.PrefManager
|
||||
@@ -122,7 +120,6 @@ import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.google.android.material.internal.ViewUtils
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import io.noties.markwon.AbstractMarkwonPlugin
|
||||
import io.noties.markwon.Markwon
|
||||
@@ -138,18 +135,17 @@ import io.noties.markwon.image.glide.GlideImagesPlugin
|
||||
import jp.wasabeef.glide.transformations.BlurTransformation
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import nl.joery.animatedbottombar.AnimatedBottomBar
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.OutputStream
|
||||
import java.lang.reflect.Field
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import java.util.Timer
|
||||
import java.util.TimerTask
|
||||
@@ -162,8 +158,30 @@ import kotlin.math.pow
|
||||
|
||||
var statusBarHeight = 0
|
||||
var navBarHeight = 0
|
||||
val Int.dp: Float get() = (this / getSystem().displayMetrics.density)
|
||||
val Float.px: Int get() = (this * getSystem().displayMetrics.density).toInt()
|
||||
|
||||
val Number.toPx get() = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics
|
||||
).toInt()
|
||||
|
||||
val Number.toDp get() = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_PX, this.toFloat(), Resources.getSystem().displayMetrics
|
||||
)
|
||||
|
||||
val Number.dpToColumns: Int get() {
|
||||
val columns = currContext()?.run {
|
||||
val metrics = DisplayMetrics()
|
||||
with(getSystemService(Context.WINDOW_SERVICE) as WindowManager) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val bounds: Rect = currentWindowMetrics.bounds
|
||||
((bounds.width() / (resources.configuration.densityDpi / 160)) + 0.5)/ this@dpToColumns.toInt()
|
||||
} else @Suppress("deprecation") {
|
||||
defaultDisplay.getRealMetrics(metrics)
|
||||
metrics.widthPixels.toDp / this@dpToColumns.toInt()
|
||||
}
|
||||
}
|
||||
} ?: 1
|
||||
return columns.toInt()
|
||||
}
|
||||
|
||||
lateinit var bottomBar: AnimatedBottomBar
|
||||
var selectedOption = 1
|
||||
@@ -189,10 +207,6 @@ fun currActivity(): Activity? {
|
||||
var loadMedia: Int? = null
|
||||
var loadIsMAL = false
|
||||
|
||||
val Int.toPx get() = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics
|
||||
).toInt()
|
||||
|
||||
fun initActivity(a: Activity) {
|
||||
val window = a.window
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
@@ -276,6 +290,16 @@ fun Activity.setNavigationTheme() {
|
||||
}
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun Context.getColorFromAttr(
|
||||
@AttrRes attrColor: Int,
|
||||
typedValue: TypedValue = TypedValue(),
|
||||
resolveRefs: Boolean = true
|
||||
): Int {
|
||||
theme.resolveAttribute(attrColor, typedValue, resolveRefs)
|
||||
return typedValue.data
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets clipToPadding false and sets the combined height of navigation bars as bottom padding.
|
||||
*
|
||||
@@ -299,29 +323,48 @@ fun ViewGroup.setBaseline(navBar: AnimatedBottomBar, overlayView: View) {
|
||||
setPadding(paddingLeft, paddingTop, paddingRight, navBarHeight + navBar.measuredHeight + overlayView.measuredHeight)
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish the calling activity and launch it again within the same lifecycle scope
|
||||
*/
|
||||
|
||||
fun Activity.reloadActivity() {
|
||||
Refresh.all()
|
||||
finish()
|
||||
startActivity(Intent(this, this::class.java))
|
||||
initActivity(this)
|
||||
}
|
||||
|
||||
fun Context.restartApp(view: View) {
|
||||
/**
|
||||
* Restarts the application from the launch intent and redirects to the calling activity
|
||||
*/
|
||||
fun Activity.restartApp() {
|
||||
val mainIntent = Intent.makeRestartActivityTask(
|
||||
packageManager.getLaunchIntentForPackage(this.packageName)!!.component
|
||||
)
|
||||
val component = ComponentName(this@restartApp.packageName, this@restartApp::class.qualifiedName!!)
|
||||
Snackbar.make(view, R.string.restart_app, Snackbar.LENGTH_INDEFINITE).apply {
|
||||
setAction(R.string.do_it) {
|
||||
this.dismiss()
|
||||
try {
|
||||
startActivity(Intent().setComponent(component))
|
||||
} catch (anything: Exception) {
|
||||
startActivity(mainIntent)
|
||||
try {
|
||||
startActivity(Intent().setComponent(component))
|
||||
} catch (anything: Exception) {
|
||||
startActivity(mainIntent)
|
||||
}
|
||||
finishAndRemoveTask()
|
||||
}
|
||||
|
||||
suspend fun serverDownDialog(activity: FragmentActivity?) = withContext(Dispatchers.Main) {
|
||||
activity?.let {
|
||||
CustomBottomDialog.newInstance().apply {
|
||||
title = it.getString(R.string.anilist_broken_title)
|
||||
addView(TextView(activity).apply {
|
||||
text = it.getString(R.string.anilist_broken)
|
||||
})
|
||||
|
||||
setNegativeButton(it.getString(R.string.cancel)) {
|
||||
dismiss()
|
||||
}
|
||||
Runtime.getRuntime().exit(0)
|
||||
|
||||
setPositiveButton(it.getString(R.string.close)) {
|
||||
it.finishAffinity()
|
||||
}
|
||||
show(it.supportFragmentManager, "dialog")
|
||||
}
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,17 +440,13 @@ fun isOnline(context: Context): Boolean {
|
||||
fun startMainActivity(activity: Activity, bundle: Bundle? = null) {
|
||||
activity.finishAffinity()
|
||||
activity.startActivity(
|
||||
Intent(
|
||||
activity,
|
||||
MainActivity::class.java
|
||||
).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
Intent(activity, MainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
if (bundle != null) putExtras(bundle)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class DatePickerFragment(activity: Activity, var date: FuzzyDate = FuzzyDate().getToday()) :
|
||||
DialogFragment(),
|
||||
DatePickerDialog.OnDateSetListener {
|
||||
@@ -605,11 +644,6 @@ fun MutableList<ShowResponse>.sortByTitle(string: String) {
|
||||
}
|
||||
}
|
||||
|
||||
fun String.findBetween(a: String, b: String): String? {
|
||||
val string = substringAfter(a, "").substringBefore(b, "")
|
||||
return string.ifEmpty { null }
|
||||
}
|
||||
|
||||
fun ImageView.loadImage(url: String?, size: Int = 0) {
|
||||
if (!url.isNullOrEmpty()) {
|
||||
val localFile = File(url)
|
||||
@@ -621,8 +655,13 @@ fun ImageView.loadImage(url: String?, size: Int = 0) {
|
||||
}
|
||||
}
|
||||
|
||||
fun geUrlOrTrolled(url: String?) : String {
|
||||
return if (PrefManager.getVal(PrefName.DisableMitM)) url ?: "" else
|
||||
PrefManager.getVal<String>(PrefName.ImageUrl).ifEmpty { url ?: "" }
|
||||
}
|
||||
|
||||
fun ImageView.loadImage(file: FileUrl?, size: Int = 0) {
|
||||
file?.url = PrefManager.getVal<String>(PrefName.ImageUrl).ifEmpty { file?.url ?: "" }
|
||||
file?.url = geUrlOrTrolled(file?.url)
|
||||
if (file?.url?.isNotEmpty() == true) {
|
||||
tryWith {
|
||||
if (file.url.startsWith("content://")) {
|
||||
@@ -993,34 +1032,56 @@ fun countDown(media: Media, view: ViewGroup) {
|
||||
fun sinceWhen(media: Media, view: ViewGroup) {
|
||||
if (media.status != "RELEASING" && media.status != "HIATUS") return
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
MangaUpdates().search(media.mangaName(), media.startDate)?.let {
|
||||
val latestChapter = MangaUpdates.getLatestChapter(view.context, it)
|
||||
val timeSince = (System.currentTimeMillis() -
|
||||
(it.metadata.series.lastUpdated!!.timestamp * 1000)) / 1000
|
||||
with (MangaUpdates()) {
|
||||
findLatestRelease(media)?.let {
|
||||
var timestamp: Long = it.metadata.series.lastUpdated!!.timestamp
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
val v =
|
||||
ItemCountDownBinding.inflate(LayoutInflater.from(view.context), view, false)
|
||||
view.addView(v.root, 0)
|
||||
v.mediaCountdownText.text =
|
||||
currActivity()?.getString(R.string.chapter_release_timeout, latestChapter)
|
||||
val latestChapter = getSeries(it)?.let { series ->
|
||||
timestamp = series.lastUpdated?.timestamp ?: timestamp
|
||||
currActivity()?.getString(R.string.chapter_number, series.latestChapter)
|
||||
} ?: {
|
||||
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT)
|
||||
timestamp = dateFormat.parse(it.record.releaseDate)?.time ?: timestamp
|
||||
getLatestChapter(view.context, it)
|
||||
}
|
||||
val predicted = predictRelease(media, timestamp * 1000)
|
||||
val timeSince = (System.currentTimeMillis() - (timestamp * 1000)) / 1000
|
||||
|
||||
object : CountUpTimer(86400000) {
|
||||
override fun onTick(second: Int) {
|
||||
val a = second + timeSince
|
||||
v.mediaCountdown.text = currActivity()?.getString(
|
||||
R.string.time_format,
|
||||
a / 86400,
|
||||
a % 86400 / 3600,
|
||||
a % 86400 % 3600 / 60,
|
||||
a % 86400 % 3600 % 60
|
||||
withContext(Dispatchers.Main) {
|
||||
val v = ItemCountDownBinding.inflate(
|
||||
LayoutInflater.from(view.context), view, false
|
||||
)
|
||||
view.addView(v.root, 0)
|
||||
v.mediaCountdownText.text =
|
||||
currActivity()?.getString(R.string.chapter_release_timeout, latestChapter)
|
||||
|
||||
predicted?.let { time ->
|
||||
v.mediaPredication.text = currActivity()?.getString(
|
||||
R.string.chapter_predication,
|
||||
SimpleDateFormat.getDateTimeInstance().format(time)
|
||||
.substringBeforeLast(' ').substringBeforeLast(' ')
|
||||
// SimpleDateFormat parses MMMM to MO5 for May. This is a workaround
|
||||
)
|
||||
v.mediaPredication.isVisible = true
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
// The legend will never die.
|
||||
}
|
||||
}.start()
|
||||
object : CountUpTimer(86400000) {
|
||||
override fun onTick(second: Int) {
|
||||
val a = second + timeSince
|
||||
v.mediaCountdown.text = currActivity()?.getString(
|
||||
R.string.time_format,
|
||||
a / 86400,
|
||||
a % 86400 / 3600,
|
||||
a % 86400 % 3600 / 60,
|
||||
a % 86400 % 3600 % 60
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
// The legend will never die.
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1103,68 +1164,6 @@ class EmptyAdapter(private val count: Int) : RecyclerView.Adapter<RecyclerView.V
|
||||
inner class EmptyViewHolder(view: View) : RecyclerView.ViewHolder(view)
|
||||
}
|
||||
|
||||
fun getAppString(res: Int): String {
|
||||
return currContext()?.getString(res) ?: ""
|
||||
}
|
||||
|
||||
fun toast(string: String?) {
|
||||
if (string != null) {
|
||||
Logger.log(string)
|
||||
MainScope().launch {
|
||||
Toast.makeText(currActivity()?.application ?: return@launch, string, Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toast(res: Int) {
|
||||
toast(getAppString(res))
|
||||
}
|
||||
|
||||
fun snackString(s: String?, activity: Activity? = null, clipboard: String? = null): Snackbar? {
|
||||
try { //I have no idea why this sometimes crashes for some people...
|
||||
if (s != null) {
|
||||
(activity ?: currActivity())?.apply {
|
||||
val snackBar = Snackbar.make(
|
||||
window.decorView.findViewById(android.R.id.content),
|
||||
s,
|
||||
Snackbar.LENGTH_SHORT
|
||||
)
|
||||
runOnUiThread {
|
||||
snackBar.view.apply {
|
||||
updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
gravity = (Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM)
|
||||
width = WRAP_CONTENT
|
||||
}
|
||||
translationY = -(navBarHeight.dp + 32f)
|
||||
translationZ = 32f
|
||||
updatePadding(16f.px, right = 16f.px)
|
||||
setOnClickListener {
|
||||
snackBar.dismiss()
|
||||
}
|
||||
setOnLongClickListener {
|
||||
copyToClipboard(clipboard ?: s, false)
|
||||
toast(getString(R.string.copied_to_clipboard))
|
||||
true
|
||||
}
|
||||
}
|
||||
snackBar.show()
|
||||
}
|
||||
return snackBar
|
||||
}
|
||||
Logger.log(s)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Logger.log(e)
|
||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun snackString(r: Int, activity: Activity? = null, clipboard: String? = null): Snackbar? {
|
||||
return snackString(getAppString(r), activity, clipboard)
|
||||
}
|
||||
|
||||
open class NoPaddingArrayAdapter<T>(context: Context, layoutId: Int, items: List<T>) :
|
||||
ArrayAdapter<T>(context, layoutId, items) {
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
@@ -1329,12 +1328,12 @@ fun openSettings(context: Context, channelId: String?): Boolean {
|
||||
}
|
||||
|
||||
suspend fun View.pop() {
|
||||
currActivity()?.runOnUiThread {
|
||||
withContext(Dispatchers.Main) {
|
||||
ObjectAnimator.ofFloat(this@pop, "scaleX", 1f, 1.25f).setDuration(120).start()
|
||||
ObjectAnimator.ofFloat(this@pop, "scaleY", 1f, 1.25f).setDuration(120).start()
|
||||
}
|
||||
delay(120)
|
||||
currActivity()?.runOnUiThread {
|
||||
withContext(Dispatchers.Main) {
|
||||
ObjectAnimator.ofFloat(this@pop, "scaleX", 1.25f, 1f).setDuration(100).start()
|
||||
ObjectAnimator.ofFloat(this@pop, "scaleY", 1.25f, 1f).setDuration(100).start()
|
||||
}
|
||||
@@ -1348,7 +1347,7 @@ fun blurImage(imageView: ImageView, banner: String?) {
|
||||
if (PrefManager.getVal(PrefName.BlurBanners)) {
|
||||
val context = imageView.context
|
||||
if (!(context as Activity).isDestroyed) {
|
||||
val url = PrefManager.getVal<String>(PrefName.ImageUrl).ifEmpty { banner }
|
||||
val url = geUrlOrTrolled(banner)
|
||||
Glide.with(context as Context)
|
||||
.load(
|
||||
if (banner.startsWith("http")) GlideUrl(url) else if (banner.startsWith("content://")) Uri.parse(
|
||||
@@ -1356,7 +1355,11 @@ fun blurImage(imageView: ImageView, banner: String?) {
|
||||
) else File(url)
|
||||
)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE).override(400)
|
||||
.apply(RequestOptions.bitmapTransform(BlurTransformation(radius, sampling)))
|
||||
.apply(if (PrefManager.getVal<String>(PrefName.ImageUrl).isEmpty()) {
|
||||
RequestOptions.noTransformation()
|
||||
} else {
|
||||
RequestOptions.bitmapTransform(BlurTransformation(radius, sampling))
|
||||
})
|
||||
.into(imageView)
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user