offline manga fix
This commit is contained in:
parent
c7bc1ffe9e
commit
f792296f78
6 changed files with 227 additions and 104 deletions
|
@ -26,6 +26,7 @@ import ani.dantotsu.R
|
|||
import ani.dantotsu.connections.discord.serializers.Activity
|
||||
import ani.dantotsu.connections.discord.serializers.Presence
|
||||
import ani.dantotsu.connections.discord.serializers.User
|
||||
import ani.dantotsu.isOnline
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
|
@ -112,6 +113,7 @@ class DiscordService : Service() {
|
|||
}else{
|
||||
log("Service onStartCommand() no presence")
|
||||
DiscordServiceRunningSingleton.running = false
|
||||
client.dispatcher.executorService.shutdown()
|
||||
stopSelf()
|
||||
}
|
||||
if (intent.hasExtra(ACTION_STOP_SERVICE)) {
|
||||
|
@ -123,8 +125,6 @@ class DiscordService : Service() {
|
|||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
log("Service Destroyed")
|
||||
if (DiscordServiceRunningSingleton.running){
|
||||
log("Accidental Service Destruction, restarting service")
|
||||
|
@ -135,6 +135,7 @@ class DiscordService : Service() {
|
|||
baseContext.startService(intent)
|
||||
}
|
||||
} else {
|
||||
if(this::webSocket.isInitialized)
|
||||
setPresence(json.encodeToString(
|
||||
Presence.Response(
|
||||
3,
|
||||
|
@ -145,6 +146,7 @@ class DiscordService : Service() {
|
|||
}
|
||||
SERVICE_RUNNING = false
|
||||
if(this::webSocket.isInitialized) webSocket.close(1000, "Closed by user")
|
||||
super.onDestroy()
|
||||
//saveLogToFile()
|
||||
}
|
||||
|
||||
|
@ -167,6 +169,9 @@ class DiscordService : Service() {
|
|||
override fun onBind(p0: Intent?): IBinder? = null
|
||||
|
||||
inner class DiscordWebSocketListener : WebSocketListener() {
|
||||
|
||||
var retryAttempts = 0
|
||||
val maxRetryAttempts = 10
|
||||
override fun onOpen(webSocket: WebSocket, response: Response) {
|
||||
super.onOpen(webSocket, response)
|
||||
this@DiscordService.webSocket = webSocket
|
||||
|
@ -256,6 +261,18 @@ class DiscordService : Service() {
|
|||
}
|
||||
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
|
||||
super.onFailure(webSocket, t, response)
|
||||
if(!isOnline(baseContext)) {
|
||||
log("WebSocket: Error, onFailure() reason: No Internet")
|
||||
errorNotification("Could not set the presence", "No Internet")
|
||||
return
|
||||
} else{
|
||||
retryAttempts++
|
||||
if(retryAttempts >= maxRetryAttempts) {
|
||||
log("WebSocket: Error, onFailure() reason: Max Retry Attempts")
|
||||
errorNotification("Could not set the presence", "Max Retry Attempts")
|
||||
return
|
||||
}
|
||||
}
|
||||
t.message?.let { Log.d("WebSocket", "onFailure() $it") }
|
||||
log("WebSocket: Error, onFailure() reason: ${t.message}")
|
||||
client = OkHttpClient()
|
||||
|
@ -264,13 +281,13 @@ class DiscordService : Service() {
|
|||
DiscordWebSocketListener()
|
||||
)
|
||||
client.dispatcher.executorService.shutdown()
|
||||
if(!heartbeatThread.isInterrupted) { heartbeatThread.interrupt() }
|
||||
if(::heartbeatThread.isInitialized && !heartbeatThread.isInterrupted) { heartbeatThread.interrupt() }
|
||||
}
|
||||
|
||||
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
|
||||
super.onClosing(webSocket, code, reason)
|
||||
Log.d("WebSocket", "onClosing() $code $reason")
|
||||
if(!heartbeatThread.isInterrupted) { heartbeatThread.interrupt() }
|
||||
if(::heartbeatThread.isInitialized && !heartbeatThread.isInterrupted) { heartbeatThread.interrupt() }
|
||||
}
|
||||
|
||||
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
|
||||
|
|
|
@ -98,14 +98,17 @@ class MangaReaderActivity : AppCompatActivity() {
|
|||
var sliding = false
|
||||
var isAnimating = false
|
||||
|
||||
private var rpc : RPC? = null
|
||||
private var rpc: RPC? = null
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !settings.showSystemBars) {
|
||||
val displayCutout = window.decorView.rootWindowInsets.displayCutout
|
||||
if (displayCutout != null) {
|
||||
if (displayCutout.boundingRects.size > 0) {
|
||||
notchHeight = min(displayCutout.boundingRects[0].width(), displayCutout.boundingRects[0].height())
|
||||
notchHeight = min(
|
||||
displayCutout.boundingRects[0].width(),
|
||||
displayCutout.boundingRects[0].height()
|
||||
)
|
||||
checkNotch()
|
||||
}
|
||||
}
|
||||
|
@ -128,15 +131,17 @@ class MangaReaderActivity : AppCompatActivity() {
|
|||
val stopIntent = Intent(this, DiscordService::class.java).apply {
|
||||
putExtra(DiscordService.ACTION_STOP_SERVICE, true)
|
||||
}
|
||||
DiscordServiceRunningSingleton.running = false
|
||||
startService(stopIntent)
|
||||
if (!isOnline(this)) { //TODO:
|
||||
DiscordServiceRunningSingleton.running = false
|
||||
startService(stopIntent)
|
||||
}
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
LangSet.setLocale(this)
|
||||
ThemeManager(this).applyTheme()
|
||||
ThemeManager(this).applyTheme()
|
||||
binding = ActivityMangaReaderBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
@ -148,8 +153,14 @@ ThemeManager(this).applyTheme()
|
|||
progress { finish() }
|
||||
}
|
||||
|
||||
settings = loadData("reader_settings", this) ?: ReaderSettings().apply { saveData("reader_settings", this) }
|
||||
uiSettings = loadData("ui_settings", this) ?: UserInterfaceSettings().apply { saveData("ui_settings", this) }
|
||||
settings = loadData("reader_settings", this)
|
||||
?: ReaderSettings().apply { saveData("reader_settings", this) }
|
||||
uiSettings = loadData("ui_settings", this) ?: UserInterfaceSettings().apply {
|
||||
saveData(
|
||||
"ui_settings",
|
||||
this
|
||||
)
|
||||
}
|
||||
controllerDuration = (uiSettings.animationSpeed * 200).toLong()
|
||||
|
||||
hideBars()
|
||||
|
@ -174,9 +185,11 @@ ThemeManager(this).applyTheme()
|
|||
if (fromUser) {
|
||||
sliding = true
|
||||
if (settings.default.layout != PAGED)
|
||||
binding.mangaReaderRecycler.scrollToPosition((value.toInt() - 1) / (dualPage { 2 } ?: 1))
|
||||
binding.mangaReaderRecycler.scrollToPosition((value.toInt() - 1) / (dualPage { 2 }
|
||||
?: 1))
|
||||
else
|
||||
binding.mangaReaderPager.currentItem = (value.toInt() - 1) / (dualPage { 2 } ?: 1)
|
||||
binding.mangaReaderPager.currentItem =
|
||||
(value.toInt() - 1) / (dualPage { 2 } ?: 1)
|
||||
pageSliderHide()
|
||||
}
|
||||
}
|
||||
|
@ -202,25 +215,25 @@ ThemeManager(this).applyTheme()
|
|||
|
||||
model.mangaReadSources = if (media.isAdult) HMangaSources else MangaSources
|
||||
binding.mangaReaderSource.visibility = if (settings.showSource) View.VISIBLE else View.GONE
|
||||
if(model.mangaReadSources!!.names.isEmpty()){
|
||||
if (model.mangaReadSources!!.names.isEmpty()) {
|
||||
//try to reload sources
|
||||
try {
|
||||
if (media.isAdult) {
|
||||
val mangaSources = MangaSources
|
||||
val scope = lifecycleScope
|
||||
scope.launch(Dispatchers.IO) {
|
||||
mangaSources.init(Injekt.get<MangaExtensionManager>().installedExtensionsFlow)
|
||||
if (media.isAdult) {
|
||||
val mangaSources = MangaSources
|
||||
val scope = lifecycleScope
|
||||
scope.launch(Dispatchers.IO) {
|
||||
mangaSources.init(Injekt.get<MangaExtensionManager>().installedExtensionsFlow)
|
||||
}
|
||||
model.mangaReadSources = mangaSources
|
||||
} else {
|
||||
val mangaSources = HMangaSources
|
||||
val scope = lifecycleScope
|
||||
scope.launch(Dispatchers.IO) {
|
||||
mangaSources.init(Injekt.get<MangaExtensionManager>().installedExtensionsFlow)
|
||||
}
|
||||
model.mangaReadSources = mangaSources
|
||||
}
|
||||
model.mangaReadSources = mangaSources
|
||||
}else{
|
||||
val mangaSources = HMangaSources
|
||||
val scope = lifecycleScope
|
||||
scope.launch(Dispatchers.IO) {
|
||||
mangaSources.init(Injekt.get<MangaExtensionManager>().installedExtensionsFlow)
|
||||
}
|
||||
model.mangaReadSources = mangaSources
|
||||
}
|
||||
}catch (e: Exception){
|
||||
} catch (e: Exception) {
|
||||
Firebase.crashlytics.recordException(e)
|
||||
logError(e)
|
||||
}
|
||||
|
@ -229,7 +242,8 @@ ThemeManager(this).applyTheme()
|
|||
if (media.selected!!.sourceIndex >= model.mangaReadSources!!.names.size) {
|
||||
media.selected!!.sourceIndex = 0
|
||||
}
|
||||
binding.mangaReaderSource.text = model.mangaReadSources!!.names[media.selected!!.sourceIndex]
|
||||
binding.mangaReaderSource.text =
|
||||
model.mangaReadSources!!.names[media.selected!!.sourceIndex]
|
||||
|
||||
binding.mangaReaderTitle.text = media.userPreferredName
|
||||
|
||||
|
@ -242,10 +256,12 @@ ThemeManager(this).applyTheme()
|
|||
chaptersTitleArr.add("${if (!chapter.title.isNullOrEmpty() && chapter.title != "null") "" else "Chapter "}${chapter.number}${if (!chapter.title.isNullOrEmpty() && chapter.title != "null") " : " + chapter.title else ""}")
|
||||
}
|
||||
|
||||
showProgressDialog = if (settings.askIndividual) loadData<Boolean>("${media.id}_progressDialog") != true else false
|
||||
showProgressDialog =
|
||||
if (settings.askIndividual) loadData<Boolean>("${media.id}_progressDialog") != true else false
|
||||
progressDialog =
|
||||
if (showProgressDialog && Anilist.userid != null && if (media.isAdult) settings.updateForH else true)
|
||||
AlertDialog.Builder(this, R.style.MyPopup).setTitle(getString(R.string.title_update_progress)).apply {
|
||||
AlertDialog.Builder(this, R.style.MyPopup)
|
||||
.setTitle(getString(R.string.title_update_progress)).apply {
|
||||
setMultiChoiceItems(
|
||||
arrayOf(getString(R.string.dont_ask_again, media.userPreferredName)),
|
||||
booleanArrayOf(false)
|
||||
|
@ -262,19 +278,27 @@ ThemeManager(this).applyTheme()
|
|||
fun change(index: Int) {
|
||||
mangaCache.clear()
|
||||
saveData("${media.id}_${chaptersArr[currentChapterIndex]}", currentChapterPage, this)
|
||||
ChapterLoaderDialog.newInstance(chapters[chaptersArr[index]]!!).show(supportFragmentManager, "dialog")
|
||||
ChapterLoaderDialog.newInstance(chapters[chaptersArr[index]]!!)
|
||||
.show(supportFragmentManager, "dialog")
|
||||
}
|
||||
|
||||
//ChapterSelector
|
||||
binding.mangaReaderChapterSelect.adapter = NoPaddingArrayAdapter(this, R.layout.item_dropdown, chaptersTitleArr)
|
||||
binding.mangaReaderChapterSelect.adapter =
|
||||
NoPaddingArrayAdapter(this, R.layout.item_dropdown, chaptersTitleArr)
|
||||
binding.mangaReaderChapterSelect.setSelection(currentChapterIndex)
|
||||
binding.mangaReaderChapterSelect.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, position: Int, p3: Long) {
|
||||
if (position != currentChapterIndex) change(position)
|
||||
}
|
||||
binding.mangaReaderChapterSelect.onItemSelectedListener =
|
||||
object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(
|
||||
p0: AdapterView<*>?,
|
||||
p1: View?,
|
||||
position: Int,
|
||||
p3: Long
|
||||
) {
|
||||
if (position != currentChapterIndex) change(position)
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>) {}
|
||||
}
|
||||
override fun onNothingSelected(parent: AdapterView<*>) {}
|
||||
}
|
||||
|
||||
binding.mangaReaderSettings.setSafeOnClickListener {
|
||||
ReaderSettingsDialogFragment.newInstance().show(supportFragmentManager, "settings")
|
||||
|
@ -305,57 +329,69 @@ ThemeManager(this).applyTheme()
|
|||
saveData("${media.id}_current_chp", chap.number, this)
|
||||
currentChapterIndex = chaptersArr.indexOf(chap.number)
|
||||
binding.mangaReaderChapterSelect.setSelection(currentChapterIndex)
|
||||
binding.mangaReaderNextChap.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
|
||||
binding.mangaReaderPrevChap.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
|
||||
binding.mangaReaderNextChap.text =
|
||||
chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
|
||||
binding.mangaReaderPrevChap.text =
|
||||
chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
|
||||
applySettings()
|
||||
val context = this
|
||||
lifecycleScope.launch {
|
||||
val presence = RPC.createPresence(RPC.Companion.RPCData(
|
||||
applicationId = Discord.application_Id,
|
||||
type = RPC.Type.WATCHING,
|
||||
activityName = media.userPreferredName,
|
||||
details = chap.title?.takeIf { it.isNotEmpty() } ?: getString(R.string.chapter_num, chap.number),
|
||||
state = "${chap.number}/${media.manga?.totalChapters ?: "??"}",
|
||||
largeImage = media.cover?.let { cover ->
|
||||
RPC.Link(media.userPreferredName, cover)
|
||||
},
|
||||
smallImage = RPC.Link(
|
||||
"Dantotsu",
|
||||
Discord.small_Image
|
||||
),
|
||||
buttons = mutableListOf(
|
||||
RPC.Link(getString(R.string.view_manga), media.shareLink ?: ""),
|
||||
RPC.Link(
|
||||
"Stream on Dantotsu",
|
||||
"https://github.com/rebelonion/Dantotsu/"
|
||||
if (isOnline(context)) {
|
||||
lifecycleScope.launch {
|
||||
val presence = RPC.createPresence(
|
||||
RPC.Companion.RPCData(
|
||||
applicationId = Discord.application_Id,
|
||||
type = RPC.Type.WATCHING,
|
||||
activityName = media.userPreferredName,
|
||||
details = chap.title?.takeIf { it.isNotEmpty() }
|
||||
?: getString(R.string.chapter_num, chap.number),
|
||||
state = "${chap.number}/${media.manga?.totalChapters ?: "??"}",
|
||||
largeImage = media.cover?.let { cover ->
|
||||
RPC.Link(media.userPreferredName, cover)
|
||||
},
|
||||
smallImage = RPC.Link(
|
||||
"Dantotsu",
|
||||
Discord.small_Image
|
||||
),
|
||||
buttons = mutableListOf(
|
||||
RPC.Link(getString(R.string.view_manga), media.shareLink ?: ""),
|
||||
RPC.Link(
|
||||
"Stream on Dantotsu",
|
||||
"https://github.com/rebelonion/Dantotsu/"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val intent = Intent(context, DiscordService::class.java).apply {
|
||||
putExtra("presence", presence)
|
||||
val intent = Intent(context, DiscordService::class.java).apply {
|
||||
putExtra("presence", presence)
|
||||
}
|
||||
DiscordServiceRunningSingleton.running = true
|
||||
startService(intent)
|
||||
}
|
||||
DiscordServiceRunningSingleton.running = true
|
||||
startService(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope.launch(Dispatchers.IO) { model.loadMangaChapterImages(chapter, media.selected!!, media.nameMAL?:media.nameRomaji) }
|
||||
scope.launch(Dispatchers.IO) {
|
||||
model.loadMangaChapterImages(
|
||||
chapter,
|
||||
media.selected!!,
|
||||
media.nameMAL ?: media.nameRomaji
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val snapHelper = PagerSnapHelper()
|
||||
|
||||
fun <T> dualPage(callback: () -> T): T? {
|
||||
return when (settings.default.dualPageMode) {
|
||||
No -> null
|
||||
No -> null
|
||||
Automatic -> {
|
||||
val orientation = resources.configuration.orientation
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) callback.invoke()
|
||||
else null
|
||||
}
|
||||
Force -> callback.invoke()
|
||||
|
||||
Force -> callback.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,7 +422,8 @@ ThemeManager(this).applyTheme()
|
|||
maxChapterPage = chapImages.size.toLong()
|
||||
saveData("${media.id}_${chapter.number}_max", maxChapterPage)
|
||||
|
||||
imageAdapter = dualPage { DualPageAdapter(this, chapter) } ?: ImageAdapter(this, chapter)
|
||||
imageAdapter =
|
||||
dualPage { DualPageAdapter(this, chapter) } ?: ImageAdapter(this, chapter)
|
||||
|
||||
if (chapImages.size > 1) {
|
||||
binding.mangaReaderSlider.apply {
|
||||
|
@ -407,8 +444,10 @@ ThemeManager(this).applyTheme()
|
|||
if ((settings.default.direction == TOP_TO_BOTTOM || settings.default.direction == BOTTOM_TO_TOP)) {
|
||||
binding.mangaReaderSwipy.vertical = true
|
||||
if (settings.default.direction == TOP_TO_BOTTOM) {
|
||||
binding.BottomSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: getString(R.string.no_chapter)
|
||||
binding.TopSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: getString(R.string.no_chapter)
|
||||
binding.BottomSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1)
|
||||
?: getString(R.string.no_chapter)
|
||||
binding.TopSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1)
|
||||
?: getString(R.string.no_chapter)
|
||||
binding.mangaReaderSwipy.onTopSwiped = {
|
||||
binding.mangaReaderPreviousChapter.performClick()
|
||||
}
|
||||
|
@ -416,8 +455,10 @@ ThemeManager(this).applyTheme()
|
|||
binding.mangaReaderNextChapter.performClick()
|
||||
}
|
||||
} else {
|
||||
binding.BottomSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: getString(R.string.no_chapter)
|
||||
binding.TopSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: getString(R.string.no_chapter)
|
||||
binding.BottomSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1)
|
||||
?: getString(R.string.no_chapter)
|
||||
binding.TopSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1)
|
||||
?: getString(R.string.no_chapter)
|
||||
binding.mangaReaderSwipy.onTopSwiped = {
|
||||
binding.mangaReaderNextChapter.performClick()
|
||||
}
|
||||
|
@ -440,8 +481,10 @@ ThemeManager(this).applyTheme()
|
|||
} else {
|
||||
binding.mangaReaderSwipy.vertical = false
|
||||
if (settings.default.direction == RIGHT_TO_LEFT) {
|
||||
binding.LeftSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: getString(R.string.no_chapter)
|
||||
binding.RightSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: getString(R.string.no_chapter)
|
||||
binding.LeftSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1)
|
||||
?: getString(R.string.no_chapter)
|
||||
binding.RightSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1)
|
||||
?: getString(R.string.no_chapter)
|
||||
binding.mangaReaderSwipy.onLeftSwiped = {
|
||||
binding.mangaReaderNextChapter.performClick()
|
||||
}
|
||||
|
@ -449,8 +492,10 @@ ThemeManager(this).applyTheme()
|
|||
binding.mangaReaderPreviousChapter.performClick()
|
||||
}
|
||||
} else {
|
||||
binding.LeftSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: getString(R.string.no_chapter)
|
||||
binding.RightSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: getString(R.string.no_chapter)
|
||||
binding.LeftSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1)
|
||||
?: getString(R.string.no_chapter)
|
||||
binding.RightSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1)
|
||||
?: getString(R.string.no_chapter)
|
||||
binding.mangaReaderSwipy.onLeftSwiped = {
|
||||
binding.mangaReaderPreviousChapter.performClick()
|
||||
}
|
||||
|
@ -475,7 +520,8 @@ ThemeManager(this).applyTheme()
|
|||
if (settings.default.layout != PAGED) {
|
||||
|
||||
binding.mangaReaderRecyclerContainer.visibility = View.VISIBLE
|
||||
binding.mangaReaderRecyclerContainer.controller.settings.isRotationEnabled = settings.default.rotation
|
||||
binding.mangaReaderRecyclerContainer.controller.settings.isRotationEnabled =
|
||||
settings.default.rotation
|
||||
|
||||
val detector = GestureDetectorCompat(this, object : GesturesListener() {
|
||||
override fun onLongPress(e: MotionEvent) {
|
||||
|
@ -483,18 +529,31 @@ ThemeManager(this).applyTheme()
|
|||
child ?: return@let false
|
||||
val pos = binding.mangaReaderRecycler.getChildAdapterPosition(child)
|
||||
val callback: (ImageViewDialog) -> Unit = { dialog ->
|
||||
lifecycleScope.launch { imageAdapter?.loadImage(pos, child as GestureFrameLayout) }
|
||||
binding.mangaReaderRecycler.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
lifecycleScope.launch {
|
||||
imageAdapter?.loadImage(
|
||||
pos,
|
||||
child as GestureFrameLayout
|
||||
)
|
||||
}
|
||||
binding.mangaReaderRecycler.performHapticFeedback(
|
||||
HapticFeedbackConstants.LONG_PRESS
|
||||
)
|
||||
dialog.dismiss()
|
||||
}
|
||||
dualPage {
|
||||
val page = chapter.dualPages().getOrNull(pos) ?: return@dualPage false
|
||||
val page =
|
||||
chapter.dualPages().getOrNull(pos) ?: return@dualPage false
|
||||
val nextPage = page.second
|
||||
if (settings.default.direction != LEFT_TO_RIGHT && nextPage != null)
|
||||
onImageLongClicked(pos * 2, nextPage, page.first, callback)
|
||||
else
|
||||
onImageLongClicked(pos * 2, page.first, nextPage, callback)
|
||||
} ?: onImageLongClicked(pos, chapImages.getOrNull(pos) ?: return@let false, null, callback)
|
||||
} ?: onImageLongClicked(
|
||||
pos,
|
||||
chapImages.getOrNull(pos) ?: return@let false,
|
||||
null,
|
||||
callback
|
||||
)
|
||||
}
|
||||
) binding.mangaReaderRecycler.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
super.onLongPress(e)
|
||||
|
@ -536,12 +595,16 @@ ThemeManager(this).applyTheme()
|
|||
&& (!v.canScrollVertically(-1) || !v.canScrollVertically(1)))
|
||||
||
|
||||
((direction == LEFT_TO_RIGHT || direction == RIGHT_TO_LEFT)
|
||||
&& (!v.canScrollHorizontally(-1) || !v.canScrollHorizontally(1)))
|
||||
&& (!v.canScrollHorizontally(-1) || !v.canScrollHorizontally(
|
||||
1
|
||||
)))
|
||||
) {
|
||||
handleController(true)
|
||||
} else handleController(false)
|
||||
}
|
||||
updatePageNumber(manager.findLastVisibleItemPosition().toLong() * (dualPage { 2 } ?: 1) + 1)
|
||||
updatePageNumber(
|
||||
manager.findLastVisibleItemPosition().toLong() * (dualPage { 2 }
|
||||
?: 1) + 1)
|
||||
super.onScrolled(v, dx, dy)
|
||||
}
|
||||
})
|
||||
|
@ -603,7 +666,7 @@ ThemeManager(this).applyTheme()
|
|||
private var onVolumeDown: (() -> Unit)? = null
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
return when (event.keyCode) {
|
||||
KEYCODE_VOLUME_UP, KEYCODE_DPAD_UP, KEYCODE_PAGE_UP -> {
|
||||
KEYCODE_VOLUME_UP, KEYCODE_DPAD_UP, KEYCODE_PAGE_UP -> {
|
||||
if (event.keyCode == KEYCODE_VOLUME_UP)
|
||||
if (!settings.default.volumeButtons)
|
||||
return false
|
||||
|
@ -612,6 +675,7 @@ ThemeManager(this).applyTheme()
|
|||
true
|
||||
} else false
|
||||
}
|
||||
|
||||
KEYCODE_VOLUME_DOWN, KEYCODE_DPAD_DOWN, KEYCODE_PAGE_DOWN -> {
|
||||
if (event.keyCode == KEYCODE_VOLUME_DOWN)
|
||||
if (!settings.default.volumeButtons)
|
||||
|
@ -621,7 +685,8 @@ ThemeManager(this).applyTheme()
|
|||
true
|
||||
} else false
|
||||
}
|
||||
else -> {
|
||||
|
||||
else -> {
|
||||
super.dispatchKeyEvent(event)
|
||||
}
|
||||
}
|
||||
|
@ -695,8 +760,14 @@ ThemeManager(this).applyTheme()
|
|||
isContVisible = false
|
||||
if (!isAnimating) {
|
||||
isAnimating = true
|
||||
ObjectAnimator.ofFloat(binding.mangaReaderCont, "alpha", 1f, 0f).setDuration(controllerDuration).start()
|
||||
ObjectAnimator.ofFloat(binding.mangaReaderBottomLayout, "translationY", 0f, 128f)
|
||||
ObjectAnimator.ofFloat(binding.mangaReaderCont, "alpha", 1f, 0f)
|
||||
.setDuration(controllerDuration).start()
|
||||
ObjectAnimator.ofFloat(
|
||||
binding.mangaReaderBottomLayout,
|
||||
"translationY",
|
||||
0f,
|
||||
128f
|
||||
)
|
||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||
ObjectAnimator.ofFloat(binding.mangaReaderTopLayout, "translationY", 0f, -128f)
|
||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||
|
@ -705,7 +776,8 @@ ThemeManager(this).applyTheme()
|
|||
} else {
|
||||
isContVisible = true
|
||||
binding.mangaReaderCont.visibility = View.VISIBLE
|
||||
ObjectAnimator.ofFloat(binding.mangaReaderCont, "alpha", 0f, 1f).setDuration(controllerDuration).start()
|
||||
ObjectAnimator.ofFloat(binding.mangaReaderCont, "alpha", 0f, 1f)
|
||||
.setDuration(controllerDuration).start()
|
||||
ObjectAnimator.ofFloat(binding.mangaReaderTopLayout, "translationY", -128f, 0f)
|
||||
.apply { interpolator = overshoot;duration = controllerDuration;start() }
|
||||
ObjectAnimator.ofFloat(binding.mangaReaderBottomLayout, "translationY", 128f, 0f)
|
||||
|
@ -731,7 +803,7 @@ ThemeManager(this).applyTheme()
|
|||
model.loadMangaChapterImages(
|
||||
chapters[chaptersArr.getOrNull(currentChapterIndex + 1) ?: return@launch]!!,
|
||||
media.selected!!,
|
||||
media.nameMAL?:media.nameRomaji,
|
||||
media.nameMAL ?: media.nameRomaji,
|
||||
false
|
||||
)
|
||||
loading = false
|
||||
|
@ -744,7 +816,11 @@ ThemeManager(this).applyTheme()
|
|||
progressDialog?.setCancelable(false)
|
||||
?.setPositiveButton(getString(R.string.yes)) { dialog, _ ->
|
||||
saveData("${media.id}_save_progress", true)
|
||||
updateProgress(media, MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!).toString())
|
||||
updateProgress(
|
||||
media,
|
||||
MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!)
|
||||
.toString()
|
||||
)
|
||||
dialog.dismiss()
|
||||
runnable.run()
|
||||
}
|
||||
|
@ -756,7 +832,11 @@ ThemeManager(this).applyTheme()
|
|||
progressDialog?.show()
|
||||
} else {
|
||||
if (loadData<Boolean>("${media.id}_save_progress") != false && if (media.isAdult) settings.updateForH else true)
|
||||
updateProgress(media, MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!).toString())
|
||||
updateProgress(
|
||||
media,
|
||||
MangaNameAdapter.findChapterNumber(media.manga!!.selectedChapter!!)
|
||||
.toString()
|
||||
)
|
||||
runnable.run()
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -24,6 +24,7 @@ import kotlinx.serialization.SerialName
|
|||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.decodeFromJsonElement
|
||||
import rx.android.BuildConfig
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
|
|
@ -231,6 +231,15 @@ internal class NovelExtensionInstaller(private val context: Context) {
|
|||
val destination = File(destinationPath)
|
||||
destination.setWritable(true)
|
||||
|
||||
//delete the file if it already exists
|
||||
if (destination.exists()) {
|
||||
if (destination.delete()) {
|
||||
Log.i("File Copy", "File deleted successfully.")
|
||||
} else {
|
||||
Log.e("File Copy", "Failed to delete file.")
|
||||
}
|
||||
}
|
||||
|
||||
var inputChannel: FileChannel? = null
|
||||
var outputChannel: FileChannel? = null
|
||||
try {
|
||||
|
|
|
@ -2,9 +2,13 @@ package ani.dantotsu.parsers.novel
|
|||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager.GET_SIGNATURES
|
||||
import android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import ani.dantotsu.logger
|
||||
import ani.dantotsu.parsers.NovelInterface
|
||||
import ani.dantotsu.snackString
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import dalvik.system.PathClassLoader
|
||||
import eu.kanade.tachiyomi.extension.anime.util.AnimeExtensionLoader
|
||||
|
@ -60,9 +64,15 @@ internal object NovelExtensionLoader {
|
|||
return loadExtension(context, File(path))
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun loadExtension(context: Context, file: File): NovelLoadResult {
|
||||
val packageInfo = context.packageManager.getPackageArchiveInfo(file.absolutePath, 0)
|
||||
?: return NovelLoadResult.Error(Exception("Failed to load extension"))
|
||||
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
context.packageManager.getPackageArchiveInfo(file.absolutePath, GET_SIGNING_CERTIFICATES)
|
||||
?: return NovelLoadResult.Error(Exception("Failed to load extension"))
|
||||
} else {
|
||||
context.packageManager.getPackageArchiveInfo(file.absolutePath, GET_SIGNATURES)
|
||||
?: return NovelLoadResult.Error(Exception("Failed to load extension"))
|
||||
}
|
||||
val appInfo = packageInfo.applicationInfo
|
||||
?: return NovelLoadResult.Error(Exception("Failed to load Extension Info"))
|
||||
appInfo.sourceDir = file.absolutePath;
|
||||
|
@ -70,10 +80,11 @@ internal object NovelExtensionLoader {
|
|||
|
||||
val signatureHash = getSignatureHash(packageInfo)
|
||||
|
||||
if (signatureHash == null || signatureHash != officialSignature) {
|
||||
if ((signatureHash == null) || !signatureHash.contains(officialSignature)) {
|
||||
logger("Package ${packageInfo.packageName} isn't signed")
|
||||
logger("signatureHash: $signatureHash")
|
||||
//return NovelLoadResult.Error(Exception("Extension not signed"))
|
||||
snackString("Package ${packageInfo.packageName} isn't signed")
|
||||
return NovelLoadResult.Error(Exception("Extension not signed"))
|
||||
}
|
||||
|
||||
val extension = NovelExtension.Installed(
|
||||
|
@ -92,10 +103,15 @@ internal object NovelExtensionLoader {
|
|||
return NovelLoadResult.Success(extension)
|
||||
}
|
||||
|
||||
private fun getSignatureHash(pkgInfo: PackageInfo): String? {
|
||||
val signatures = pkgInfo.signatures
|
||||
@Suppress("DEPRECATION")
|
||||
private fun getSignatureHash(pkgInfo: PackageInfo): List<String>? {
|
||||
val signatures = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
pkgInfo.signingInfo.apkContentsSigners
|
||||
} else {
|
||||
pkgInfo.signatures
|
||||
}
|
||||
return if (signatures != null && signatures.isNotEmpty()) {
|
||||
Hash.sha256(signatures.first().toByteArray())
|
||||
signatures.map { Hash.sha256(it.toByteArray()) }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ class NovelExtensionManager(private val context: Context) {
|
|||
override fun onExtensionFileCreated(file: File) {
|
||||
NovelExtensionLoader.loadExtension(context, file).let {
|
||||
if (it is NovelLoadResult.Success) {
|
||||
registerNewExtension(it.extension)
|
||||
registerNewExtension(it.extension.withUpdateCheck())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ class NovelExtensionManager(private val context: Context) {
|
|||
override fun onExtensionFileModified(file: File) {
|
||||
NovelExtensionLoader.loadExtension(context, file).let {
|
||||
if (it is NovelLoadResult.Success) {
|
||||
registerUpdatedExtension(it.extension)
|
||||
registerUpdatedExtension(it.extension.withUpdateCheck())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue