Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
22dccaa24b
40 changed files with 561 additions and 165 deletions
|
@ -11,7 +11,7 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "ani.dantotsu"
|
applicationId "ani.dantotsu"
|
||||||
minSdk 23
|
minSdk 21
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
versionCode((System.currentTimeMillis() / 60000).toInteger())
|
versionCode((System.currentTimeMillis() / 60000).toInteger())
|
||||||
versionName "2.2.0"
|
versionName "2.2.0"
|
||||||
|
|
|
@ -261,6 +261,17 @@
|
||||||
<data android:host="myanimelist.net" />
|
<data android:host="myanimelist.net" />
|
||||||
<data android:pathPrefix="/anime" />
|
<data android:pathPrefix="/anime" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter android:label="@string/view_profile_in_dantotsu">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data android:scheme="http" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="anilist.co" />
|
||||||
|
<data android:pathPrefix="/user" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
@ -276,6 +287,15 @@
|
||||||
|
|
||||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:pathPattern=".*\\.ani" />
|
||||||
|
<data android:pathPattern=".*\\.sani" />
|
||||||
|
<data android:scheme="file" />
|
||||||
|
<data android:scheme="content" />
|
||||||
|
<data android:mimeType="*/*" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="eu.kanade.tachiyomi.extension.manga.util.MangaExtensionInstallActivity"
|
android:name="eu.kanade.tachiyomi.extension.manga.util.MangaExtensionInstallActivity"
|
||||||
|
|
|
@ -13,7 +13,7 @@ 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.notifications.CommentNotificationWorker
|
import ani.dantotsu.notifications.comment.CommentNotificationWorker
|
||||||
import ani.dantotsu.notifications.anilist.AnilistNotificationWorker
|
import ani.dantotsu.notifications.anilist.AnilistNotificationWorker
|
||||||
import ani.dantotsu.others.DisabledReports
|
import ani.dantotsu.others.DisabledReports
|
||||||
import ani.dantotsu.parsers.AnimeSources
|
import ani.dantotsu.parsers.AnimeSources
|
||||||
|
@ -134,7 +134,8 @@ class App : MultiDexApplication() {
|
||||||
// CommentNotificationWorker
|
// CommentNotificationWorker
|
||||||
val commentInterval = CommentNotificationWorker.checkIntervals[PrefManager.getVal(PrefName.CommentNotificationInterval)]
|
val commentInterval = CommentNotificationWorker.checkIntervals[PrefManager.getVal(PrefName.CommentNotificationInterval)]
|
||||||
if (commentInterval.toInt() != 0) {
|
if (commentInterval.toInt() != 0) {
|
||||||
val recurringWork = PeriodicWorkRequest.Builder(CommentNotificationWorker::class.java,
|
val recurringWork = PeriodicWorkRequest.Builder(
|
||||||
|
CommentNotificationWorker::class.java,
|
||||||
commentInterval, java.util.concurrent.TimeUnit.MINUTES)
|
commentInterval, java.util.concurrent.TimeUnit.MINUTES)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
.build()
|
.build()
|
||||||
|
@ -146,7 +147,8 @@ class App : MultiDexApplication() {
|
||||||
} else {
|
} else {
|
||||||
androidx.work.WorkManager.getInstance(this).cancelUniqueWork(CommentNotificationWorker.WORK_NAME)
|
androidx.work.WorkManager.getInstance(this).cancelUniqueWork(CommentNotificationWorker.WORK_NAME)
|
||||||
//run once
|
//run once
|
||||||
androidx.work.WorkManager.getInstance(this).enqueue(OneTimeWorkRequest.Companion.from(CommentNotificationWorker::class.java))
|
androidx.work.WorkManager.getInstance(this).enqueue(OneTimeWorkRequest.Companion.from(
|
||||||
|
CommentNotificationWorker::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnilistNotificationWorker
|
// AnilistNotificationWorker
|
||||||
|
|
|
@ -244,21 +244,35 @@ fun isOnline(context: Context): Boolean {
|
||||||
val connectivityManager =
|
val connectivityManager =
|
||||||
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
return tryWith {
|
return tryWith {
|
||||||
val cap = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
return@tryWith if (cap != null) {
|
val cap = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
|
||||||
when {
|
return@tryWith if (cap != null) {
|
||||||
cap.hasTransport(TRANSPORT_BLUETOOTH) ||
|
when {
|
||||||
cap.hasTransport(TRANSPORT_CELLULAR) ||
|
cap.hasTransport(TRANSPORT_BLUETOOTH) ||
|
||||||
cap.hasTransport(TRANSPORT_ETHERNET) ||
|
cap.hasTransport(TRANSPORT_CELLULAR) ||
|
||||||
cap.hasTransport(TRANSPORT_LOWPAN) ||
|
cap.hasTransport(TRANSPORT_ETHERNET) ||
|
||||||
cap.hasTransport(TRANSPORT_USB) ||
|
cap.hasTransport(TRANSPORT_LOWPAN) ||
|
||||||
cap.hasTransport(TRANSPORT_VPN) ||
|
cap.hasTransport(TRANSPORT_USB) ||
|
||||||
cap.hasTransport(TRANSPORT_WIFI) ||
|
cap.hasTransport(TRANSPORT_VPN) ||
|
||||||
cap.hasTransport(TRANSPORT_WIFI_AWARE) -> true
|
cap.hasTransport(TRANSPORT_WIFI) ||
|
||||||
|
cap.hasTransport(TRANSPORT_WIFI_AWARE) -> true
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
} else false
|
} else false
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
return@tryWith connectivityManager.activeNetworkInfo?.run {
|
||||||
|
type == ConnectivityManager.TYPE_BLUETOOTH ||
|
||||||
|
type == ConnectivityManager.TYPE_ETHERNET ||
|
||||||
|
type == ConnectivityManager.TYPE_MOBILE ||
|
||||||
|
type == ConnectivityManager.TYPE_MOBILE_DUN ||
|
||||||
|
type == ConnectivityManager.TYPE_MOBILE_HIPRI ||
|
||||||
|
type == ConnectivityManager.TYPE_WIFI ||
|
||||||
|
type == ConnectivityManager.TYPE_WIMAX ||
|
||||||
|
type == ConnectivityManager.TYPE_VPN
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
} ?: false
|
} ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ani.dantotsu
|
||||||
|
|
||||||
import android.animation.ObjectAnimator
|
import android.animation.ObjectAnimator
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.AlertDialog
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
|
@ -14,6 +15,7 @@ import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.animation.AnticipateInterpolator
|
import android.view.animation.AnticipateInterpolator
|
||||||
|
@ -28,6 +30,7 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.doOnAttach
|
import androidx.core.view.doOnAttach
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.core.view.updateMargins
|
import androidx.core.view.updateMargins
|
||||||
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
|
@ -47,17 +50,21 @@ import ani.dantotsu.home.MangaFragment
|
||||||
import ani.dantotsu.home.NoInternet
|
import ani.dantotsu.home.NoInternet
|
||||||
import ani.dantotsu.media.MediaDetailsActivity
|
import ani.dantotsu.media.MediaDetailsActivity
|
||||||
import ani.dantotsu.others.CustomBottomDialog
|
import ani.dantotsu.others.CustomBottomDialog
|
||||||
|
import ani.dantotsu.profile.ProfileActivity
|
||||||
import ani.dantotsu.profile.activity.FeedActivity
|
import ani.dantotsu.profile.activity.FeedActivity
|
||||||
import ani.dantotsu.profile.activity.NotificationActivity
|
import ani.dantotsu.profile.activity.NotificationActivity
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefManager.asLiveBool
|
import ani.dantotsu.settings.saving.PrefManager.asLiveBool
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.settings.saving.SharedPreferenceBooleanLiveData
|
import ani.dantotsu.settings.saving.SharedPreferenceBooleanLiveData
|
||||||
|
import ani.dantotsu.settings.saving.internal.PreferenceKeystore
|
||||||
|
import ani.dantotsu.settings.saving.internal.PreferencePackager
|
||||||
import ani.dantotsu.subcriptions.Subscription.Companion.startSubscription
|
import ani.dantotsu.subcriptions.Subscription.Companion.startSubscription
|
||||||
import ani.dantotsu.themes.ThemeManager
|
import ani.dantotsu.themes.ThemeManager
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||||
|
@ -91,6 +98,60 @@ class MainActivity : AppCompatActivity() {
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
val action = intent.action
|
||||||
|
val type = intent.type
|
||||||
|
if (Intent.ACTION_VIEW == action && type != null) {
|
||||||
|
val uri: Uri? = intent.data
|
||||||
|
try {
|
||||||
|
if (uri == null) {
|
||||||
|
throw Exception("Uri is null")
|
||||||
|
}
|
||||||
|
val jsonString =
|
||||||
|
contentResolver.openInputStream(uri)?.readBytes()
|
||||||
|
?: throw Exception("Error reading file")
|
||||||
|
val name =
|
||||||
|
DocumentFile.fromSingleUri(this, uri)?.name ?: "settings"
|
||||||
|
//.sani is encrypted, .ani is not
|
||||||
|
if (name.endsWith(".sani")) {
|
||||||
|
passwordAlertDialog { password ->
|
||||||
|
if (password != null) {
|
||||||
|
val salt = jsonString.copyOfRange(0, 16)
|
||||||
|
val encrypted = jsonString.copyOfRange(16, jsonString.size)
|
||||||
|
val decryptedJson = try {
|
||||||
|
PreferenceKeystore.decryptWithPassword(
|
||||||
|
password,
|
||||||
|
encrypted,
|
||||||
|
salt
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
toast("Incorrect password")
|
||||||
|
return@passwordAlertDialog
|
||||||
|
}
|
||||||
|
if (PreferencePackager.unpack(decryptedJson)) {
|
||||||
|
val intent = Intent(this, this.javaClass)
|
||||||
|
this.finish()
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toast("Password cannot be empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (name.endsWith(".ani")) {
|
||||||
|
val decryptedJson = jsonString.toString(Charsets.UTF_8)
|
||||||
|
if (PreferencePackager.unpack(decryptedJson)) {
|
||||||
|
val intent = Intent(this, this.javaClass)
|
||||||
|
this.finish()
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toast("Invalid file type")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
toast("Error importing settings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val _bottomBar = findViewById<AnimatedBottomBar>(R.id.navbar)
|
val _bottomBar = findViewById<AnimatedBottomBar>(R.id.navbar)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
|
||||||
|
@ -214,7 +275,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
binding.root.doOnAttach {
|
binding.root.doOnAttach {
|
||||||
initActivity(this)
|
initActivity(this)
|
||||||
window.navigationBarColor = getColor(android.R.color.transparent)
|
window.navigationBarColor = ContextCompat.getColor(this, android.R.color.transparent)
|
||||||
selectedOption = if (fragment != null) {
|
selectedOption = if (fragment != null) {
|
||||||
when (fragment) {
|
when (fragment) {
|
||||||
AnimeFragment::class.java.name -> 0
|
AnimeFragment::class.java.name -> 0
|
||||||
|
@ -329,6 +390,22 @@ class MainActivity : AppCompatActivity() {
|
||||||
snackString(this@MainActivity.getString(R.string.anilist_not_found))
|
snackString(this@MainActivity.getString(R.string.anilist_not_found))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val username = intent.extras?.getString("username")
|
||||||
|
if (username != null) {
|
||||||
|
val nameInt = username.toIntOrNull()
|
||||||
|
if (nameInt != null) {
|
||||||
|
startActivity(
|
||||||
|
Intent(this@MainActivity, ProfileActivity::class.java)
|
||||||
|
.putExtra("userId", nameInt)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
startActivity(
|
||||||
|
Intent(this@MainActivity, ProfileActivity::class.java)
|
||||||
|
.putExtra("username", username)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delay(500)
|
delay(500)
|
||||||
startSubscription()
|
startSubscription()
|
||||||
}
|
}
|
||||||
|
@ -381,7 +458,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onRestart() {
|
override fun onRestart() {
|
||||||
super.onRestart()
|
super.onRestart()
|
||||||
window.navigationBarColor = getColor(android.R.color.transparent)
|
window.navigationBarColor = ContextCompat.getColor(this, android.R.color.transparent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val Int.toPx get() = TypedValue.applyDimension(
|
private val Int.toPx get() = TypedValue.applyDimension(
|
||||||
|
@ -398,6 +475,44 @@ class MainActivity : AppCompatActivity() {
|
||||||
params.updateMargins(bottom = 32.toPx)
|
params.updateMargins(bottom = 32.toPx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun passwordAlertDialog(callback: (CharArray?) -> Unit) {
|
||||||
|
val password = CharArray(16).apply { fill('0') }
|
||||||
|
|
||||||
|
// Inflate the dialog layout
|
||||||
|
val dialogView =
|
||||||
|
LayoutInflater.from(this).inflate(R.layout.dialog_user_agent, null)
|
||||||
|
dialogView.findViewById<TextInputEditText>(R.id.userAgentTextBox)?.hint = "Password"
|
||||||
|
val subtitleTextView = dialogView.findViewById<TextView>(R.id.subtitle)
|
||||||
|
subtitleTextView?.visibility = View.VISIBLE
|
||||||
|
subtitleTextView?.text = "Enter your password to decrypt the file"
|
||||||
|
|
||||||
|
val dialog = AlertDialog.Builder(this, R.style.MyPopup)
|
||||||
|
.setTitle("Enter Password")
|
||||||
|
.setView(dialogView)
|
||||||
|
.setPositiveButton("OK", null)
|
||||||
|
.setNegativeButton("Cancel") { dialog, _ ->
|
||||||
|
password.fill('0')
|
||||||
|
dialog.dismiss()
|
||||||
|
callback(null)
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
|
||||||
|
dialog.window?.setDimAmount(0.8f)
|
||||||
|
dialog.show()
|
||||||
|
|
||||||
|
// Override the positive button here
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||||
|
val editText = dialog.findViewById<TextInputEditText>(R.id.userAgentTextBox)
|
||||||
|
if (editText?.text?.isNotBlank() == true) {
|
||||||
|
editText.text?.toString()?.trim()?.toCharArray(password)
|
||||||
|
dialog.dismiss()
|
||||||
|
callback(password)
|
||||||
|
} else {
|
||||||
|
toast("Password cannot be empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//ViewPager
|
//ViewPager
|
||||||
private class ViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
private class ViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
||||||
FragmentStateAdapter(fragmentManager, lifecycle) {
|
FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||||
|
|
|
@ -54,6 +54,8 @@ class AnilistQueries {
|
||||||
Anilist.chapterRead = user.statistics?.manga?.chaptersRead
|
Anilist.chapterRead = user.statistics?.manga?.chaptersRead
|
||||||
Anilist.adult = user.options?.displayAdultContent ?: false
|
Anilist.adult = user.options?.displayAdultContent ?: false
|
||||||
Anilist.unreadNotificationCount = user.unreadNotificationCount ?: 0
|
Anilist.unreadNotificationCount = user.unreadNotificationCount ?: 0
|
||||||
|
val unread = PrefManager.getVal<Int>(PrefName.UnreadCommentNotifications)
|
||||||
|
Anilist.unreadNotificationCount += unread
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,6 +1347,18 @@ Page(page:$page,perPage:50) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getUserProfile(username: String): Query.UserProfileResponse? {
|
||||||
|
val id = getUserId(username) ?: return null
|
||||||
|
return getUserProfile(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getUserId(username: String): Int? {
|
||||||
|
return executeQuery<Query.User>(
|
||||||
|
"""{User(name:"$username"){id}}""",
|
||||||
|
force = true
|
||||||
|
)?.data?.user?.id
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun getUserStatistics(id: Int, sort: String = "ID"): Query.StatisticsResponse? {
|
suspend fun getUserStatistics(id: Int, sort: String = "ID"): Query.StatisticsResponse? {
|
||||||
return executeQuery<Query.StatisticsResponse>(
|
return executeQuery<Query.StatisticsResponse>(
|
||||||
"""{User(id:$id){id name mediaListOptions{scoreFormat}statistics{anime{...UserStatistics}manga{...UserStatistics}}}}fragment UserStatistics on UserStatistics{count meanScore standardDeviation minutesWatched episodesWatched chaptersRead volumesRead formats(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds format}statuses(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds status}scores(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds score}lengths(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds length}releaseYears(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds releaseYear}startYears(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds startYear}genres(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds genre}tags(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds tag{id name}}countries(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds country}voiceActors(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds voiceActor{id name{first middle last full native alternative userPreferred}}characterIds}staff(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds staff{id name{first middle last full native alternative userPreferred}}}studios(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds studio{id name isAnimationStudio}}}""",
|
"""{User(id:$id){id name mediaListOptions{scoreFormat}statistics{anime{...UserStatistics}manga{...UserStatistics}}}}fragment UserStatistics on UserStatistics{count meanScore standardDeviation minutesWatched episodesWatched chaptersRead volumesRead formats(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds format}statuses(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds status}scores(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds score}lengths(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds length}releaseYears(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds releaseYear}startYears(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds startYear}genres(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds genre}tags(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds tag{id name}}countries(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds country}voiceActors(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds voiceActor{id name{first middle last full native alternative userPreferred}}characterIds}staff(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds staff{id name{first middle last full native alternative userPreferred}}}studios(sort:$sort){count meanScore minutesWatched chaptersRead mediaIds studio{id name isAnimationStudio}}}""",
|
||||||
|
@ -1392,7 +1406,10 @@ Page(page:$page,perPage:50) {
|
||||||
"""{User(id:$id){unreadNotificationCount}Page(page:$page,perPage:$ITEMS_PER_PAGE){notifications(resetNotificationCount:$reset){__typename...on AiringNotification{id,type,animeId,episode,contexts,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}},}...on FollowingNotification{id,userId,type,context,createdAt,user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMessageNotification{id,userId,type,activityId,context,createdAt,message{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMentionNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplySubscribedNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentMentionNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentReplyNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentSubscribedNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentLikeNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadLikeNotification{id,userId,type,threadId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on RelatedMediaAdditionNotification{id,type,context,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDataChangeNotification{id,type,mediaId,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaMergeNotification{id,type,mediaId,deletedMediaTitles,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDeletionNotification{id,type,deletedMediaTitle,context,reason,createdAt,}}}}""",
|
"""{User(id:$id){unreadNotificationCount}Page(page:$page,perPage:$ITEMS_PER_PAGE){notifications(resetNotificationCount:$reset){__typename...on AiringNotification{id,type,animeId,episode,contexts,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}},}...on FollowingNotification{id,userId,type,context,createdAt,user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMessageNotification{id,userId,type,activityId,context,createdAt,message{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMentionNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplySubscribedNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentMentionNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentReplyNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentSubscribedNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentLikeNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadLikeNotification{id,userId,type,threadId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on RelatedMediaAdditionNotification{id,type,context,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDataChangeNotification{id,type,mediaId,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaMergeNotification{id,type,mediaId,deletedMediaTitles,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDeletionNotification{id,type,deletedMediaTitle,context,reason,createdAt,}}}}""",
|
||||||
force = true
|
force = true
|
||||||
)
|
)
|
||||||
if (res != null) {
|
if (res != null && resetNotification) {
|
||||||
|
val commentNotifications = PrefManager.getVal(PrefName.UnreadCommentNotifications, 0)
|
||||||
|
res.data.user.unreadNotificationCount += commentNotifications
|
||||||
|
PrefManager.setVal(PrefName.UnreadCommentNotifications, 0)
|
||||||
Anilist.unreadNotificationCount = 0
|
Anilist.unreadNotificationCount = 0
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
|
@ -1404,7 +1421,8 @@ Page(page:$page,perPage:50) {
|
||||||
else if (global) "isFollowing:false,hasRepliesOrTypeText:true,"
|
else if (global) "isFollowing:false,hasRepliesOrTypeText:true,"
|
||||||
else "isFollowing:true,type_not:MESSAGE,"
|
else "isFollowing:true,type_not:MESSAGE,"
|
||||||
return executeQuery<FeedResponse>(
|
return executeQuery<FeedResponse>(
|
||||||
"""{Page(page:$page,perPage:$ITEMS_PER_PAGE){activities(${filter}sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id title{english romaji native userPreferred}bannerImage coverImage{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id recipientId messengerId type replyCount likeCount message(asHtml:true)isLocked isSubscribed isLiked isPrivate siteUrl createdAt recipient{id name bannerImage avatar{medium large}}messenger{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}}}}"""
|
"""{Page(page:$page,perPage:$ITEMS_PER_PAGE){activities(${filter}sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id title{english romaji native userPreferred}bannerImage coverImage{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id recipientId messengerId type replyCount likeCount message(asHtml:true)isLocked isSubscribed isLiked isPrivate siteUrl createdAt recipient{id name bannerImage avatar{medium large}}messenger{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}}}}""",
|
||||||
|
force = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,20 +11,27 @@ import ani.dantotsu.themes.ThemeManager
|
||||||
class UrlMedia : Activity() {
|
class UrlMedia : Activity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
ThemeManager(this).applyTheme()
|
ThemeManager(this).applyTheme()
|
||||||
var id: Int? = intent?.extras?.getInt("media", 0) ?: 0
|
val data: Uri? = intent?.data
|
||||||
var isMAL = false
|
val type = data?.pathSegments?.getOrNull(0)
|
||||||
var continueMedia = true
|
if (type == "anime" || type == "manga") {
|
||||||
if (id == 0) {
|
var id: Int? = intent?.extras?.getInt("media", 0) ?: 0
|
||||||
continueMedia = false
|
var isMAL = false
|
||||||
val data: Uri? = intent?.data
|
var continueMedia = true
|
||||||
isMAL = data?.host != "anilist.co"
|
if (id == 0) {
|
||||||
id = data?.pathSegments?.getOrNull(1)?.toIntOrNull()
|
continueMedia = false
|
||||||
} else loadMedia = id
|
isMAL = data.host != "anilist.co"
|
||||||
startMainActivity(
|
id = data.pathSegments?.getOrNull(1)?.toIntOrNull()
|
||||||
this,
|
} else loadMedia = id
|
||||||
bundleOf("mediaId" to id, "mal" to isMAL, "continue" to continueMedia)
|
startMainActivity(
|
||||||
)
|
this,
|
||||||
|
bundleOf("mediaId" to id, "mal" to isMAL, "continue" to continueMedia)
|
||||||
|
)
|
||||||
|
} else if (type == "user") {
|
||||||
|
val username = data.pathSegments?.getOrNull(1)
|
||||||
|
startMainActivity(this, bundleOf("username" to username))
|
||||||
|
} else {
|
||||||
|
startMainActivity(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,7 +20,9 @@ enum class NotificationType(val value: String) {
|
||||||
RELATED_MEDIA_ADDITION("RELATED_MEDIA_ADDITION"),
|
RELATED_MEDIA_ADDITION("RELATED_MEDIA_ADDITION"),
|
||||||
MEDIA_DATA_CHANGE("MEDIA_DATA_CHANGE"),
|
MEDIA_DATA_CHANGE("MEDIA_DATA_CHANGE"),
|
||||||
MEDIA_MERGE("MEDIA_MERGE"),
|
MEDIA_MERGE("MEDIA_MERGE"),
|
||||||
MEDIA_DELETION("MEDIA_DELETION")
|
MEDIA_DELETION("MEDIA_DELETION"),
|
||||||
|
//custom
|
||||||
|
COMMENT_REPLY("COMMENT_REPLY"),
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -40,7 +42,7 @@ data class NotificationResponse(
|
||||||
@Serializable
|
@Serializable
|
||||||
data class NotificationUser(
|
data class NotificationUser(
|
||||||
@SerialName("unreadNotificationCount")
|
@SerialName("unreadNotificationCount")
|
||||||
val unreadNotificationCount: Int,
|
var unreadNotificationCount: Int,
|
||||||
) : java.io.Serializable
|
) : java.io.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -56,41 +58,41 @@ data class Notification(
|
||||||
@SerialName("id")
|
@SerialName("id")
|
||||||
val id: Int,
|
val id: Int,
|
||||||
@SerialName("userId")
|
@SerialName("userId")
|
||||||
val userId: Int?,
|
val userId: Int? = null,
|
||||||
@SerialName("CommentId")
|
@SerialName("CommentId")
|
||||||
val commentId: Int?,
|
val commentId: Int?,
|
||||||
@SerialName("type")
|
@SerialName("type")
|
||||||
val notificationType: String,
|
val notificationType: String,
|
||||||
@SerialName("activityId")
|
@SerialName("activityId")
|
||||||
val activityId: Int?,
|
val activityId: Int? = null,
|
||||||
@SerialName("animeId")
|
@SerialName("animeId")
|
||||||
val mediaId: Int?,
|
val mediaId: Int? = null,
|
||||||
@SerialName("episode")
|
@SerialName("episode")
|
||||||
val episode: Int?,
|
val episode: Int? = null,
|
||||||
@SerialName("contexts")
|
@SerialName("contexts")
|
||||||
val contexts: List<String>?,
|
val contexts: List<String>? = null,
|
||||||
@SerialName("context")
|
@SerialName("context")
|
||||||
val context: String?,
|
val context: String? = null,
|
||||||
@SerialName("reason")
|
@SerialName("reason")
|
||||||
val reason: String?,
|
val reason: String? = null,
|
||||||
@SerialName("deletedMediaTitle")
|
@SerialName("deletedMediaTitle")
|
||||||
val deletedMediaTitle: String?,
|
val deletedMediaTitle: String? = null,
|
||||||
@SerialName("deletedMediaTitles")
|
@SerialName("deletedMediaTitles")
|
||||||
val deletedMediaTitles: List<String>?,
|
val deletedMediaTitles: List<String>? = null,
|
||||||
@SerialName("createdAt")
|
@SerialName("createdAt")
|
||||||
val createdAt: Int,
|
val createdAt: Int,
|
||||||
@SerialName("media")
|
@SerialName("media")
|
||||||
val media: ani.dantotsu.connections.anilist.api.Media?,
|
val media: ani.dantotsu.connections.anilist.api.Media? = null,
|
||||||
@SerialName("user")
|
@SerialName("user")
|
||||||
val user: ani.dantotsu.connections.anilist.api.User?,
|
val user: ani.dantotsu.connections.anilist.api.User? = null,
|
||||||
@SerialName("message")
|
@SerialName("message")
|
||||||
val message: MessageActivity?,
|
val message: MessageActivity? = null,
|
||||||
@SerialName("activity")
|
@SerialName("activity")
|
||||||
val activity: ActivityUnion?,
|
val activity: ActivityUnion? = null,
|
||||||
@SerialName("Thread")
|
@SerialName("Thread")
|
||||||
val thread: Thread?,
|
val thread: Thread? = null,
|
||||||
@SerialName("comment")
|
@SerialName("comment")
|
||||||
val comment: ThreadComment?,
|
val comment: ThreadComment? = null,
|
||||||
) : java.io.Serializable
|
) : java.io.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|
|
@ -31,12 +31,15 @@ object CommentsAPI {
|
||||||
var isMod: Boolean = false
|
var isMod: Boolean = false
|
||||||
var totalVotes: Int = 0
|
var totalVotes: Int = 0
|
||||||
|
|
||||||
suspend fun getCommentsForId(id: Int, page: Int = 1, tag: Int?): CommentResponse? {
|
suspend fun getCommentsForId(id: Int, page: Int = 1, tag: Int?, sort: String?): CommentResponse? {
|
||||||
var url = "$address/comments/$id/$page"
|
var url = "$address/comments/$id/$page"
|
||||||
val request = requestBuilder()
|
val request = requestBuilder()
|
||||||
tag?.let {
|
tag?.let {
|
||||||
url += "?tag=$it"
|
url += "?tag=$it"
|
||||||
}
|
}
|
||||||
|
sort?.let {
|
||||||
|
url += if (tag != null) "&sort=$it" else "?sort=$it"
|
||||||
|
}
|
||||||
val json = try {
|
val json = try {
|
||||||
request.get(url)
|
request.get(url)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
|
|
|
@ -54,6 +54,7 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import tachiyomi.core.util.lang.launchIO
|
||||||
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
|
import java.io.File
|
||||||
|
@ -355,15 +356,13 @@ class AnimeDownloaderService : Service() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
|
||||||
private fun saveMediaInfo(task: AnimeDownloadTask) {
|
private fun saveMediaInfo(task: AnimeDownloadTask) {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
launchIO {
|
||||||
val directory = File(
|
val directory = File(
|
||||||
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||||
"${DownloadsManager.animeLocation}/${task.title}"
|
"${DownloadsManager.animeLocation}/${task.title}"
|
||||||
)
|
)
|
||||||
val episodeDirectory = File(directory, task.episode)
|
val episodeDirectory = File(directory, task.episode)
|
||||||
if (!directory.exists()) directory.mkdirs()
|
|
||||||
if (!episodeDirectory.exists()) episodeDirectory.mkdirs()
|
if (!episodeDirectory.exists()) episodeDirectory.mkdirs()
|
||||||
|
|
||||||
val file = File(directory, "media.json")
|
val file = File(directory, "media.json")
|
||||||
|
|
|
@ -37,6 +37,7 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SChapterImpl
|
import eu.kanade.tachiyomi.source.model.SChapterImpl
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
@ -47,6 +48,7 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import tachiyomi.core.util.lang.launchIO
|
||||||
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
|
import java.io.File
|
||||||
|
@ -287,8 +289,9 @@ class MangaDownloaderService : Service() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
private fun saveMediaInfo(task: DownloadTask) {
|
private fun saveMediaInfo(task: DownloadTask) {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
launchIO {
|
||||||
val directory = File(
|
val directory = File(
|
||||||
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||||
"Dantotsu/Manga/${task.title}"
|
"Dantotsu/Manga/${task.title}"
|
||||||
|
|
|
@ -31,6 +31,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SChapterImpl
|
import eu.kanade.tachiyomi.source.model.SChapterImpl
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
@ -42,6 +43,7 @@ import kotlinx.coroutines.withContext
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.sink
|
import okio.sink
|
||||||
|
import tachiyomi.core.util.lang.launchIO
|
||||||
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
|
import java.io.File
|
||||||
|
@ -347,8 +349,9 @@ class NovelDownloaderService : Service() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
private fun saveMediaInfo(task: DownloadTask) {
|
private fun saveMediaInfo(task: DownloadTask) {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
launchIO {
|
||||||
val directory = File(
|
val directory = File(
|
||||||
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
|
||||||
"Dantotsu/Novel/${task.title}"
|
"Dantotsu/Novel/${task.title}"
|
||||||
|
|
|
@ -17,6 +17,7 @@ import ani.dantotsu.openLinkInBrowser
|
||||||
import ani.dantotsu.settings.saving.internal.PreferenceKeystore
|
import ani.dantotsu.settings.saving.internal.PreferenceKeystore
|
||||||
import ani.dantotsu.settings.saving.internal.PreferencePackager
|
import ani.dantotsu.settings.saving.internal.PreferencePackager
|
||||||
import ani.dantotsu.toast
|
import ani.dantotsu.toast
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
|
||||||
class LoginFragment : Fragment() {
|
class LoginFragment : Fragment() {
|
||||||
|
@ -50,7 +51,7 @@ class LoginFragment : Fragment() {
|
||||||
DocumentFile.fromSingleUri(requireActivity(), uri)?.name ?: "settings"
|
DocumentFile.fromSingleUri(requireActivity(), uri)?.name ?: "settings"
|
||||||
//.sani is encrypted, .ani is not
|
//.sani is encrypted, .ani is not
|
||||||
if (name.endsWith(".sani")) {
|
if (name.endsWith(".sani")) {
|
||||||
passwordAlertDialog() { password ->
|
passwordAlertDialog { password ->
|
||||||
if (password != null) {
|
if (password != null) {
|
||||||
val salt = jsonString.copyOfRange(0, 16)
|
val salt = jsonString.copyOfRange(0, 16)
|
||||||
val encrypted = jsonString.copyOfRange(16, jsonString.size)
|
val encrypted = jsonString.copyOfRange(16, jsonString.size)
|
||||||
|
@ -78,7 +79,7 @@ class LoginFragment : Fragment() {
|
||||||
toast("Invalid file type")
|
toast("Invalid file type")
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
Logger.log(e)
|
||||||
toast("Error importing settings")
|
toast("Error importing settings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import java.util.regex.Pattern
|
||||||
class AnimeNameAdapter {
|
class AnimeNameAdapter {
|
||||||
companion object {
|
companion object {
|
||||||
const val episodeRegex =
|
const val episodeRegex =
|
||||||
"(episode|ep|e)[\\s:.\\-]*([\\d]+\\.?[\\d]*)[\\s:.\\-]*\\(?\\s*(sub|subbed|dub|dubbed)*\\s*\\)?\\s*"
|
"(episode|episodio|ep|e)[\\s:.\\-]*([\\d]+\\.?[\\d]*)[\\s:.\\-]*\\(?\\s*(sub|subbed|dub|dubbed)*\\s*\\)?\\s*"
|
||||||
const val failedEpisodeNumberRegex =
|
const val failedEpisodeNumberRegex =
|
||||||
"(?<!part\\s)\\b(\\d+)\\b"
|
"(?<!part\\s)\\b(\\d+)\\b"
|
||||||
const val seasonRegex = "(season|s)[\\s:.\\-]*(\\d+)[\\s:.\\-]*"
|
const val seasonRegex = "(season|s)[\\s:.\\-]*(\\d+)[\\s:.\\-]*"
|
||||||
|
|
|
@ -130,12 +130,12 @@ class CommentItem(val comment: Comment,
|
||||||
viewBinding.modBadge.visibility = if (comment.isMod == true) View.VISIBLE else View.GONE
|
viewBinding.modBadge.visibility = if (comment.isMod == true) View.VISIBLE else View.GONE
|
||||||
viewBinding.adminBadge.visibility = if (comment.isAdmin == true) View.VISIBLE else View.GONE
|
viewBinding.adminBadge.visibility = if (comment.isAdmin == true) View.VISIBLE else View.GONE
|
||||||
viewBinding.commentDelete.setOnClickListener {
|
viewBinding.commentDelete.setOnClickListener {
|
||||||
dialogBuilder("Delete CommentNotificationWorker", "Are you sure you want to delete this comment?") {
|
dialogBuilder("Delete Comment", "Are you sure you want to delete this comment?") {
|
||||||
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
||||||
scope.launch {
|
scope.launch {
|
||||||
val success = CommentsAPI.deleteComment(comment.commentId)
|
val success = CommentsAPI.deleteComment(comment.commentId)
|
||||||
if (success) {
|
if (success) {
|
||||||
snackString("CommentNotificationWorker Deleted")
|
snackString("Comment Deleted")
|
||||||
parentSection.remove(this@CommentItem)
|
parentSection.remove(this@CommentItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,12 +153,12 @@ class CommentItem(val comment: Comment,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
viewBinding.commentReport.setOnClickListener {
|
viewBinding.commentReport.setOnClickListener {
|
||||||
dialogBuilder("Report CommentNotificationWorker", "Only report comments that violate the rules. Are you sure you want to report this comment?") {
|
dialogBuilder("Report Comment", "Only report comments that violate the rules. Are you sure you want to report this comment?") {
|
||||||
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
||||||
scope.launch {
|
scope.launch {
|
||||||
val success = CommentsAPI.reportComment(comment.commentId, comment.username, commentsFragment.mediaName, comment.userId)
|
val success = CommentsAPI.reportComment(comment.commentId, comment.username, commentsFragment.mediaName, comment.userId)
|
||||||
if (success) {
|
if (success) {
|
||||||
snackString("CommentNotificationWorker Reported")
|
snackString("Comment Reported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.core.animation.doOnEnd
|
import androidx.core.animation.doOnEnd
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
@ -33,7 +32,7 @@ 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.snackString
|
||||||
import ani.dantotsu.toast
|
import ani.dantotsu.toast
|
||||||
import com.bumptech.glide.Glide
|
import ani.dantotsu.util.Logger
|
||||||
import com.xwray.groupie.GroupieAdapter
|
import com.xwray.groupie.GroupieAdapter
|
||||||
import com.xwray.groupie.Section
|
import com.xwray.groupie.Section
|
||||||
import io.noties.markwon.editor.MarkwonEditor
|
import io.noties.markwon.editor.MarkwonEditor
|
||||||
|
@ -139,9 +138,15 @@ class CommentsFragment : Fragment() {
|
||||||
R.id.comment_sort_lowest_rated -> "lowest_rated"
|
R.id.comment_sort_lowest_rated -> "lowest_rated"
|
||||||
else -> return@setOnMenuItemClickListener false
|
else -> return@setOnMenuItemClickListener false
|
||||||
}
|
}
|
||||||
|
|
||||||
PrefManager.setVal(PrefName.CommentSortOrder, sortOrder)
|
PrefManager.setVal(PrefName.CommentSortOrder, sortOrder)
|
||||||
sortComments(sortOrder)
|
if (totalPages > pagesLoaded) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
loadAndDisplayComments()
|
||||||
|
activity.binding.commentReplyToContainer.visibility = View.GONE
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sortComments(sortOrder)
|
||||||
|
}
|
||||||
binding.commentsList.scrollToPosition(0)
|
binding.commentsList.scrollToPosition(0)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -197,7 +202,8 @@ class CommentsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
snackString("No more comments")
|
//snackString("No more comments") fix spam?
|
||||||
|
Logger.log("No more comments")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,7 +225,12 @@ class CommentsFragment : Fragment() {
|
||||||
|
|
||||||
private suspend fun fetchComments(): CommentResponse? {
|
private suspend fun fetchComments(): CommentResponse? {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
CommentsAPI.getCommentsForId(mediaId, pagesLoaded + 1, filterTag)
|
CommentsAPI.getCommentsForId(
|
||||||
|
mediaId,
|
||||||
|
pagesLoaded + 1,
|
||||||
|
filterTag,
|
||||||
|
PrefManager.getVal(PrefName.CommentSortOrder, "newest")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +264,7 @@ class CommentsFragment : Fragment() {
|
||||||
300,
|
300,
|
||||||
activity.binding.commentInput.text.length
|
activity.binding.commentInput.text.length
|
||||||
)
|
)
|
||||||
snackString("CommentNotificationWorker cannot be longer than 300 characters")
|
snackString("Comment cannot be longer than 300 characters")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -377,7 +388,11 @@ class CommentsFragment : Fragment() {
|
||||||
section.clear()
|
section.clear()
|
||||||
|
|
||||||
val comments = withContext(Dispatchers.IO) {
|
val comments = withContext(Dispatchers.IO) {
|
||||||
CommentsAPI.getCommentsForId(mediaId, tag = filterTag)
|
CommentsAPI.getCommentsForId(
|
||||||
|
mediaId,
|
||||||
|
tag = filterTag,
|
||||||
|
sort = PrefManager.getVal(PrefName.CommentSortOrder, "newest")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val sortedComments = sortComments(comments?.comments)
|
val sortedComments = sortComments(comments?.comments)
|
||||||
|
@ -460,6 +475,7 @@ class CommentsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionState.REPLY -> {
|
InteractionState.REPLY -> {
|
||||||
|
activity.binding.commentReplyToContainer.visibility = View.GONE
|
||||||
activity.binding.commentInput.setText("")
|
activity.binding.commentInput.setText("")
|
||||||
val imm = activity.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
val imm = activity.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
imm.hideSoftInputFromWindow(activity.binding.commentInput.windowToken, 0)
|
imm.hideSoftInputFromWindow(activity.binding.commentInput.windowToken, 0)
|
||||||
|
@ -587,7 +603,7 @@ class CommentsFragment : Fragment() {
|
||||||
private fun processComment() {
|
private fun processComment() {
|
||||||
val commentText = activity.binding.commentInput.text.toString()
|
val commentText = activity.binding.commentInput.text.toString()
|
||||||
if (commentText.isEmpty()) {
|
if (commentText.isEmpty()) {
|
||||||
snackString("CommentNotificationWorker cannot be empty")
|
snackString("Comment cannot be empty")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,6 +620,7 @@ class CommentsFragment : Fragment() {
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
resetOldState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,7 +640,7 @@ class CommentsFragment : Fragment() {
|
||||||
groups.forEach { item ->
|
groups.forEach { item ->
|
||||||
if (item is CommentItem && item.comment.commentId == commentWithInteraction?.comment?.commentId) {
|
if (item is CommentItem && item.comment.commentId == commentWithInteraction?.comment?.commentId) {
|
||||||
updateCommentItem(item, commentText)
|
updateCommentItem(item, commentText)
|
||||||
snackString("CommentNotificationWorker edited")
|
snackString("Comment edited")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ 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
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.databinding.ItemNovelResponseBinding
|
import ani.dantotsu.databinding.ItemNovelResponseBinding
|
||||||
|
@ -59,11 +60,11 @@ class NovelResponseAdapter(
|
||||||
}
|
}
|
||||||
if (binding.itemEpisodeFiller.text.contains("Downloading")) {
|
if (binding.itemEpisodeFiller.text.contains("Downloading")) {
|
||||||
binding.itemEpisodeFiller.setTextColor(
|
binding.itemEpisodeFiller.setTextColor(
|
||||||
fragment.requireContext().getColor(android.R.color.holo_blue_light)
|
ContextCompat.getColor(fragment.requireContext(), android.R.color.holo_blue_light)
|
||||||
)
|
)
|
||||||
} else if (binding.itemEpisodeFiller.text.contains("Downloaded")) {
|
} else if (binding.itemEpisodeFiller.text.contains("Downloaded")) {
|
||||||
binding.itemEpisodeFiller.setTextColor(
|
binding.itemEpisodeFiller.setTextColor(
|
||||||
fragment.requireContext().getColor(android.R.color.holo_green_light)
|
ContextCompat.getColor(fragment.requireContext(), android.R.color.holo_green_light)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
binding.itemEpisodeFiller.setTextColor(color)
|
binding.itemEpisodeFiller.setTextColor(color)
|
||||||
|
|
|
@ -16,6 +16,7 @@ import ani.dantotsu.connections.anilist.Anilist
|
||||||
import ani.dantotsu.profile.activity.ActivityItemBuilder
|
import ani.dantotsu.profile.activity.ActivityItemBuilder
|
||||||
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.util.Logger
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -78,12 +79,13 @@ class AnilistNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
putExtra("FRAGMENT_TO_LOAD", "NOTIFICATIONS")
|
putExtra("FRAGMENT_TO_LOAD", "NOTIFICATIONS")
|
||||||
if (notificationId != null) {
|
if (notificationId != null) {
|
||||||
|
Logger.log("notificationId: $notificationId")
|
||||||
putExtra("activityId", notificationId)
|
putExtra("activityId", notificationId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
0,
|
notificationId ?: 0,
|
||||||
intent,
|
intent,
|
||||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package ani.dantotsu.notifications
|
package ani.dantotsu.notifications.comment
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
|
@ -20,6 +20,7 @@ import ani.dantotsu.R
|
||||||
import ani.dantotsu.connections.comments.CommentsAPI
|
import ani.dantotsu.connections.comments.CommentsAPI
|
||||||
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.util.Logger
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -58,8 +59,12 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
if (newRecentGlobal != null) {
|
if (newRecentGlobal != null) {
|
||||||
PrefManager.setVal(PrefName.RecentGlobalNotification, newRecentGlobal)
|
PrefManager.setVal(PrefName.RecentGlobalNotification, newRecentGlobal)
|
||||||
}
|
}
|
||||||
|
if (notifications.isNullOrEmpty()) return@launch
|
||||||
|
PrefManager.setVal(PrefName.UnreadCommentNotifications,
|
||||||
|
PrefManager.getVal<Int>(PrefName.UnreadCommentNotifications) + (notifications?.size ?: 0)
|
||||||
|
)
|
||||||
|
|
||||||
notifications?.forEach {
|
notifications.forEach {
|
||||||
val type: NotificationType = when (it.type) {
|
val type: NotificationType = when (it.type) {
|
||||||
1 -> NotificationType.COMMENT_REPLY
|
1 -> NotificationType.COMMENT_REPLY
|
||||||
2 -> NotificationType.COMMENT_WARNING
|
2 -> NotificationType.COMMENT_WARNING
|
||||||
|
@ -71,6 +76,15 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
NotificationType.COMMENT_WARNING -> {
|
NotificationType.COMMENT_WARNING -> {
|
||||||
val title = "You received a warning"
|
val title = "You received a warning"
|
||||||
val message = it.content ?: "Be more thoughtful with your comments"
|
val message = it.content ?: "Be more thoughtful with your comments"
|
||||||
|
|
||||||
|
val commentStore = CommentStore(
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
it.mediaId,
|
||||||
|
it.commentId
|
||||||
|
)
|
||||||
|
addNotificationToStore(commentStore)
|
||||||
|
|
||||||
createNotification(
|
createNotification(
|
||||||
NotificationType.COMMENT_WARNING,
|
NotificationType.COMMENT_WARNING,
|
||||||
message,
|
message,
|
||||||
|
@ -83,9 +97,18 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationType.COMMENT_REPLY -> {
|
NotificationType.COMMENT_REPLY -> {
|
||||||
val title = "New CommentNotificationWorker Reply"
|
val title = "New Comment Reply"
|
||||||
val mediaName = names[it.mediaId]?.title ?: "Unknown"
|
val mediaName = names[it.mediaId]?.title ?: "Unknown"
|
||||||
val message = "${it.username} replied to your comment in $mediaName"
|
val message = "${it.username} replied to your comment in $mediaName"
|
||||||
|
|
||||||
|
val commentStore = CommentStore(
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
it.mediaId,
|
||||||
|
it.commentId
|
||||||
|
)
|
||||||
|
addNotificationToStore(commentStore)
|
||||||
|
|
||||||
createNotification(
|
createNotification(
|
||||||
NotificationType.COMMENT_REPLY,
|
NotificationType.COMMENT_REPLY,
|
||||||
message,
|
message,
|
||||||
|
@ -100,6 +123,15 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
NotificationType.APP_GLOBAL -> {
|
NotificationType.APP_GLOBAL -> {
|
||||||
val title = "Update from Dantotsu"
|
val title = "Update from Dantotsu"
|
||||||
val message = it.content ?: "New feature available"
|
val message = it.content ?: "New feature available"
|
||||||
|
|
||||||
|
val commentStore = CommentStore(
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
addNotificationToStore(commentStore)
|
||||||
|
|
||||||
createNotification(
|
createNotification(
|
||||||
NotificationType.APP_GLOBAL,
|
NotificationType.APP_GLOBAL,
|
||||||
message,
|
message,
|
||||||
|
@ -143,6 +175,22 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addNotificationToStore(notification: CommentStore) {
|
||||||
|
val notificationStore = PrefManager.getNullableVal<List<CommentStore>>(
|
||||||
|
PrefName.CommentNotificationStore,
|
||||||
|
null
|
||||||
|
) ?: listOf()
|
||||||
|
val newStore = notificationStore.toMutableList()
|
||||||
|
if (newStore.size > 10) {
|
||||||
|
newStore.remove(newStore.minByOrNull { it.time })
|
||||||
|
}
|
||||||
|
if (newStore.any { it.content == notification.content }) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
newStore.add(notification)
|
||||||
|
PrefManager.setVal(PrefName.CommentNotificationStore, newStore)
|
||||||
|
}
|
||||||
|
|
||||||
private fun createNotification(
|
private fun createNotification(
|
||||||
notificationType: NotificationType,
|
notificationType: NotificationType,
|
||||||
message: String,
|
message: String,
|
||||||
|
@ -152,6 +200,10 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
color: String,
|
color: String,
|
||||||
imageUrl: String
|
imageUrl: String
|
||||||
): android.app.Notification? {
|
): android.app.Notification? {
|
||||||
|
Logger.log(
|
||||||
|
"Creating notification of type $notificationType" +
|
||||||
|
", message: $message, title: $title, mediaId: $mediaId, commentId: $commentId"
|
||||||
|
)
|
||||||
val notification = when (notificationType) {
|
val notification = when (notificationType) {
|
||||||
NotificationType.COMMENT_WARNING -> {
|
NotificationType.COMMENT_WARNING -> {
|
||||||
val intent = Intent(applicationContext, MainActivity::class.java).apply {
|
val intent = Intent(applicationContext, MainActivity::class.java).apply {
|
||||||
|
@ -162,7 +214,7 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
}
|
}
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
0,
|
commentId,
|
||||||
intent,
|
intent,
|
||||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
)
|
)
|
||||||
|
@ -185,7 +237,7 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
}
|
}
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
0,
|
commentId,
|
||||||
intent,
|
intent,
|
||||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
)
|
)
|
||||||
|
@ -214,7 +266,7 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
}
|
}
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
0,
|
System.currentTimeMillis().toInt(),
|
||||||
intent,
|
intent,
|
||||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
)
|
)
|
||||||
|
@ -266,6 +318,6 @@ class CommentNotificationWorker(appContext: Context, workerParams: WorkerParamet
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val checkIntervals = arrayOf(0L, 720, 1440)
|
val checkIntervals = arrayOf(0L, 720, 1440)
|
||||||
const val WORK_NAME = "ani.dantotsu.notifications.CommentNotificationWorker"
|
const val WORK_NAME = "ani.dantotsu.notifications.comment.CommentNotificationWorker"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package ani.dantotsu.notifications.comment
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
||||||
|
@Suppress("INAPPROPRIATE_CONST_NAME")
|
||||||
|
@Serializable
|
||||||
|
data class CommentStore(
|
||||||
|
val title: String,
|
||||||
|
val content: String,
|
||||||
|
val mediaId: Int? = null,
|
||||||
|
val commentId: Int? = null,
|
||||||
|
val time: Long = System.currentTimeMillis(),
|
||||||
|
) : java.io.Serializable {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
@Suppress("INAPPROPRIATE_CONST_NAME")
|
||||||
|
private const val serialVersionUID = 1L
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package ani.dantotsu.notifications
|
package ani.dantotsu.notifications.comment
|
||||||
|
|
||||||
import ani.dantotsu.client
|
import ani.dantotsu.client
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
|
@ -82,6 +82,9 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDub(): Boolean {
|
private fun getDub(): Boolean {
|
||||||
|
if (sourceLanguage >= extension.sources.size) {
|
||||||
|
sourceLanguage = extension.sources.size - 1
|
||||||
|
}
|
||||||
val configurableSource = extension.sources[sourceLanguage] as? ConfigurableAnimeSource
|
val configurableSource = extension.sources[sourceLanguage] as? ConfigurableAnimeSource
|
||||||
?: return false
|
?: return false
|
||||||
currContext()?.let { context ->
|
currContext()?.let { context ->
|
||||||
|
@ -103,6 +106,9 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setDub(setDub: Boolean) {
|
fun setDub(setDub: Boolean) {
|
||||||
|
if (sourceLanguage >= extension.sources.size) {
|
||||||
|
sourceLanguage = extension.sources.size - 1
|
||||||
|
}
|
||||||
val configurableSource = extension.sources[sourceLanguage] as? ConfigurableAnimeSource
|
val configurableSource = extension.sources[sourceLanguage] as? ConfigurableAnimeSource
|
||||||
?: return
|
?: return
|
||||||
val type = when (setDub) {
|
val type = when (setDub) {
|
||||||
|
|
|
@ -7,7 +7,10 @@ import ani.dantotsu.databinding.ItemChartBinding
|
||||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartView
|
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartView
|
||||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAMoveOverEventMessageModel
|
import com.github.aachartmodel.aainfographics.aachartcreator.AAMoveOverEventMessageModel
|
||||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAOptions
|
import com.github.aachartmodel.aainfographics.aachartcreator.AAOptions
|
||||||
|
import com.xwray.groupie.OnItemClickListener
|
||||||
|
import com.xwray.groupie.OnItemLongClickListener
|
||||||
import com.xwray.groupie.viewbinding.BindableItem
|
import com.xwray.groupie.viewbinding.BindableItem
|
||||||
|
import com.xwray.groupie.viewbinding.GroupieViewHolder
|
||||||
|
|
||||||
class ChartItem(
|
class ChartItem(
|
||||||
private val title: String,
|
private val title: String,
|
||||||
|
@ -31,6 +34,7 @@ class ChartItem(
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
binding.chartView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
|
||||||
binding.chartView.callBack = callback
|
binding.chartView.callBack = callback
|
||||||
binding.chartView.reload()
|
binding.chartView.reload()
|
||||||
binding.chartView.aa_drawChartWithChartOptions(aaOptions)
|
binding.chartView.aa_drawChartWithChartOptions(aaOptions)
|
||||||
|
@ -49,4 +53,32 @@ class ChartItem(
|
||||||
override fun initializeViewBinding(view: View): ItemChartBinding {
|
override fun initializeViewBinding(view: View): ItemChartBinding {
|
||||||
return ItemChartBinding.bind(view)
|
return ItemChartBinding.bind(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun bind(viewHolder: GroupieViewHolder<ItemChartBinding>, position: Int) {
|
||||||
|
viewHolder.setIsRecyclable(false)
|
||||||
|
super.bind(viewHolder, position)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bind(
|
||||||
|
viewHolder: GroupieViewHolder<ItemChartBinding>,
|
||||||
|
position: Int,
|
||||||
|
payloads: MutableList<Any>
|
||||||
|
) {
|
||||||
|
viewHolder.setIsRecyclable(false)
|
||||||
|
super.bind(viewHolder, position, payloads)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bind(
|
||||||
|
viewHolder: GroupieViewHolder<ItemChartBinding>,
|
||||||
|
position: Int,
|
||||||
|
payloads: MutableList<Any>,
|
||||||
|
onItemClickListener: OnItemClickListener?,
|
||||||
|
onItemLongClickListener: OnItemLongClickListener?
|
||||||
|
) {
|
||||||
|
viewHolder.setIsRecyclable(false)
|
||||||
|
super.bind(viewHolder, position, payloads, onItemClickListener, onItemLongClickListener)
|
||||||
|
}
|
||||||
|
override fun getViewType(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -68,8 +68,11 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
|
||||||
binding.profileViewPager.isUserInputEnabled = false
|
binding.profileViewPager.isUserInputEnabled = false
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val userid = intent.getIntExtra("userId", 0)
|
val userid = intent.getIntExtra("userId", -1)
|
||||||
val respond = Anilist.query.getUserProfile(userid)
|
val username = intent.getStringExtra("username") ?: ""
|
||||||
|
val respond =
|
||||||
|
if (userid != -1) Anilist.query.getUserProfile(userid) else
|
||||||
|
Anilist.query.getUserProfile(username)
|
||||||
val user = respond?.data?.user
|
val user = respond?.data?.user
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
toast("User not found")
|
toast("User not found")
|
||||||
|
|
|
@ -65,7 +65,7 @@ class ProfileFragment : Fragment() {
|
||||||
binding.profileUserBio.setInitialScale(1)
|
binding.profileUserBio.setInitialScale(1)
|
||||||
val styledHtml = getFullAniHTML(
|
val styledHtml = getFullAniHTML(
|
||||||
user.about ?: "",
|
user.about ?: "",
|
||||||
activity.getColor(R.color.bg_opp)
|
ContextCompat.getColor(activity, R.color.bg_opp)
|
||||||
)
|
)
|
||||||
binding.profileUserBio.loadDataWithBaseURL(
|
binding.profileUserBio.loadDataWithBaseURL(
|
||||||
null,
|
null,
|
||||||
|
@ -76,7 +76,7 @@ class ProfileFragment : Fragment() {
|
||||||
)
|
)
|
||||||
binding.profileUserBio.setBackgroundColor(
|
binding.profileUserBio.setBackgroundColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
activity,
|
||||||
android.R.color.transparent
|
android.R.color.transparent
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -86,7 +86,7 @@ class ProfileFragment : Fragment() {
|
||||||
super.onPageFinished(view, url)
|
super.onPageFinished(view, url)
|
||||||
binding.profileUserBio.setBackgroundColor(
|
binding.profileUserBio.setBackgroundColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
activity,
|
||||||
android.R.color.transparent
|
android.R.color.transparent
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -146,7 +146,7 @@ class ProfileFragment : Fragment() {
|
||||||
}
|
}
|
||||||
binding.profileFavStaffRecycler.adapter = AuthorAdapter(favStaff)
|
binding.profileFavStaffRecycler.adapter = AuthorAdapter(favStaff)
|
||||||
binding.profileFavStaffRecycler.layoutManager = LinearLayoutManager(
|
binding.profileFavStaffRecycler.layoutManager = LinearLayoutManager(
|
||||||
requireContext(),
|
activity,
|
||||||
LinearLayoutManager.HORIZONTAL,
|
LinearLayoutManager.HORIZONTAL,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
@ -155,7 +155,7 @@ class ProfileFragment : Fragment() {
|
||||||
}
|
}
|
||||||
binding.profileFavCharactersRecycler.adapter = CharacterAdapter(favCharacter)
|
binding.profileFavCharactersRecycler.adapter = CharacterAdapter(favCharacter)
|
||||||
binding.profileFavCharactersRecycler.layoutManager = LinearLayoutManager(
|
binding.profileFavCharactersRecycler.layoutManager = LinearLayoutManager(
|
||||||
requireContext(),
|
activity,
|
||||||
LinearLayoutManager.HORIZONTAL,
|
LinearLayoutManager.HORIZONTAL,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
@ -177,9 +177,9 @@ 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, requireActivity(), fav=true)
|
recyclerView.adapter = MediaAdaptor(0, it, activity, fav=true)
|
||||||
recyclerView.layoutManager = LinearLayoutManager(
|
recyclerView.layoutManager = LinearLayoutManager(
|
||||||
requireContext(),
|
activity,
|
||||||
LinearLayoutManager.HORIZONTAL,
|
LinearLayoutManager.HORIZONTAL,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
|
@ -51,9 +51,9 @@ class StatsFragment :
|
||||||
user = arguments?.getSerializable("user") as Query.UserProfile
|
user = arguments?.getSerializable("user") as Query.UserProfile
|
||||||
|
|
||||||
binding.statisticList.adapter = adapter
|
binding.statisticList.adapter = adapter
|
||||||
binding.statisticList.setHasFixedSize(true)
|
binding.statisticList.recycledViewPool.setMaxRecycledViews(0, 0)
|
||||||
binding.statisticList.isNestedScrollingEnabled = true
|
binding.statisticList.isNestedScrollingEnabled = true
|
||||||
binding.statisticList.layoutManager = LinearLayoutManager(requireContext())
|
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 }
|
||||||
|
@ -104,9 +104,15 @@ class StatsFragment :
|
||||||
binding.filterContainer.visibility = View.GONE
|
binding.filterContainer.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
binding.statisticList.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
if (this::binding.isInitialized) {
|
if (this::binding.isInitialized) {
|
||||||
|
binding.statisticList.visibility = View.VISIBLE
|
||||||
binding.root.requestLayout()
|
binding.root.requestLayout()
|
||||||
if (!loadedFirstTime) {
|
if (!loadedFirstTime) {
|
||||||
activity.lifecycleScope.launch {
|
activity.lifecycleScope.launch {
|
||||||
|
|
|
@ -79,6 +79,10 @@ class ActivityItemBuilder {
|
||||||
NotificationType.MEDIA_DELETION -> {
|
NotificationType.MEDIA_DELETION -> {
|
||||||
"${notification.deletedMediaTitle} has been deleted from the site"
|
"${notification.deletedMediaTitle} has been deleted from the site"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationType.COMMENT_REPLY -> {
|
||||||
|
notification.context ?: "You should not see this"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ 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.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.Logger
|
||||||
import com.xwray.groupie.GroupieAdapter
|
import com.xwray.groupie.GroupieAdapter
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -80,7 +81,8 @@ class FeedFragment : Fragment() {
|
||||||
binding.listRecyclerView.setOnTouchListener { _, event ->
|
binding.listRecyclerView.setOnTouchListener { _, event ->
|
||||||
if (event?.action == MotionEvent.ACTION_UP) {
|
if (event?.action == MotionEvent.ACTION_UP) {
|
||||||
if (activityList.size % AnilistQueries.ITEMS_PER_PAGE != 0 && !global) {
|
if (activityList.size % AnilistQueries.ITEMS_PER_PAGE != 0 && !global) {
|
||||||
snackString("No more activities")
|
//snackString("No more activities") fix spam?
|
||||||
|
Logger.log("No more activities")
|
||||||
} else if (!scrollView.canScrollVertically(1) && !binding.feedRefresh.isVisible
|
} else if (!scrollView.canScrollVertically(1) && !binding.feedRefresh.isVisible
|
||||||
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
|
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
|
||||||
(binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
|
(binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
|
||||||
|
|
|
@ -18,6 +18,7 @@ import ani.dantotsu.databinding.ActivityFollowBinding
|
||||||
import ani.dantotsu.initActivity
|
import ani.dantotsu.initActivity
|
||||||
import ani.dantotsu.media.MediaDetailsActivity
|
import ani.dantotsu.media.MediaDetailsActivity
|
||||||
import ani.dantotsu.navBarHeight
|
import ani.dantotsu.navBarHeight
|
||||||
|
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
|
||||||
|
@ -29,6 +30,7 @@ import com.xwray.groupie.GroupieAdapter
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class NotificationActivity : AppCompatActivity() {
|
class NotificationActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: ActivityFollowBinding
|
private lateinit var binding: ActivityFollowBinding
|
||||||
|
@ -73,7 +75,25 @@ class NotificationActivity : AppCompatActivity() {
|
||||||
notifications.filter { it.id == activityId }
|
notifications.filter { it.id == activityId }
|
||||||
} else {
|
} else {
|
||||||
notifications
|
notifications
|
||||||
|
}.toMutableList()
|
||||||
|
val commentStore = PrefManager.getNullableVal<List<CommentStore>>(
|
||||||
|
PrefName.CommentNotificationStore,
|
||||||
|
null
|
||||||
|
) ?: listOf()
|
||||||
|
commentStore.forEach {
|
||||||
|
val notification = Notification(
|
||||||
|
"COMMENT_REPLY",
|
||||||
|
System.currentTimeMillis().toInt(),
|
||||||
|
commentId = it.commentId,
|
||||||
|
notificationType = "COMMENT_REPLY",
|
||||||
|
mediaId = it.mediaId,
|
||||||
|
context = it.title + "\n" + it.content,
|
||||||
|
createdAt = (it.time / 1000L).toInt(),
|
||||||
|
)
|
||||||
|
notificationList = notificationList + notification
|
||||||
}
|
}
|
||||||
|
notificationList = notificationList.sortedByDescending { it.createdAt }
|
||||||
|
|
||||||
adapter.update(notificationList.map { NotificationItem(it, ::onNotificationClick) })
|
adapter.update(notificationList.map { NotificationItem(it, ::onNotificationClick) })
|
||||||
}
|
}
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
@ -81,7 +101,8 @@ class NotificationActivity : AppCompatActivity() {
|
||||||
binding.listRecyclerView.setOnTouchListener { _, event ->
|
binding.listRecyclerView.setOnTouchListener { _, event ->
|
||||||
if (event?.action == MotionEvent.ACTION_UP) {
|
if (event?.action == MotionEvent.ACTION_UP) {
|
||||||
if (adapter.itemCount % AnilistQueries.ITEMS_PER_PAGE != 0) {
|
if (adapter.itemCount % AnilistQueries.ITEMS_PER_PAGE != 0) {
|
||||||
snackString("No more notifications")
|
//snackString("No more notifications") fix spam?
|
||||||
|
Logger.log("No more notifications")
|
||||||
} else if (!binding.listRecyclerView.canScrollVertically(1) && !binding.followRefresh.isVisible
|
} else if (!binding.listRecyclerView.canScrollVertically(1) && !binding.followRefresh.isVisible
|
||||||
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
|
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
|
||||||
(binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
|
(binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
|
||||||
|
@ -105,7 +126,6 @@ class NotificationActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadPage(onFinish: () -> Unit = {}) {
|
private fun loadPage(onFinish: () -> Unit = {}) {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val res = Anilist.query.getNotifications(Anilist.userid ?: 0, page)
|
val res = Anilist.query.getNotifications(Anilist.userid ?: 0, page)
|
||||||
|
@ -120,7 +140,7 @@ class NotificationActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onNotificationClick(id: Int, type: NotificationClickType) {
|
private fun onNotificationClick(id: Int, optional: Int?, type: NotificationClickType) {
|
||||||
when (type) {
|
when (type) {
|
||||||
NotificationClickType.USER -> {
|
NotificationClickType.USER -> {
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
|
@ -143,6 +163,16 @@ class NotificationActivity : AppCompatActivity() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationClickType.COMMENT -> {
|
||||||
|
ContextCompat.startActivity(this, Intent(this, MediaDetailsActivity::class.java)
|
||||||
|
.putExtra("FRAGMENT_TO_LOAD", "COMMENTS")
|
||||||
|
.putExtra("mediaId", id)
|
||||||
|
.putExtra("commentId", optional ?: -1),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
NotificationClickType.UNDEFINED -> {
|
NotificationClickType.UNDEFINED -> {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
@ -151,7 +181,7 @@ class NotificationActivity : AppCompatActivity() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
enum class NotificationClickType {
|
enum class NotificationClickType {
|
||||||
USER, MEDIA, ACTIVITY, UNDEFINED
|
USER, MEDIA, ACTIVITY, COMMENT, UNDEFINED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@ import com.xwray.groupie.viewbinding.BindableItem
|
||||||
|
|
||||||
class NotificationItem(
|
class NotificationItem(
|
||||||
private val notification: Notification,
|
private val notification: Notification,
|
||||||
val clickCallback: (Int, NotificationClickType) -> Unit
|
val clickCallback: (Int, Int?, NotificationClickType) -> Unit
|
||||||
) : BindableItem<ItemNotificationBinding>() {
|
) : BindableItem<ItemNotificationBinding>() {
|
||||||
private lateinit var binding: ItemNotificationBinding
|
private lateinit var binding: ItemNotificationBinding
|
||||||
override fun bind(viewBinding: ItemNotificationBinding, position: Int) {
|
override fun bind(viewBinding: ItemNotificationBinding, position: Int) {
|
||||||
|
@ -31,7 +31,7 @@ class NotificationItem(
|
||||||
return ItemNotificationBinding.bind(view)
|
return ItemNotificationBinding.bind(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun image(user: Boolean = false) {
|
private fun image(user: Boolean = false, commentNotification: Boolean = false) {
|
||||||
|
|
||||||
val cover = if (user) notification.user?.bannerImage
|
val cover = if (user) notification.user?.bannerImage
|
||||||
?: notification.user?.avatar?.medium else notification.media?.bannerImage
|
?: notification.user?.avatar?.medium else notification.media?.bannerImage
|
||||||
|
@ -52,7 +52,13 @@ class NotificationItem(
|
||||||
binding.notificationCover.visibility = View.GONE
|
binding.notificationCover.visibility = View.GONE
|
||||||
binding.notificationCoverUser.visibility = View.VISIBLE
|
binding.notificationCoverUser.visibility = View.VISIBLE
|
||||||
binding.notificationCoverUserContainer.visibility = View.VISIBLE
|
binding.notificationCoverUserContainer.visibility = View.VISIBLE
|
||||||
binding.notificationCoverUser.loadImage(notification.user?.avatar?.large)
|
if (commentNotification) {
|
||||||
|
binding.notificationCoverUser.setImageResource(R.drawable.ic_dantotsu_round)
|
||||||
|
binding.notificationCoverUser.scaleX = 1.4f
|
||||||
|
binding.notificationCoverUser.scaleY = 1.4f
|
||||||
|
} else {
|
||||||
|
binding.notificationCoverUser.loadImage(notification.user?.avatar?.large)
|
||||||
|
}
|
||||||
binding.notificationBannerImage.layoutParams.height = userHeight
|
binding.notificationBannerImage.layoutParams.height = userHeight
|
||||||
} else {
|
} else {
|
||||||
binding.notificationCover.visibility = View.VISIBLE
|
binding.notificationCover.visibility = View.VISIBLE
|
||||||
|
@ -75,12 +81,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.activityId ?: 0, NotificationClickType.ACTIVITY
|
notification.activityId ?: 0, null, NotificationClickType.ACTIVITY
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,12 +96,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.activityId ?: 0, NotificationClickType.ACTIVITY
|
notification.activityId ?: 0, null, NotificationClickType.ACTIVITY
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,12 +111,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.userId ?: 0, NotificationClickType.USER
|
notification.userId ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,12 +126,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.activityId ?: 0, NotificationClickType.ACTIVITY
|
notification.activityId ?: 0, null, NotificationClickType.ACTIVITY
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,12 +141,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,12 +156,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,12 +171,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +186,7 @@ class NotificationItem(
|
||||||
image()
|
image()
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.media?.id ?: 0, NotificationClickType.MEDIA
|
notification.media?.id ?: 0, null, NotificationClickType.MEDIA
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,12 +196,12 @@ class NotificationItem(
|
||||||
binding.notificationCover.loadImage(notification.user?.avatar?.large)
|
binding.notificationCover.loadImage(notification.user?.avatar?.large)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.activityId ?: 0, NotificationClickType.ACTIVITY
|
notification.activityId ?: 0, null, NotificationClickType.ACTIVITY
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,12 +211,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.activityId ?: 0, NotificationClickType.ACTIVITY
|
notification.activityId ?: 0, null, NotificationClickType.ACTIVITY
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,12 +226,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,12 +241,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,12 +256,12 @@ class NotificationItem(
|
||||||
image(true)
|
image(true)
|
||||||
binding.notificationCoverUser.setOnClickListener {
|
binding.notificationCoverUser.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.user?.id ?: 0, NotificationClickType.USER
|
notification.user?.id ?: 0, null, NotificationClickType.USER
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.activityId ?: 0, NotificationClickType.ACTIVITY
|
notification.activityId ?: 0, null, NotificationClickType.ACTIVITY
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,7 +271,7 @@ class NotificationItem(
|
||||||
image()
|
image()
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.media?.id ?: 0, NotificationClickType.MEDIA
|
notification.media?.id ?: 0, null, NotificationClickType.MEDIA
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,7 +281,7 @@ class NotificationItem(
|
||||||
image()
|
image()
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.media?.id ?: 0, NotificationClickType.MEDIA
|
notification.media?.id ?: 0, null, NotificationClickType.MEDIA
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,7 +291,7 @@ class NotificationItem(
|
||||||
image()
|
image()
|
||||||
binding.notificationBannerImage.setOnClickListener {
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
clickCallback(
|
clickCallback(
|
||||||
notification.media?.id ?: 0, NotificationClickType.MEDIA
|
notification.media?.id ?: 0, null, NotificationClickType.MEDIA
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,6 +299,17 @@ class NotificationItem(
|
||||||
NotificationType.MEDIA_DELETION -> {
|
NotificationType.MEDIA_DELETION -> {
|
||||||
binding.notificationCover.visibility = View.GONE
|
binding.notificationCover.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationType.COMMENT_REPLY -> {
|
||||||
|
image(user = true, commentNotification = true)
|
||||||
|
if (notification.commentId != null && notification.mediaId != null) {
|
||||||
|
binding.notificationBannerImage.setOnClickListener {
|
||||||
|
clickCallback(
|
||||||
|
notification.mediaId, notification.commentId, NotificationClickType.COMMENT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ import ani.dantotsu.initActivity
|
||||||
import ani.dantotsu.loadImage
|
import ani.dantotsu.loadImage
|
||||||
import ani.dantotsu.util.Logger
|
import ani.dantotsu.util.Logger
|
||||||
import ani.dantotsu.navBarHeight
|
import ani.dantotsu.navBarHeight
|
||||||
import ani.dantotsu.notifications.CommentNotificationWorker
|
import ani.dantotsu.notifications.comment.CommentNotificationWorker
|
||||||
import ani.dantotsu.notifications.anilist.AnilistNotificationWorker
|
import ani.dantotsu.notifications.anilist.AnilistNotificationWorker
|
||||||
import ani.dantotsu.openLinkInBrowser
|
import ani.dantotsu.openLinkInBrowser
|
||||||
import ani.dantotsu.others.AppUpdater
|
import ani.dantotsu.others.AppUpdater
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ani.dantotsu.settings.saving
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import ani.dantotsu.connections.comments.AuthResponse
|
import ani.dantotsu.connections.comments.AuthResponse
|
||||||
import ani.dantotsu.connections.mal.MAL
|
import ani.dantotsu.connections.mal.MAL
|
||||||
|
import ani.dantotsu.notifications.comment.CommentStore
|
||||||
import ani.dantotsu.settings.saving.internal.Location
|
import ani.dantotsu.settings.saving.internal.Location
|
||||||
import ani.dantotsu.settings.saving.internal.Pref
|
import ani.dantotsu.settings.saving.internal.Pref
|
||||||
|
|
||||||
|
@ -171,6 +172,8 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
||||||
CommentTokenExpiry(Pref(Location.Irrelevant, Long::class, 0L)),
|
CommentTokenExpiry(Pref(Location.Irrelevant, Long::class, 0L)),
|
||||||
LogToFile(Pref(Location.Irrelevant, Boolean::class, false)),
|
LogToFile(Pref(Location.Irrelevant, Boolean::class, false)),
|
||||||
RecentGlobalNotification(Pref(Location.Irrelevant, Int::class, 0)),
|
RecentGlobalNotification(Pref(Location.Irrelevant, Int::class, 0)),
|
||||||
|
CommentNotificationStore(Pref(Location.Irrelevant, List::class, listOf<CommentStore>())),
|
||||||
|
UnreadCommentNotifications(Pref(Location.Irrelevant, Int::class, 0)),
|
||||||
|
|
||||||
//Protected
|
//Protected
|
||||||
DiscordToken(Pref(Location.Protected, String::class, "")),
|
DiscordToken(Pref(Location.Protected, String::class, "")),
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ani.dantotsu.util
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import ani.dantotsu.BuildConfig
|
import ani.dantotsu.BuildConfig
|
||||||
|
@ -31,8 +32,8 @@ object Logger {
|
||||||
}
|
}
|
||||||
file?.writeText("log started\n")
|
file?.writeText("log started\n")
|
||||||
file?.appendText("date/time: ${Date()}\n")
|
file?.appendText("date/time: ${Date()}\n")
|
||||||
file?.appendText("device: ${android.os.Build.MODEL}\n")
|
file?.appendText("device: ${Build.MODEL}\n")
|
||||||
file?.appendText("os version: ${android.os.Build.VERSION.RELEASE}\n")
|
file?.appendText("os version: ${Build.VERSION.RELEASE}\n")
|
||||||
file?.appendText(
|
file?.appendText(
|
||||||
"app version: ${
|
"app version: ${
|
||||||
context.packageManager.getPackageInfo(
|
context.packageManager.getPackageInfo(
|
||||||
|
@ -46,29 +47,35 @@ object Logger {
|
||||||
context.packageManager.getPackageInfo(
|
context.packageManager.getPackageInfo(
|
||||||
context.packageName,
|
context.packageName,
|
||||||
0
|
0
|
||||||
).versionCode
|
).run {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||||
|
longVersionCode
|
||||||
|
else
|
||||||
|
@Suppress("DEPRECATION") versionCode
|
||||||
|
|
||||||
|
}
|
||||||
}\n"
|
}\n"
|
||||||
)
|
)
|
||||||
file?.appendText("sdk version: ${android.os.Build.VERSION.SDK_INT}\n")
|
file?.appendText("sdk version: ${Build.VERSION.SDK_INT}\n")
|
||||||
file?.appendText("manufacturer: ${android.os.Build.MANUFACTURER}\n")
|
file?.appendText("manufacturer: ${Build.MANUFACTURER}\n")
|
||||||
file?.appendText("brand: ${android.os.Build.BRAND}\n")
|
file?.appendText("brand: ${Build.BRAND}\n")
|
||||||
file?.appendText("product: ${android.os.Build.PRODUCT}\n")
|
file?.appendText("product: ${Build.PRODUCT}\n")
|
||||||
file?.appendText("device: ${android.os.Build.DEVICE}\n")
|
file?.appendText("device: ${Build.DEVICE}\n")
|
||||||
file?.appendText("hardware: ${android.os.Build.HARDWARE}\n")
|
file?.appendText("hardware: ${Build.HARDWARE}\n")
|
||||||
file?.appendText("host: ${android.os.Build.HOST}\n")
|
file?.appendText("host: ${Build.HOST}\n")
|
||||||
file?.appendText("id: ${android.os.Build.ID}\n")
|
file?.appendText("id: ${Build.ID}\n")
|
||||||
file?.appendText("type: ${android.os.Build.TYPE}\n")
|
file?.appendText("type: ${Build.TYPE}\n")
|
||||||
file?.appendText("user: ${android.os.Build.USER}\n")
|
file?.appendText("user: ${Build.USER}\n")
|
||||||
file?.appendText("tags: ${android.os.Build.TAGS}\n")
|
file?.appendText("tags: ${Build.TAGS}\n")
|
||||||
file?.appendText("time: ${android.os.Build.TIME}\n")
|
file?.appendText("time: ${Build.TIME}\n")
|
||||||
file?.appendText("radio: ${android.os.Build.RADIO}\n")
|
file?.appendText("radio: ${Build.getRadioVersion()}\n")
|
||||||
file?.appendText("bootloader: ${android.os.Build.BOOTLOADER}\n")
|
file?.appendText("bootloader: ${Build.BOOTLOADER}\n")
|
||||||
file?.appendText("board: ${android.os.Build.BOARD}\n")
|
file?.appendText("board: ${Build.BOARD}\n")
|
||||||
file?.appendText("fingerprint: ${android.os.Build.FINGERPRINT}\n")
|
file?.appendText("fingerprint: ${Build.FINGERPRINT}\n")
|
||||||
file?.appendText("supported_abis: ${android.os.Build.SUPPORTED_ABIS.joinToString()}\n")
|
file?.appendText("supported_abis: ${Build.SUPPORTED_ABIS.joinToString()}\n")
|
||||||
file?.appendText("supported_32_bit_abis: ${android.os.Build.SUPPORTED_32_BIT_ABIS.joinToString()}\n")
|
file?.appendText("supported_32_bit_abis: ${Build.SUPPORTED_32_BIT_ABIS.joinToString()}\n")
|
||||||
file?.appendText("supported_64_bit_abis: ${android.os.Build.SUPPORTED_64_BIT_ABIS.joinToString()}\n")
|
file?.appendText("supported_64_bit_abis: ${Build.SUPPORTED_64_BIT_ABIS.joinToString()}\n")
|
||||||
file?.appendText("is emulator: ${android.os.Build.FINGERPRINT.contains("generic")}\n")
|
file?.appendText("is emulator: ${Build.FINGERPRINT.contains("generic")}\n")
|
||||||
file?.appendText("--------------------------------\n")
|
file?.appendText("--------------------------------\n")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Injekt.get<CrashlyticsInterface>().logException(e)
|
Injekt.get<CrashlyticsInterface>().logException(e)
|
||||||
|
|
|
@ -147,7 +147,7 @@ object Notifications {
|
||||||
setGroup(GROUP_COMMENTS)
|
setGroup(GROUP_COMMENTS)
|
||||||
},
|
},
|
||||||
buildNotificationChannel(CHANNEL_COMMENT_WARING, IMPORTANCE_HIGH) {
|
buildNotificationChannel(CHANNEL_COMMENT_WARING, IMPORTANCE_HIGH) {
|
||||||
setName("CommentNotificationWorker Warnings")
|
setName("Comment Warnings")
|
||||||
setGroup(GROUP_COMMENTS)
|
setGroup(GROUP_COMMENTS)
|
||||||
},
|
},
|
||||||
buildNotificationChannel(CHANNEL_ANILIST, IMPORTANCE_DEFAULT) {
|
buildNotificationChannel(CHANNEL_ANILIST, IMPORTANCE_DEFAULT) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import android.os.PowerManager
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import androidx.annotation.AttrRes
|
import androidx.annotation.AttrRes
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.PermissionChecker
|
import androidx.core.content.PermissionChecker
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.graphics.alpha
|
import androidx.core.graphics.alpha
|
||||||
|
@ -85,7 +86,7 @@ fun Context.getThemeColor(attr: Int): Int {
|
||||||
val tv = TypedValue()
|
val tv = TypedValue()
|
||||||
return if (this.theme.resolveAttribute(attr, tv, true)) {
|
return if (this.theme.resolveAttribute(attr, tv, true)) {
|
||||||
if (tv.resourceId != 0) {
|
if (tv.resourceId != 0) {
|
||||||
getColor(tv.resourceId)
|
ContextCompat.getColor(this, tv.resourceId)
|
||||||
} else {
|
} else {
|
||||||
tv.data
|
tv.data
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import androidx.core.app.NotificationChannelGroupCompat
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.core.app.NotificationManagerCompat.NotificationWithIdAndTag
|
import androidx.core.app.NotificationManagerCompat.NotificationWithIdAndTag
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.PermissionChecker
|
import androidx.core.content.PermissionChecker
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
|
|
||||||
|
@ -65,7 +66,7 @@ fun Context.notificationBuilder(
|
||||||
block: (NotificationCompat.Builder.() -> Unit)? = null
|
block: (NotificationCompat.Builder.() -> Unit)? = null
|
||||||
): NotificationCompat.Builder {
|
): NotificationCompat.Builder {
|
||||||
val builder = NotificationCompat.Builder(this, channelId)
|
val builder = NotificationCompat.Builder(this, channelId)
|
||||||
.setColor(getColor(android.R.color.holo_blue_dark))
|
.setColor(ContextCompat.getColor(this, android.R.color.holo_blue_dark))
|
||||||
if (block != null) {
|
if (block != null) {
|
||||||
builder.block()
|
builder.block()
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,7 @@
|
||||||
android:id="@+id/statisticList"
|
android:id="@+id/statisticList"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
android:nestedScrollingEnabled="true"
|
android:nestedScrollingEnabled="true"
|
||||||
tools:listitem="@layout/item_chart" />
|
tools:listitem="@layout/item_chart" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
7
app/src/main/res/values-v23/themes.xml
Normal file
7
app/src/main/res/values-v23/themes.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="Theme.Dantotsu" parent="Theme.Base">
|
||||||
|
<item name="android:windowLightStatusBar">false</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
|
@ -486,6 +486,7 @@
|
||||||
|
|
||||||
<string name="read_on_dantotsu">Read on Dantotsu</string>
|
<string name="read_on_dantotsu">Read on Dantotsu</string>
|
||||||
<string name="watch_on_dantotsu">Watch on Dantotsu</string>
|
<string name="watch_on_dantotsu">Watch on Dantotsu</string>
|
||||||
|
<string name="view_profile_in_dantotsu">View Profile in Dantotsu</string>
|
||||||
<string name="continue_episode">"Continue : Episode "</string>
|
<string name="continue_episode">"Continue : Episode "</string>
|
||||||
<string name="continue_chapter">"Continue : "</string>
|
<string name="continue_chapter">"Continue : "</string>
|
||||||
<string name="episode">"Episode "</string>
|
<string name="episode">"Episode "</string>
|
||||||
|
|
|
@ -29,10 +29,6 @@
|
||||||
</item>
|
</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Dantotsu" parent="Theme.Base">
|
|
||||||
<item name="android:windowLightStatusBar">false</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="Theme.Dantotsu.NoActionBar">
|
<style name="Theme.Dantotsu.NoActionBar">
|
||||||
<item name="windowActionBar">false</item>
|
<item name="windowActionBar">false</item>
|
||||||
<item name="windowNoTitle">true</item>
|
<item name="windowNoTitle">true</item>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue