Compare commits

...

No commits in common. "main" and "proto" have entirely different histories.
main ... proto

133 changed files with 49 additions and 5936 deletions

63
.gitignore vendored
View File

@ -1,15 +1,50 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
# These are some examples of commonly ignored file patterns.
# You should customize this list as applicable to your project.
# Learn more about .gitignore:
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore
# Node artifact files
node_modules/
dist/
# Compiled Java class files
*.class
# Compiled Python bytecode
*.py[cod]
# Log files
*.log
# Package files
*.jar
# Maven
target/
dist/
# JetBrains IDE
.idea/
# Unit test reports
TEST*.xml
# Generated by MacOS
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
# Generated by Windows
Thumbs.db
# Applications
*.app
*.exe
*.war
# Large media files
*.mp4
*.tiff
*.avi
*.flv
*.mov
*.wmv

View File

@ -1,11 +0,0 @@
# tokkiz
resource from {
https://www.flaticon.com/search/2?word=rotate&color=black&shape=fill
}
한글 폰트 from {
https://gongu.copyright.or.kr/gongu/bbs/B0000018/list.do?menuNo=200195
https://noonnu.cc/font_page/1075
}

1
app/.gitignore vendored
View File

@ -1 +0,0 @@
/build

Binary file not shown.

View File

@ -1,74 +0,0 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'io.realm.kotlin'
// id 'kotlin-android-extensions'
}
android {
namespace 'com.mime.dualscreenview'
compileSdk 34
defaultConfig {
applicationId "com.mime.dualscreenview"
minSdk 24
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
debug {
storeFile = file("./bs_debug.keystore")
storePassword = "android"
keyAlias = "androiddebugkey"
keyPassword = "android"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'resources.arsc'
exclude 'AndroidManifest.xml'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
dataBinding true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.collection:collection-ktx:1.4.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1'
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.android.material:material:1.12.0'
implementation 'com.google.code.gson:gson:2.10.1'
// implementation files('libs/DualScreen.jar')
implementation ("org.jsoup:jsoup:1.18.1")
implementation 'io.realm.kotlin:library-base:2.0.0'
// testImplementation 'junit:junit:4.13.2'
}

View File

@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="false"
android:name=".BaseAppication"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:usesCleartextTraffic="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:largeHeap="true"
android:theme="@style/Theme.DualScreenView"
tools:targetApi="31" >
<activity
android:name=".activity.Intro"
android:launchMode="singleTask"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:launchMode="singleInstance"
android:name=".activity.Main"
android:exported="false">
</activity>
<activity
android:launchMode="singleInstance"
android:name=".activity.Settings"
android:exported="false"
/>
</application>
</manifest>

View File

@ -1,12 +0,0 @@
package com.mime.dualscreenview
import android.app.Application
import com.mime.dualscreenview.common.PrefManager
import io.realm.kotlin.Realm
class BaseAppication : Application() {
override fun onCreate() {
super.onCreate()
PrefManager.init(this)
}
}

View File

@ -1,181 +0,0 @@
package com.mime.dualscreenview.activity
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.text.SpannableStringBuilder
import android.text.style.RelativeSizeSpan
import android.view.Gravity
import android.view.KeyEvent
import android.view.KeyEvent.KEYCODE_BACK
import android.view.KeyEvent.KEYCODE_MEDIA_FAST_FORWARD
import android.view.KeyEvent.KEYCODE_MEDIA_NEXT
import android.view.KeyEvent.KEYCODE_MEDIA_PREVIOUS
import android.view.KeyEvent.KEYCODE_MEDIA_REWIND
import android.view.KeyEvent.KEYCODE_VOLUME_DOWN
import android.view.KeyEvent.KEYCODE_VOLUME_MUTE
import android.view.KeyEvent.KEYCODE_VOLUME_UP
import android.view.MotionEvent
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.mime.dualscreenview.common.Blog
import com.mime.dualscreenview.data.HistoryManager
import com.mime.dualscreenview.data.model.HistoryItem
import com.mime.dualscreenview.data.model.LastInfo
import io.realm.kotlin.Realm
import io.realm.kotlin.RealmConfiguration
import io.realm.kotlin.types.BaseRealmObject
import kotlin.reflect.KClass
open class Base : AppCompatActivity() {
inner class BaseHandler(looper : Looper = Looper.getMainLooper()) : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
}
}
val baseHandler = BaseHandler()
var didBackPress = false
val onBackPressRunnable = Runnable {
didBackPress = false
}
val backPressString = arrayOf(
"이퓨 워너 백투웹?\n플리즈~\n한번더 뒤로가기!!",
"이퓨 워너 종료?\n플리즈~\n한번더 뒤로가기!~!",
)
fun firstBackPress() {
didBackPress = true
val origin = "이퓨 워너 종료?\n플리즈~ 한번더 뒤로가기!~!"
val biggerText = SpannableStringBuilder(origin)
biggerText.setSpan(RelativeSizeSpan(1.6f), 0, origin.length, 0)
Toast.makeText(baseContext,biggerText,Toast.LENGTH_LONG).apply {
setGravity(Gravity.CENTER, 0, 0)
}.show()
baseHandler.postDelayed(onBackPressRunnable,1500L)
}
var actionButtonPressX = 0f
var actionButtonPressY = 0f
override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
if (ev?.device?.name?.contains("BLE-M3") == true) {
Blog.LOGE("keyEvent >>>>> dispatchGenericMotionEvent ${ev}")
ev?.action?.let { action ->
when(action) {
MotionEvent.ACTION_HOVER_ENTER -> {
return false
}
MotionEvent.ACTION_HOVER_MOVE ->{return false}
MotionEvent.ACTION_BUTTON_PRESS ->{
if (actionButtonPressX * actionButtonPressY == 0f) {
actionButtonPressX = ev.x ?: 0f
actionButtonPressY = ev.y ?: 0f
}
return true
}
MotionEvent.ACTION_BUTTON_RELEASE ->{
if (actionButtonPressY == ev.y) {
if (actionButtonPressX.minus(ev.x ?: 0f) > 0f) {
Blog.LOGE("Arrow Right Click")
onKeyClick(KeyEvent.KEYCODE_VOLUME_DOWN)
} else {
Blog.LOGE("Arrow Left Click")
onKeyClick(KeyEvent.KEYCODE_VOLUME_UP)
}
} else {
if (actionButtonPressY.minus(ev.y ?: 0f) > 0f) {
Blog.LOGE("Arrow Down Click")
} else {
Blog.LOGE("Arrow Up Click")
}
}
return false
}
MotionEvent.ACTION_HOVER_EXIT ->{
actionButtonPressX = 0f
actionButtonPressY = 0f
return false
}
else -> {return false}
}
}
}
return super.dispatchGenericMotionEvent(ev)
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
Blog.LOGD(log = "keyCode : ${keyCode}, event : ${event}")
return when(keyCode) {
KEYCODE_VOLUME_DOWN -> { true }
KEYCODE_VOLUME_UP -> { true }
KEYCODE_VOLUME_MUTE -> { true }
KEYCODE_MEDIA_FAST_FORWARD -> { true }
KEYCODE_MEDIA_REWIND -> { true }
KEYCODE_MEDIA_PREVIOUS -> { true }
KEYCODE_MEDIA_NEXT -> { true }
KEYCODE_BACK -> { false }
else -> {
super.onKeyDown(keyCode, event)
}
}
}
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
Blog.LOGD(log = "keyCode : ${keyCode}, event : ${event}")
return when(keyCode) {
KEYCODE_VOLUME_DOWN -> {
onKeyClick(keyCode)
true
}
KEYCODE_VOLUME_UP -> {
onKeyClick(keyCode)
true
}
KEYCODE_VOLUME_MUTE -> {
onKeyClick(keyCode)
true }
KEYCODE_BACK -> {
// onBackPressed()
this.onBackPressed()
false
}
KEYCODE_MEDIA_FAST_FORWARD -> { true }
KEYCODE_MEDIA_REWIND -> { true }
KEYCODE_MEDIA_PREVIOUS -> { true }
KEYCODE_MEDIA_NEXT -> { true }
else -> {
super.onKeyDown(keyCode, event)
}
}
}
open fun onKeyClick(keyCode: Int) : Boolean {
when(keyCode) {
KEYCODE_VOLUME_DOWN -> {
true
}
KEYCODE_VOLUME_UP -> {
true
}
KEYCODE_VOLUME_MUTE -> {
}
KEYCODE_MEDIA_FAST_FORWARD -> { true }
KEYCODE_MEDIA_REWIND -> { true }
KEYCODE_MEDIA_PREVIOUS -> { true }
KEYCODE_MEDIA_NEXT -> { true }
else -> {
}
}
return false
}
fun openRealm() : Realm = HistoryManager.openRealm
}

View File

@ -1,981 +0,0 @@
package com.mime.dualscreenview.activity
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.text.InputType
import android.text.SpannableStringBuilder
import android.text.style.RelativeSizeSpan
import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.View.inflate
import android.webkit.JavascriptInterface
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.ArrayAdapter
import android.widget.EditText
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.utils.widget.ImageFilterButton
import androidx.core.net.toUri
import com.google.gson.Gson
import com.mime.dualscreenview.R
import com.mime.dualscreenview.common.Blog
import com.mime.dualscreenview.common.PairArray
import com.mime.dualscreenview.common.PrefManager
import com.mime.dualscreenview.common.colorz
import com.mime.dualscreenview.common.getIndex
import com.mime.dualscreenview.common.typesfacez
import com.mime.dualscreenview.data.HistoryManager
import com.mime.dualscreenview.data.model.BookPageInfo
import com.mime.dualscreenview.data.model.BookPageInfos
import com.mime.dualscreenview.data.model.BookPageInfosJ
import com.mime.dualscreenview.data.model.HistoryItem
import com.mime.dualscreenview.data.model.LastInfo
import com.mime.dualscreenview.data.model.ReaderConfig
import com.mime.dualscreenview.databinding.IntroBinding
import com.mime.dualscreenview.dialog.DefaultList
import com.mime.dualscreenview.view.PagedTextLayout
import com.mime.dualscreenview.view.PagedTextViewInterface
import com.mime.dualscreenview.view.TouchArea
import com.mime.dualscreenview.webcontents.BaseWebContentsViewer
import com.mime.dualscreenview.webcontents.MainControllInterface
import com.mime.dualscreenview.webcontents.contentsinfo.GotoSomeWhere
import com.mime.dualscreenview.webcontents.contentsinfo.NewtokiOne
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.copyFromRealm
import io.realm.kotlin.ext.query
import org.jsoup.Jsoup
import java.lang.System.currentTimeMillis
import java.text.SimpleDateFormat
import java.util.Date
import kotlin.random.Random
class Intro : Base() , MainControllInterface, PagedTextViewInterface {
private lateinit var mBaseWebContentsViewer : BaseWebContentsViewer
var lastInfo : LastInfo? = null
lateinit var paged_layer : PagedTextLayout
lateinit var textview_title : TextView
var currentBooinfo : BookPageInfo? = null
val handle = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
if (msg.what == 0 ) {
(msg.obj as? ReaderConfig)?.let {
}
}
}
}
fun getCurrentUrl() : String {
var currentPath = currentBooinfo?.pathUrl ?: mBaseWebContentsViewer.webview.url?.toUri()?.path ?: ""
var domain = PrefManager.getLastDomain()
return domain.plus(if (currentPath.length > 4) currentPath else "")
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
Blog.LOGD(log= "onConfigurationChanged ${this::class.java.name} >> newConfig ${newConfig}")
mBaseWebContentsViewer.webview.reload()
}
var contentsSaver : WebView? = null
lateinit var binding : IntroBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Blog.LOGD(log= "onCreate ${this::class.java.name} >> savedInstanceState ${savedInstanceState}")
binding = IntroBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.menuWeb.let {
it.setOnLongClickListener {
onTouch(TouchArea.Center)
return@setOnLongClickListener false
}
mBaseWebContentsViewer = BaseWebContentsViewer(it,this)
}
paged_layer = binding.pagedLayer
textview_title = binding.textviewTitle
binding.btnList.setOnClickListener { v ->
mBaseWebContentsViewer?.webview?.url?.let {
Uri.parse(it).path?.let {
HistoryManager.getBookInfos(it, {
it?.let {
it.pages.sortBy { it.pathUrl }
showList(it)
}
})
}
}
}
binding.hiddenWeb?.let { v->
contentsSaver = v
contentsSaver?.webViewClient = saveClient
try {
contentsSaver?.removeJavascriptInterface("MyJavaScriptInterface")
} catch (e:Exception) {e.printStackTrace()}
contentsSaver?.addJavascriptInterface(SaveHelper(),"MyJavaScriptInterface")
contentsSaver?.settings?.textZoom = 100
contentsSaver?.settings?.javaScriptEnabled = true
contentsSaver?.settings?.javaScriptCanOpenWindowsAutomatically = false
contentsSaver?.settings?.loadWithOverviewMode = true
contentsSaver?.settings?.setPluginState(WebSettings.PluginState.ON)
contentsSaver?.settings?.domStorageEnabled = true
contentsSaver?.clearCache(true);
contentsSaver?.clearHistory();
contentsSaver?.clearSslPreferences();
}
// findViewById<View>(R.id.btn_rotate).setOnClickListener { v->
// switcvhOrient()
// }
binding.btnSetting.setOnClickListener { v->
startActivity(Intent(this@Intro, Settings::class.java))
}
binding.btnHistory.setOnClickListener { v->
var realm = openRealm()
realm.query<HistoryItem>().find().let {
showHistory(realm.copyFromRealm(it))
}
}
binding.btnHome.setOnClickListener { v->
paged_layer.visibility = GONE
mBaseWebContentsViewer.loadContents(NewtokiOne)
}
loadLastInfo()
}
fun loadLastInfo(){
val realm = openRealm()
try { lastInfo = realm.query<LastInfo>().find().last()?.copyFromRealm()
try {
if (lastInfo != null) {
HistoryManager.getBookPageInfo(Uri.parse(lastInfo!!.pageUrl!!).path!!) {
it?.let {
currentBooinfo = it
paged_layer.visibility = VISIBLE
if(it?.pathUrl?.length ?: 0 > 0) {
HistoryManager.save(historyItem = HistoryItem().putHistory(it,mBaseWebContentsViewer.webview.url!!))
Blog.LOGE("HistoryManager.getNextPage(${it?.pathUrl})")
if (lastInfo?.pageUrl?.length ?: 0 > 0 && lastInfo?.pageUrl!!.startsWith("http")) {
Blog.LOGE("HistoryManager.getNextPage(${lastInfo?.pageUrl})")
mBaseWebContentsViewer.webview.loadUrl(lastInfo!!.pageUrl!!.replace(Uri.parse(lastInfo!!.pageUrl)!!.path!!,it?.pathUrl!!))
} else {
Blog.LOGE("HistoryManager.getNextPage(${NewtokiOne.getLastedDoamin()})")
mBaseWebContentsViewer.webview.loadUrl(NewtokiOne.getLastedDoamin() + it?.pathUrl!!)
}
it?.pathUrl?.let {
HistoryManager.getBookInfos(it) {
saveItem(it)
}
}
}
HistoryManager.openRealm.query<ReaderConfig>()?.find()?.let {
if (it.size > 0) {
realm.copyFromRealm(it.first()).let {
applyReaderConfig()
}
}
}
paged_layer.text = it!!.contents!!
}
}
}
}catch (e1 : Exception){
}} catch (e : Exception) { }
}
fun reloadLastInfo() {
val configuration: Configuration = getResources().getConfiguration()
if(lastInfo != null && lastInfo?.displayOrientation != configuration.orientation) {
// findViewById<View>(R.id.btn_rotate).performClick()
}
}
override fun onBookInfos(aInfos: BookPageInfos) {
Blog.LOGE("onBookInfos(aInfos: ${aInfos})")
runOnUiThread {
showList(aInfos)
}
}
override fun onBookInfos(jsonString: String) {
Blog.LOGE("onBookInfos" , "jsonString >> ${jsonString}")
val realm = openRealm()
var infos : BookPageInfos? = null
realm.writeBlocking {
try {
var infosj : BookPageInfosJ? = null
infosj = Gson().fromJson(jsonString, BookPageInfosJ::class.java)
HistoryManager.getBookInfos(infosj.bookPageUrl!!){
if (it != null) {
infos = copyToRealm(it!!, UpdatePolicy.ALL)
for (item in infosj.pages) {
if (infos!!.hasItem(item.getRealm()) == false) {
infos!!.pages.add(item.getRealm())
}
}
if (infos != null) {
infos = this.copyFromRealm(infos!!)
}
} else {
infos = infosj?.getR()
if (infos != null) {
infos = copyToRealm(infos!!, UpdatePolicy.ALL)
for (item in infosj.pages) {
infos?.pages?.add(item.getRealm())
}
}
if (infos != null) {
infos = this.copyFromRealm(infos!!)
}
}
}
} catch (e :Exception) {
e.printStackTrace()
} finally {
infos?.bookPageUrl?.let {
HistoryManager.getBookInfos(it){
it?.let {
Blog.LOGE(s(), "onBookInfos it >> ${it}")
runOnUiThread {
showList(it)
}
}
}
}
}
}
}
private fun s() = "onBookInfos"
fun reloadTo(lastInfo: LastInfo?) {
findViewById<WebView>(R.id.menu_web)?.postDelayed({
if (lastInfo != null) {
mBaseWebContentsViewer.loadLastInfo(lastInfo!!)
} else {
mBaseWebContentsViewer.loadContents(NewtokiOne)
}
},200L)
}
override fun onStart() {
super.onStart()
proceedLastPage()
}
override fun onResume() {
super.onResume()
}
fun proceedLastPage() {
var realm = HistoryManager.openRealm
realm.query<ReaderConfig>()?.find()?.let {
if (it.size > 0) {
realm.copyFromRealm(it.first())?.let {
var msg = handle.obtainMessage()
msg.what = 0
msg.obj = it
handle.sendMessageDelayed(msg, 200)
}
}
}
reloadLastInfo()
reloadTo(lastInfo)
}
fun switcvhOrient(){
// val configuration: Configuration = getResources().getConfiguration()
// setRequestedOrientation(
// if(configuration.orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE }
// else {ActivityInfo.SCREEN_ORIENTATION_PORTRAIT}
// )
}
fun showHistory(infos: List<HistoryItem>) {
val builderSingle: AlertDialog.Builder = AlertDialog.Builder(this@Intro)
builderSingle.setTitle("${currentTitle} : ${currentChapter} -> Select One ")
val arrayAdapter =
ArrayAdapter<String>(this@Intro, android.R.layout.select_dialog_singlechoice)
for (item in infos) {
arrayAdapter.addAll(item.title)
}
builderSingle.setNegativeButton("cancel",
DialogInterface.OnClickListener { dialog, which -> dialog.dismiss() })
builderSingle.setAdapter(arrayAdapter,
DialogInterface.OnClickListener { dialog, which ->
val strName = arrayAdapter.getItem(which)
val item = infos.get(which)
val builderInner: AlertDialog.Builder = AlertDialog.Builder(this@Intro)
builderInner.setMessage(strName)
builderInner.setTitle("${infos.get(which).title}로 이동 고고!?")
builderInner.setPositiveButton("Ok",
DialogInterface.OnClickListener {
dialog, which ->
contentsLoad(item.pageUrl)
dialog.dismiss()
})
builderInner.setNeutralButton("삭제",
DialogInterface.OnClickListener {
dialog, which ->
var realm = openRealm()
realm?.writeBlocking {
this.query<HistoryItem>().query("title == '${item.title}'").find()?.last()?.let{
this.delete(it)
}
}
dialog.dismiss()
})
builderInner.setNegativeButton("취소",
DialogInterface.OnClickListener {
dialog, which ->
dialog.dismiss()
})
builderInner.show()
})
var ddddd= builderSingle.create()
ddddd.setOnShowListener { d->
(d as? AlertDialog)?.let{
it.listView?.setSelection(currentChapter)
}
}
ddddd.show()
}
fun showList(infos: BookPageInfos) {
Blog.LOGE("showList infos >>>>${infos}")
if (infos != null && infos.pages.size ?: 0 > 0) {
var items : ArrayList<BookPageInfo> = arrayListOf()
for (item in infos.pages) {
items.add(item)
}
items.sortBy { it.chapterID }
DefaultList.showDefaultList(
this@Intro,
"현제는 ${currentTitle} - ${currentChapter} -> 다른화를 골라",
items,
currentChapter,
{ position ->
return@showDefaultList items?.get(position)?.chapterTitle ?: ""
},
{ position ->
items?.get(position)?.let { moveTo(it) }
}, { state ->
if (state < 0 ) {
saveItem(infos)
}
})
}
}
val String.cleanTextContent: String
get() {
// strips off all non-ASCII characters
var text = this
text = text.replace("[^\\x00-\\x7F]".toRegex(), "")
// erases all the ASCII control characters
text = text.replace("[\\p{Cntrl}&&[^\r\n\t]]".toRegex(), "")
// removes non-printable characters from Unicode
text = text.replace("\\p{C}".toRegex(), "")
return text.trim()
}
var saveClient = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
}
override fun onPageFinished(webView: WebView?, url: String?) {
super.onPageFinished(webView, url)
// val delayed = 3500L + Math.abs(Random.nextLong().rem(9999L))
finishedUrl = url ?: ""
webView?.postDelayed({
webView?.evaluateJavascript(
"function getAll() {\n" +
" MyJavaScriptInterface.sendValueFromHtml(document.getElementsByTagName('html')[0].innerHTML)" +
" };getAll()"
) { result ->
(result as? String)?.let {
}
}
}, delayed)
}
}
fun showToast(origin: String) {
runOnUiThread {
val toast = Toast(this)
toast.duration = Toast.LENGTH_SHORT
val biggerText = SpannableStringBuilder(origin)
biggerText.setSpan(RelativeSizeSpan(1.6f), 0, origin.length, 0)
val view: View = inflate(this, com.mime.dualscreenview.R.layout.simple_toast,null)
view.findViewById<TextView>(com.mime.dualscreenview.R.id.text).text = biggerText
toast.setView(view)
toast.show()
// Toast.makeText(
// baseContext,
// biggerText,
// Toast.LENGTH_SHORT
// ).show()
}
}
var delayed = 3500L + Math.abs(Random.nextLong().rem(9999L))
var finishedUrl : String? = null
inner class SaveHelper {
@JavascriptInterface
fun sendValueFromHtml(string: String) {
Jsoup.parse(string)?.let { html ->
val view_padding = html.getElementsByClass("view-padding")
if (view_padding.size > 0){
// Blog.LOGE("finishedUrl >>> ${finishedUrl} :::: ${html.title()}")
val contents = view_padding.get(0).children().html().replace("<p>"," ").replace("</p>","\n\n")
// Blog.LOGE("finishedUrl >>> ${finishedUrl} :::: view_padding.get(0)\n${contents}")
if (contents.length > 20) {
Uri.parse(finishedUrl).path?.let {
delayed = 3500L + Math.abs(Random.nextLong().rem(9999L))
HistoryManager.getBooPageInfoContentsSave(it, contents).apply {
HistoryManager.getBookPageInfo(it) { book ->
showToast("saved ${book?.getTitleItem()} \n:: lenght = ${contents.length} \n:: saveTarget = ${saveTarget.size}\n:: delayed >> ${delayed}")
}
}.apply {
HistoryManager.getBookInfos(it) { saveItem(it)}
}
}
}
} else {
}
}
}
}
var saveTarget : ArrayList<BookPageInfo> = arrayListOf()
private fun saveItem(infos: BookPageInfos?) {
Blog.LOGE("saveItem >>> infos?.pages ${infos?.pages?.size ?: 0}")
var savedCount = Math.abs(Random(System.currentTimeMillis()).nextLong().rem(9) + 6L)
Blog.LOGE("saveItem >>> targetCount = ${savedCount}")
infos?.pages?.reversed()?.forEach {
if ((it.contents?.length ?: 0) > 10) {
} else {
if (savedCount.toInt() > 0) {
saveTarget.add(it)
savedCount = savedCount - 1L
}
}
}
if (savedCount > 0) {
HistoryManager.openRealm.query<BookPageInfo>().find().forEach {
if ((it.contents?.length ?: 0) > 10) {
} else if(savedCount.toInt() > 0) {
saveTarget.add(HistoryManager.openRealm.copyFromRealm(it))
savedCount = savedCount - 1
}
}
}
Blog.LOGE("saveItem >>> saveTarget ${saveTarget.count()}")
try {
saveTarget.removeFirst().let {
Blog.LOGE("saveItem >>> ${it.pathUrl}")
runOnUiThread {
mBaseWebContentsViewer.webview.url?.let { currentUrl ->
currentUrl.replace(Uri.parse(currentUrl).path ?: "", it.pathUrl ?: "")
?.let { targetUrl ->
Blog.LOGE("targetUrl >>> ${targetUrl}")
contentsSaver?.loadUrl(targetUrl)
}
}
}
}
} catch ( e : Exception) {
e.printStackTrace()
}
}
private fun moveTo(item: BookPageInfo?) {
item?.pathUrl?.let { newPath ->
if (item.contents?.length ?: 0 > 10) {
paged_layer.text = item!!.contents!!
paged_layer.visibility = VISIBLE
}
mBaseWebContentsViewer?.webview?.url?.let { currentUrl ->
Uri.parse(currentUrl)?.path?.let {
currentUrl.replace(it, newPath)?.let {
mBaseWebContentsViewer?.webview?.loadUrl(it)
}
}
}
}
}
// fun showStyleList() {
// var mStylez = Stylez(this@Intro)
// mStylez.styleSelectInterface = object : StyleSelectInterface {
// override fun onSelectStyle(bgColor: String, textColor: String) {
// paged_layer?.setColorStyle(arrayOf(textColor,bgColor))
// }
// }
// mStylez.show()
// }
override fun onDestroy() {
super.onDestroy()
}
var onNextClickAction: GotoSomeWhere? = null
override fun showNextBtn(find : Boolean , onClickAction: GotoSomeWhere) {
onNextClickAction = onClickAction
findViewById<ImageFilterButton>(R.id.btn_right)?.let{
it.setOnClickListener {
actionNextEvent()
}
it.visibility= if(find) VISIBLE else GONE
}
}
fun moveToNext(pathUrl : String?) {
if (pathUrl != null && pathUrl.length > 6) {
HistoryManager.getNextPage(pathUrl!!) {
if(it != null && it!!.pathUrl?.length ?: 0 > 6) {contentsLoad(it.pathUrl!!)}
}
}
}
fun moveToPrev(pathUrl : String?) {
if (pathUrl != null && pathUrl.length > 6) {
HistoryManager.getPrevPage(pathUrl!!) {
if(it != null && it!!.pathUrl?.length ?: 0 > 6) {contentsLoad(it.pathUrl!!)}
}
}
}
fun contentsLoad(pathUrl : String) {
HistoryManager.getBookPageInfo(pathUrl) {
Blog.LOGE("contentsLoad :::: pathUrl >> ${pathUrl}")
it?.pathUrl?.let {
Blog.LOGE("contentsLoad :::: pathUrl >> ${it}")
HistoryManager.getBookInfos(it) {
Blog.LOGE("contentsLoad :::: getBookInfos >> ${it}")
saveItem(it)
}
}
if (it != null) currentBooinfo = it
if (it != null && (it?.contents?.length ?: 0) > 10) {
paged_layer.visibility = VISIBLE
if((it?.pathUrl?.length ?: 0) > 0) {
if (lastInfo?.pageUrl?.length ?: 0 > 0 && lastInfo?.pageUrl!!.startsWith("http")) {
mBaseWebContentsViewer.webview.loadUrl(lastInfo!!.pageUrl!!.replace(Uri.parse(lastInfo!!.pageUrl)!!.path!!,it?.pathUrl!!))
} else {
mBaseWebContentsViewer.webview.loadUrl(NewtokiOne.getLastedDoamin() + it?.pathUrl!!)
}
HistoryManager.save(historyItem = HistoryItem().putHistory(it,mBaseWebContentsViewer.webview.url!!))
}
applyReaderConfig()
paged_layer.text = it!!.contents!!
} else {
if(it?.pathUrl?.length ?: 0 > 0) {
if (lastInfo?.pageUrl?.length ?: 0 > 0 && lastInfo?.pageUrl!!.startsWith("http")) {
paged_layer.visibility = GONE
mBaseWebContentsViewer.webview.loadUrl(lastInfo!!.pageUrl!!.replace(Uri.parse(lastInfo!!.pageUrl)!!.path!!,it?.pathUrl!!))
} else {
paged_layer.visibility = GONE
mBaseWebContentsViewer.webview.loadUrl(NewtokiOne.getLastedDoamin() + it?.pathUrl!!)
}
HistoryManager.save(historyItem = HistoryItem().putHistory(it,mBaseWebContentsViewer.webview.url!!))
}
}
}
}
fun actionNextEvent(fast : Boolean = false) {
if (paged_layer != null && paged_layer!!.visibility == View.VISIBLE && paged_layer!!.size() > 0 && (paged_layer!!.current() < paged_layer!!.size() - 1) ) {
paged_layer!!.doNext(fast)
updateLastInfo(paged_layer!!)
} else {
moveToNext(currentBooinfo?.pathUrl ?: mBaseWebContentsViewer.webview.url?.toUri()?.path)
}
}
var onPrevClickAction: GotoSomeWhere? = null
override fun showPrevBtn(find : Boolean, onClickAction: GotoSomeWhere) {
onPrevClickAction = onClickAction
findViewById<ImageFilterButton>(R.id.btn_left)?.let{
it.setOnClickListener {
actionPrevEvent()
}
it.visibility= if(find) VISIBLE else GONE
}
}
fun applyReaderConfig() {
var realm = HistoryManager.openRealm
realm.query<ReaderConfig>()?.find()?.let {
if (it.size > 0) {
realm.copyFromRealm(it.first())?.let {
runOnUiThread {
var typeface = typesfacez.get(getIndex(typesfacez as PairArray<Any>,it.font ?: ""))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
paged_layer?.setTypeface(resources.getFont(typeface.second))
}
val color = colorz.get(it.style ?: 0)
paged_layer?.setColorStyle(color.second)
paged_layer.setTextSize(it.textSize?.toFloat()?: 14f)
paged_layer.setLineSpacing(it.lineSpace?.toFloat() ?: 1f)
paged_layer.setLetterSpacing(it.letterSpace?.toFloat() ?: 1f)
paged_layer.setPadding(
it.padding ?: 1,
it.padding ?: 1,
it.padding ?: 1,
it.padding ?: 1)
paged_layer.invalidate()
}
}
}
}
}
fun actionPrevEvent(fast : Boolean = false) {
if (paged_layer != null && paged_layer!!.visibility == View.VISIBLE && paged_layer!!.size() > 0 && paged_layer!!.current() > 0 ) {
paged_layer!!.doPrev(fast)
updateLastInfo(paged_layer!!)
} else {
moveToPrev(currentBooinfo?.pathUrl ?: mBaseWebContentsViewer.webview.url?.toUri()?.path)
}
}
override fun onBackPressed() {
// super.onBackPressed()
var layer = findViewById<PagedTextLayout>(R.id.paged_layer)
// if (!didBackPress) {
// firstBackPress()
// return
// }
if (layer != null && layer.visibility == View.VISIBLE) {
didBackPress = false
layer.visibility = GONE
onTouch(TouchArea.Center)
return
}
if (mBaseWebContentsViewer.webview.canGoBack()) {
mBaseWebContentsViewer.webview.goBack()
return
}
if (!didBackPress) {
firstBackPress()
return
} else {
finishAffinity()
didBackPress = false
// super.onBackPressed()
}
}
override fun showAlert(alert: String) {
Log.i(TAG,"showAlert >> " + alert)
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onLoadedContents(aContents: String) {
paged_layer.apply {
paged_layer.post {
if (aContents != null && aContents.length > 10) {
var contents = aContents.replace("\\\"", "\"")
contents = (contents.replace("\\n", System.getProperty("line.separator")))
contents = (contents.replace("\\n", System.getProperty("line.separator")))
mPagedTextViewInterface = this@Intro
if (lastInfo != null && mBaseWebContentsViewer.webview.url?.endsWith(lastInfo!!.pageUrl) ?: false) {
binding.progress.visibility = VISIBLE
paged_layer.postDelayed({
binding.progress.visibility = GONE
}, 1000)
}
applyReaderConfig()
runOnUiThread {
text = contents
visibility = VISIBLE
}
forceUpdateUI()
mBaseWebContentsViewer.webview.url?.let {
Uri.parse(it)?.let {
it.path?.let {
HistoryManager.getBookPageInfo(it) {
currentBooinfo = it
currentChapter = it?.chapterNum ?: 0
currentPage = it?.chapterNum ?: 0
HistoryManager.save(
historyItem = HistoryItem().putHistory(
it,
mBaseWebContentsViewer.webview.url!!
)
)
}
}
HistoryManager.getBooPageInfoContentsSave(it!!.path!!, contents)
}
}
}
}
}
Log.i(TAG,"onLoadedContents >> " + aContents)
}
var currentTitle : String = ""
var currentChapter : Int = 0
override fun onFindTitle(contents: String) {
textview_title.text = contents
textview_title.setOnClickListener {
val builder = AlertDialog.Builder(this)
builder.setTitle("Title")
val input = EditText(this)
input.setText(mBaseWebContentsViewer?.webview?.url ?: "")
input.inputType = InputType.TYPE_CLASS_TEXT
builder.setView(input)
builder.setPositiveButton(
"OK"
) { dialog, which ->
var m_Text = input.text.toString()
mBaseWebContentsViewer?.webview?.loadUrl(m_Text.trim())
}
builder.setNegativeButton(
"Cancel"
) { dialog, which -> dialog.cancel() }
builder.show()
}
var testRegex = """[^0-9]""".toRegex();
Blog.LOGI(TAG,"onFindTitle >> " + contents + " ::: ${testRegex.replace(contents,"")}")
if(contents.contains("-")) {
currentTitle = contents.split("-")[0]
try {
currentChapter = testRegex.replace(contents.split("-")[1],"").toInt()
} catch (e : Exception) {
currentChapter = 0
}
} else if(testRegex.replace(contents,"").length > 0){
currentChapter = testRegex.replace(contents,"").toInt()
currentTitle = contents.split(testRegex.replace(contents,""))[0]
} else {
val dateFormat = "yyyyMMdd-HH"
val date = Date(currentTimeMillis())
val simpleDateFormat = SimpleDateFormat(dateFormat)
currentTitle = simpleDateFormat.format(date)
}
}
override fun onStartLoad() {
findViewById<ProgressBar>(R.id.progress).visibility = VISIBLE
}
override fun completePageLoad(lastInfo: LastInfo) {
val configuration: Configuration = getResources().getConfiguration()
if(this.lastInfo == null || !(this.lastInfo?.pageUrl.equals(lastInfo?.pageUrl)) || this.lastInfo?.displayOrientation != configuration?.orientation) {
lastInfo.displayOrientation = configuration?.orientation ?: ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
saveLastInfo(lastInfo)
}
binding.progress.visibility = GONE
}
fun saveLastInfo(lastInfo: LastInfo) {
val realm = openRealm()
if((realm.query<LastInfo>()?.count()?.find() ?: 0) > 0) {
realm.writeBlocking {
this.query<LastInfo>()?.find()?.last()?.let{
it.pageUrl = lastInfo.pageUrl
it.title = currentTitle
it.chapter = currentChapter
it.pageIndex = lastInfo.pageIndex
it.contentsName = lastInfo.contentsName
it.displayOrientation = lastInfo.displayOrientation
this@Intro.lastInfo = copyFromRealm(it)
}
}
} else {
realm.writeBlocking {
copyToRealm(lastInfo)
}
}
Blog.LOGD(log ="Successfully opened realm: ${realm.configuration.name}")
}
fun updateLastInfo(pagedTextLayout: PagedTextLayout) {
val configuration: Configuration = getResources().getConfiguration()
val realm = openRealm()
realm.writeBlocking {
this.query<LastInfo>()?.find()?.last()?.let{
it.displayOrientation = configuration.orientation
it.title = currentTitle
// it.pageUrl = currentBooinfo?.pathUrl ?: mBaseWebContentsViewer.webview.url?.toUri()?.path ?: ""
it.chapter = currentChapter
it.pageIndex = pagedTextLayout.current()
this@Intro.lastInfo = copyFromRealm(it)
}
if (currentTitle.length > 0 && currentChapter > 0) {
this@Intro.lastInfo?.makeHistoryItem()?.let{
copyToRealm(it, UpdatePolicy.ALL)
}
}
}
Blog.LOGD(log ="Successfully opened realm: ${realm.configuration.name}")
}
override fun onKeyClick(keyCode: Int): Boolean {
when(keyCode) {
KeyEvent.KEYCODE_VOLUME_DOWN ->{actionNextEvent()}
KeyEvent.KEYCODE_VOLUME_UP ->{actionPrevEvent()}
KeyEvent.KEYCODE_VOLUME_MUTE -> {actionNextEvent()}
}
return super.onKeyClick(keyCode)
}
override fun onTouch(touchArea: TouchArea) {
Blog.LOGD(log="onTouch ${touchArea}")
when (touchArea) {
TouchArea.Center-> {
findViewById<View>(R.id.btn_right).visibility = VISIBLE
findViewById<View>(R.id.btn_left).visibility = VISIBLE
findViewById<View>(R.id.btn_setting).visibility = VISIBLE
textview_title.visibility = VISIBLE
findViewById<View>(R.id.btn_home).visibility = VISIBLE
findViewById<View>(R.id.btn_list).visibility = VISIBLE
findViewById<View>(R.id.btn_history).visibility = VISIBLE
// findViewById<View>(R.id.btn_rotate).visibility = VISIBLE
}
TouchArea.Right -> {
actionNextEvent()
}
TouchArea.Left-> {
actionPrevEvent()
}
TouchArea.DoubleRight -> {
actionNextEvent(true)
}
TouchArea.DoubleLeft -> {
actionPrevEvent(true)
}
else -> {
}
}
}
override fun onLongClick() {
Blog.LOGD(log="onLongClick")
}
override fun onSwipeLeft(count : Int) {
Blog.LOGD(log="onSwipeLeft ${count}")
actionNextEvent(count > 1)
}
override fun onSwipeRight(count : Int) {
Blog.LOGD(log="onSwipeRight ${count}")
actionPrevEvent(count > 1)
}
override fun onSwipeUp(touchCount: Int) {
}
override fun onSwipeDown(touchCount: Int) {
if (touchCount == 2) {
if (paged_layer?.visibility == VISIBLE) {
paged_layer?.visibility = GONE
findViewById<View>(R.id.btn_right).visibility = VISIBLE
findViewById<View>(R.id.btn_left).visibility = VISIBLE
findViewById<View>(R.id.btn_setting).visibility = VISIBLE
textview_title.visibility = VISIBLE
findViewById<View>(R.id.btn_home).visibility = VISIBLE
findViewById<View>(R.id.btn_list).visibility = VISIBLE
findViewById<View>(R.id.btn_history).visibility = VISIBLE
// findViewById<View>(R.id.btn_rotate).visibility = VISIBLE
}
}
}
override fun onTimeoverTouch() {
Blog.LOGD(log="onTimeoverTouch")
findViewById<View>(R.id.btn_right).visibility = GONE
findViewById<View>(R.id.btn_left).visibility = GONE
findViewById<View>(R.id.btn_setting).visibility = GONE
textview_title.visibility = GONE
findViewById<View>(R.id.btn_home).visibility = GONE
findViewById<View>(R.id.btn_list).visibility = GONE
findViewById<View>(R.id.btn_history).visibility = GONE
// findViewById<View>(R.id.btn_rotate).visibility = GONE
}
companion object {
private const val TAG = "DualScreenStatus"
}
}

View File

@ -1,8 +0,0 @@
package com.mime.dualscreenview.activity
import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
class Main : Base() {
}

View File

@ -1,123 +0,0 @@
package com.mime.dualscreenview.activity
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import androidx.annotation.RequiresApi
import androidx.databinding.DataBindingUtil
import com.mime.dualscreenview.R
import com.mime.dualscreenview.common.PairArray
import com.mime.dualscreenview.common.colorz
import com.mime.dualscreenview.common.getIndex
import com.mime.dualscreenview.common.typesfacez
import com.mime.dualscreenview.data.HistoryManager
import com.mime.dualscreenview.data.model.ReaderConfig
import com.mime.dualscreenview.databinding.SettingsBinding
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query
class Settings : Base() {
lateinit var binding : SettingsBinding
var readerConfig : ReaderConfig? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.settings)
// setContentView(R.layout.settings)
var realm = HistoryManager.openRealm
realm.writeBlocking {
this.query<ReaderConfig>()?.find()?.let {
if (it.size > 0) {
readerConfig = copyFromRealm(it.first())
} else {
readerConfig = ReaderConfig()
}
}
}
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onResume() {
super.onResume()
binding.textSize.displayFormat = "글자 크기 : %d"
binding.textSize.value = readerConfig?.textSize ?: 14
binding.textSize.mValueChange = {
binding.preview.textSize = it.toFloat() ;
if (readerConfig?.textSize != it) {
readerConfig?.textSize = it
configSave()
}
}
binding.pagePadding.displayFormat = "페이지 여백 : %d"
binding.pagePadding.value = readerConfig?.padding ?: 5
binding.pagePadding.mValueChange = {
binding.preview.setPadding(it,it,it,it) ;
if (readerConfig?.padding != it) {
readerConfig?.padding = it
configSave()
}
}
binding.letterSpace.displayFormat = "자간 : %d"
binding.letterSpace.value = readerConfig?.letterSpace ?: 1
binding.letterSpace.mValueChange = {
binding.preview.letterSpacing = it.times(0.01).toFloat() ;
if (readerConfig?.letterSpace != it) {
readerConfig?.letterSpace = it
configSave()
}
}
binding.lineSpace.displayFormat = "행간 : %d"
binding.lineSpace.value = readerConfig?.lineSpace ?: 1
binding.lineSpace.mValueChange = {
binding.preview.setLineSpacing(1f, 1f.plus(it.times(0.01f))) ;
if (readerConfig?.lineSpace != it) {
readerConfig?.lineSpace = it
configSave()
}
}
binding.pageTypesface.displayFormat = "폰트 : %s"
binding.pageTypesface.titleArray = typesfacez.map { it.first }.toTypedArray()
binding.pageTypesface.value = getIndex(typesfacez as PairArray<Any>,readerConfig?.font ?: "")
binding.pageTypesface.mValueChange = {
val pair = typesfacez.get(it)
binding.preview.setTypeface(resources.getFont(pair.second))
if (readerConfig?.font != pair.first) {
readerConfig?.font = pair.first ?: ""
configSave()
}
}
binding.pageStyle.displayFormat = "스타일 : %s"
binding.pageStyle.titleArray = colorz.map { it.first }.toTypedArray()
binding.pageStyle.value = readerConfig?.style ?: 0
binding.pageStyle.mValueChange = {
val pair = colorz.get(it)
binding.preview.setBackgroundColor(Color.parseColor(pair.second.last()))
binding.preview.setTextColor(Color.parseColor(pair.second.first()))
if (readerConfig?.style != it) {
readerConfig?.style = it ?: 0
configSave()
}
}
}
fun configSave() {
var realm = HistoryManager.openRealm
realm.writeBlocking {
copyToRealm(readerConfig!!, UpdatePolicy.ALL)
}
}
}

View File

@ -1,54 +0,0 @@
package com.mime.dualscreenview.common
import android.util.Log
import com.mime.dualscreenview.BuildConfig
import java.lang.Exception
object Blog {
val DEFAULT_TAG = "MyEBook_TAG"
enum class BLogType {
D,I,E
}
fun LOGD(tag : String = DEFAULT_TAG, log: String){
LOG(BLogType.D,tag,log)
}
fun LOGI(tag : String = DEFAULT_TAG, log: String){
LOG(BLogType.I,tag,log)
}
fun LOGE(tag : String = DEFAULT_TAG, log: Throwable){
LOG(BLogType.E,tag,log.toString())
}
fun LOGE(tag : String = DEFAULT_TAG, log: Exception){
LOG(BLogType.E,tag,log.toString())
}
fun LOGE(tag : String = DEFAULT_TAG, log: String){
LOG(BLogType.E,tag,log)
}
fun LOGE(log: String){
LOG(BLogType.E,DEFAULT_TAG,log)
}
private fun LOG(type : BLogType, tag : String, log : String) {
if (BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.contains("debug")) {
when(type) {
BLogType.D -> {
Log.d(tag,log)
}
BLogType.I -> {
Log.i(tag,log)
}
BLogType.E -> {
Log.e(tag,log)
}
else -> {}
}
}
}
}

View File

@ -1,84 +0,0 @@
package com.mime.dualscreenview.common
import com.mime.dualscreenview.R
typealias PairArray<T> = Array<Pair<String,T>>
val colorz : PairArray<Array<String>> = arrayOf<Pair<String,Array<String>>>(
Pair("color set 01",arrayOf<String>("#E1F5FE", "#263238")),
Pair("color set 02",arrayOf<String>("#F0F4C3", "#37474F")),
Pair("color set 03",arrayOf<String>("#ECEFF1", "#455A64")),
Pair("color set 04",arrayOf<String>("#E0F7FA", "#263238")),
Pair("color set 05",arrayOf<String>("#F5F5F5", "#263238")),
Pair("color set 06",arrayOf<String>("#ECEFF1", "#263238")),
Pair("color set 07",arrayOf<String>("#F8BBD0", "#263238")),
Pair("color set 08",arrayOf<String>("#E6EE9C", "#455A64")),
Pair("color set 09",arrayOf<String>("#CFD8DC", "#455A64")),
Pair("color set 10",arrayOf<String>("#FFF59D", "#37474F")),
Pair("color set 21",arrayOf<String>("#263238","#E1F5FE")),
Pair("color set 22",arrayOf<String>("#37474F","#F0F4C3")),
Pair("color set 23",arrayOf<String>("#455A64","#ECEFF1")),
Pair("color set 24",arrayOf<String>("#263238","#E0F7FA")),
Pair("color set 25",arrayOf<String>("#263238","#F5F5F5")),
Pair("color set 26",arrayOf<String>("#263238","#ECEFF1")),
Pair("color set 27",arrayOf<String>("#263238","#F8BBD0")),
Pair("color set 28",arrayOf<String>("#455A64","#E6EE9C")),
Pair("color set 29",arrayOf<String>("#455A64","#CFD8DC")),
Pair("color set 30",arrayOf<String>("#37474F","#FFF59D")),
Pair("color set 31",arrayOf<String>("#FFFFFF","#1C1B1B")),
Pair("color set 32",arrayOf<String>("#272727","#FFFFFF")),
Pair("color set 33",arrayOf<String>("#1C1B1B","#FFFFFF")),
Pair("color set 34",arrayOf<String>("#FFFFFF","#272727"))
)
val typesfacez : PairArray<Int> = arrayOf<Pair<String,Int>>(
Pair("정선 아리랑 혼", R.font.jsarirang_hon),
Pair("정선 아리랑 뿌리", R.font.jsarirang_ppuri),
Pair("정선 동강 레귤러", R.font.jsdongkang_regular),
Pair("손기정체", R.font.kcc_sonkeechung),
Pair("교보 손글씨", R.font.kyobo_handwriting_2021sjy),
Pair("태백 은하수", R.font.taebaek_milkyway),
Pair("taebaek_milkyway",R.font.taebaek_milkyway),
Pair("kccahnjunggeun",R.font.kccahnjunggeun),
Pair("kotra_songeulssi",R.font.kotra_songeulssi),
Pair("kotra_bold",R.font.kotra_bold),
Pair("cafe24oneprettynight",R.font.cafe24oneprettynight),
Pair("nnsgc_wsjidyp",R.font.nnsgc_wsjidyp),
Pair("nnsgc_yjc",R.font.nnsgc_yjc),
Pair("nnsgc_brhp",R.font.nnsgc_brhp),
Pair("nnsgc_md",R.font.nnsgc_md),
Pair("nnsgc_gd_an_gd",R.font.nnsgc_gd_an_gd),
Pair("dovemayo",R.font.dovemayo),
Pair("gabia_solmee",R.font.gabia_solmee),
Pair("ylee_mortal_heart_immortal_memory",R.font.ylee_mortal_heart_immortal_memory),
Pair("kcc_kimhoon",R.font.kcc_kimhoon),
Pair("taefont_tsthlml",R.font.taefont_tsthlml),
Pair("ssshinb7",R.font.ssshinb7),
Pair("godomaum",R.font.godomaum),
Pair("tvn_jguiyg_medium",R.font.tvn_jguiyg_medium),
Pair("tvn_jguiyg_light",R.font.tvn_jguiyg_light),
Pair("on_jsuhr",R.font.on_jsuhr),
Pair("on_jsuhl",R.font.on_jsuhl),
Pair("on_ychyuhr",R.font.on_ychyuhr),
Pair("on_ychyuhl",R.font.on_ychyuhl),
Pair("on_treeususimgul_r",R.font.on_treeususimgul_r),
Pair("on_treeususimgul",R.font.on_treeususimgul),
Pair("on_wibsr",R.font.on_wibsr),
Pair("on_wisbl",R.font.on_wisbl),
Pair("on_sbsjl",R.font.on_sbsjl),
Pair("on_sbsjr",R.font.on_sbsjr),
Pair("wandohoper",R.font.wandohoper),
Pair("ebs_r",R.font.ebs_r),
)
@JvmName("getIndexAny")
fun PairArray<Any>.getIndex(key : String) = getIndex(this, key)
fun getIndex(collection : PairArray<Any>, key : String) : Int {
var index = 0
var returns = 0
for (item in collection) {
if(item.first.equals(key)) {
returns = index
}
index = index.inc()
}
return returns
}

View File

@ -1,30 +0,0 @@
package com.mime.dualscreenview.common
import android.content.Context
import android.content.SharedPreferences
import com.mime.dualscreenview.webcontents.contentsinfo.Booktoki
import com.mime.dualscreenview.webcontents.contentsinfo.NewtokiOne
object PrefManager {
private val mainName = "Main_Pref_"
private val domainKey = "Last_Domain_"
private lateinit var main : SharedPreferences
fun init(context: Context) {
main = context.getSharedPreferences(mainName,Context.MODE_PRIVATE)
}
fun save(key : String, value : String?) {
main.edit().putString(key,value).apply()
}
fun load(key : String) : String? {
return main.getString(key, "")
}
fun getLastDomain() : String {
return main.getString(domainKey, NewtokiOne.getLastedDoamin()) ?: NewtokiOne.getLastedDoamin()
}
fun putLastDomain(domain : String) {
Blog.LOGE("domain >>> ${domain}")
main.edit().putString(domainKey,domain).apply()
}
}

View File

@ -1,168 +0,0 @@
package com.mime.dualscreenview.data
import com.mime.dualscreenview.common.Blog
import com.mime.dualscreenview.data.model.BookPageInfo
import com.mime.dualscreenview.data.model.BookPageInfos
import com.mime.dualscreenview.data.model.HistoryItem
import com.mime.dualscreenview.data.model.LastInfo
import com.mime.dualscreenview.data.model.ReaderConfig
import io.realm.kotlin.Realm
import io.realm.kotlin.RealmConfiguration
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.types.BaseRealmObject
import io.realm.kotlin.types.TypedRealmObject
import kotlin.reflect.KClass
object HistoryManager {
val clazz : Set<KClass<out BaseRealmObject>> = setOf(LastInfo::class, HistoryItem::class, ReaderConfig::class, BookPageInfos::class, BookPageInfo::class)
val schemaVersion : Long = 5
val openRealm : Realm = Realm.open(RealmConfiguration.Builder(clazz as Set<KClass<out TypedRealmObject>>)
.schemaVersion(schemaVersion)
.deleteRealmIfMigrationNeeded()
.build())
fun save(lastInfo: LastInfo) {
openRealm.apply{
this.writeBlocking {
copyToRealm(lastInfo, UpdatePolicy.ALL)
}
}
}
fun save(historyItem: HistoryItem) {
openRealm.apply{
this.writeBlocking {
copyToRealm(historyItem, UpdatePolicy.ALL)
}
}
}
fun requestLastInfo(callback : (LastInfo)->Unit) {
openRealm.apply{
}
}
fun save(config : ReaderConfig) {
openRealm.apply{
this.writeBlocking {
copyToRealm(config,UpdatePolicy.ALL)
}
}
}
fun getBookInfos(aUrl : String, callback : (BookPageInfos?)->Unit) {
var url : String = aUrl
openRealm.apply{
if (url.startsWith("//")) {
while (url.startsWith("//")) {
url = url.replace("//","/").trim()
}
}
Blog.LOGE("aUrl >>> ${aUrl}")
Blog.LOGE("aUrl >>> ${aUrl}")
var bookPageInfo = this.query(BookPageInfo::class).query("pathUrl == $0 || bookPageUrl == $0","${url}").find()
if (bookPageInfo != null && bookPageInfo.count() > 0) {
Blog.LOGE("get ${bookPageInfo}" )
var pgs = this.query(BookPageInfos::class,"bookPageUrl == $0", bookPageInfo.first().bookPageUrl).find()
if (pgs.size > 0) {
pgs.first().let {
Blog.LOGE("get ${it} , ${it?.pages}")
callback.invoke(this.copyFromRealm(it))
}
}
} else {
callback.invoke(null)
}
}
}
fun getBookPageInfo(aUrl : String, callback : (BookPageInfo?)->Unit) {
var url : String = aUrl
openRealm.apply{
if (url.startsWith("//")) {
while (url.startsWith("//")) {
url = url.replace("//","/").trim()
}
}
var result = this.query(BookPageInfo::class).query("pathUrl == $0","${url}").find()
if (result.size > 0) {
var bookPageInfo = result?.first()
if (bookPageInfo != null) {
callback.invoke(bookPageInfo)
}
}
}
}
fun getBooPageInfoContentsSave(aUrl : String, contents : String) {
var url : String = aUrl
openRealm.writeBlocking {
Blog.LOGE("getBooPageInfoContentsSave ${url}")
val result = query(BookPageInfo::class).query("pathUrl == $0", "${url}").find()
if (result.size > 0) {
result.first().contents = contents
copyToRealm(result.first(), UpdatePolicy.ALL)
}
}
}
fun getNextPage(aUrl : String ,callback : (BookPageInfo?)->Unit) {
var url : String = aUrl
openRealm.apply{
if (url.startsWith("//")) {
while (url.startsWith("//")) {
url = url.replace("//","/").trim()
}
}
var bookPageInfo =
this.query(BookPageInfo::class).query("pathUrl == $0", url).find()
if (bookPageInfo.size > 0) {
Blog.LOGE("getNextPage 2 => chapterNum : ${bookPageInfo.first().chapterNum} , bookPageInfo.bookPageUrl : ${bookPageInfo.first().bookPageUrl}" )
var results = this.query(BookPageInfo::class).query("chapterNum == $0",bookPageInfo.first().chapterNum + 1).query("bookPageUrl == $0","${bookPageInfo.first().bookPageUrl}").find()
if(results.size > 0) {
results.first().let {
Blog.LOGE("getNextPage 2 nextBook pathUrl : ${it.pathUrl}" )
callback.invoke(it)
}
} else {callback.invoke(null)}
} else {callback.invoke(null)}
}
}
fun getPrevPage(aUrl : String ,callback : (BookPageInfo?)->Unit) {
var url : String = aUrl
openRealm.apply{
Blog.LOGE("getPrevPage ${url}" )
if (url.startsWith("//")) {
while (url.startsWith("//")) {
url = url.replace("//","/").trim()
}
}
Blog.LOGE("getPrevPage ${url}" )
var bookPageInfo =
this.query(BookPageInfo::class).query("pathUrl == $0", url).find()
Blog.LOGE("getPrevPage ${bookPageInfo}" )
if (bookPageInfo.size > 0) {
Blog.LOGE("getPrevPage 2 ${bookPageInfo?.first()?.chapterNum}" )
Blog.LOGE("getPrevPage 2 ${bookPageInfo?.first()?.bookPageUrl}" )
var results = this.query(BookPageInfo::class).query("chapterNum == $0",bookPageInfo.first().chapterNum - 1).query("bookPageUrl == $0","${bookPageInfo.first().bookPageUrl}").find()
if(results.size > 0) {
results.first()?.let {
callback.invoke(it)
}
} else {
callback.invoke(null)
}
} else {
callback.invoke(null)
}
}
}
}

View File

@ -1,121 +0,0 @@
package com.mime.dualscreenview.data.model
import io.realm.kotlin.ext.realmListOf
import io.realm.kotlin.types.RealmList
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.Ignore
import io.realm.kotlin.types.annotations.PrimaryKey
class BookPageInfosJ {
var bookTitle : String = ""
var bookPageUrl : String = ""
var pages : ArrayList<BookPageInfoJ> = arrayListOf<BookPageInfoJ>()
fun getTitleArray() : ArrayList<String> {
var arrayList = ArrayList<String>()
pages.forEach { arrayList.add(it.bookTitle ?: "") }
return arrayList
}
fun getR() : BookPageInfos{
var r = BookPageInfos()
r.bookTitle = this.bookTitle
r.bookPageUrl = this.bookPageUrl
return r
}
}
class BookPageInfoJ {
var chapterID : Int = 0
var contents : String? = ""
var bookPageUrl : String? = ""
var chapterTitle : String? = ""
var bookTitle : String? = ""
var chapterNum : Int = 0
var lastPage : Int? = 0
var pathUrl : String? = ""
fun getRealm() : BookPageInfo {
var r = BookPageInfo()
r.chapterID = this.chapterID
r.contents = this.contents
r.bookPageUrl = this.bookPageUrl ?: ""
r.chapterTitle = this.chapterTitle
r.bookTitle = this.bookTitle ?: ""
r.chapterNum = this.chapterNum
r.lastPage = this.lastPage
r.pathUrl = this.pathUrl?.replace("'","")
return r
}
}
class BookPageInfos : RealmObject {
var bookTitle : String = ""
@PrimaryKey
var bookPageUrl : String? = ""
var pages : RealmList<BookPageInfo> = realmListOf()
fun getTitleArray() : ArrayList<String> {
var arrayList = ArrayList<String>()
pages.forEach {
arrayList.add(it.getTitleItem())}
return arrayList
}
fun sort() {
val comparator : Comparator<BookPageInfo> = compareBy { it.chapterID }
pages.sortWith(comparator)
}
fun hasItem(item: BookPageInfo) : Boolean {
var hasItem = false
for (c in pages) {
if (!hasItem) {
hasItem = c.pathUrl.equals(item.pathUrl)
}
}
return hasItem
}
}
class BookPageInfo : RealmObject {
var chapterID : Int = 0
var contents : String? = ""
var bookPageUrl : String? = ""
var chapterTitle : String? = ""
var bookTitle : String? = ""
var chapterNum : Int = 0
var lastPage : Int? = 0
@PrimaryKey
var pathUrl : String? = ""
fun getTitleItem() : String {
var result = StringBuilder()
result.append(if ((contents?.length ?: 0) > 10) {
"S:[0] "
} else {
"[X] "
})
result.append(chapterTitle?: "")
result.append(if ((lastPage ?: 0) > 0) {
" [0] "
} else {
" [X] "
})
return result.toString()
}
}

View File

@ -1,61 +0,0 @@
package com.mime.dualscreenview.data.model
import android.content.pm.ActivityInfo
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.PrimaryKey
import java.text.SimpleDateFormat
import java.util.Date
class LastInfo : RealmObject {
@PrimaryKey
var _id : String = "UniqLastId"
var pageUrl : String = ""
var title : String = ""
var chapter : Int = 0
var pageIndex : Int = 0
var contentsName : String = ""
var displayOrientation : Int = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
fun makeHistoryItem() : HistoryItem = HistoryItem().apply {
title = this@LastInfo.title
pageUrl = this@LastInfo.pageUrl
chapter = this@LastInfo.chapter
pageIndex = this@LastInfo.pageIndex
contentsName = this@LastInfo.contentsName
displayOrientation = this@LastInfo.displayOrientation
}
}
class HistoryItem : RealmObject {
@PrimaryKey
var title : String = ""
var pageUrl : String = ""
var chapter : Int = 0
var pageIndex : Int = 0
var contentsName : String = ""
var displayOrientation : Int = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
fun makeLastInfo() = LastInfo().apply{
_id = "UniqLastId"
title = this@HistoryItem.title
pageUrl = this@HistoryItem.pageUrl
chapter = this@HistoryItem.chapter
pageIndex = this@HistoryItem.pageIndex
contentsName = this@HistoryItem.contentsName
displayOrientation = this@HistoryItem.displayOrientation
}
fun putHistory(bookPageInfo: BookPageInfo? , currentPath : String) : HistoryItem {
title = bookPageInfo?.bookTitle ?: SimpleDateFormat("YY-mm-DD-HH:mm").format(Date())
pageUrl = bookPageInfo?.pathUrl ?: ""
chapter = bookPageInfo?.chapterNum ?: 0
pageIndex = bookPageInfo?.lastPage ?: 0
contentsName = bookPageInfo?.chapterTitle ?: ""
return this
}
}
class Bookmark() : RealmObject {
@PrimaryKey
var pageUrl : String = ""
}

View File

@ -1,17 +0,0 @@
package com.mime.dualscreenview.data.model
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.PrimaryKey
class ReaderConfig : RealmObject {
@PrimaryKey
var id : String? = "ReaderConfig"
var textSize : Int? = 14
var textColor : String? = "#FFFFFF"
var bgColor : String? = "#000000"
var style : Int? = 0
var lineSpace : Int? = 1
var letterSpace : Int? = 1
var font : String? = ""
var padding : Int? = 5
}

View File

@ -1,55 +0,0 @@
package com.mime.dualscreenview.dialog
import android.R
import android.content.Context
import android.content.DialogInterface
import android.widget.ArrayAdapter
import androidx.appcompat.app.AlertDialog
import com.mime.dualscreenview.data.model.BookPageInfo
object DefaultList {
fun showDefaultList(context: Context, title : String, items : Collection<BookPageInfo>, firstPosition : Int, choosedTitle : (Int)->String, chooedPositive : (Int)->Unit, saveCalback : (Int)->Unit ) {
val builderSingle: AlertDialog.Builder = AlertDialog.Builder(context)
builderSingle.setTitle(title)
val arrayAdapter =
ArrayAdapter<String>(context, R.layout.select_dialog_singlechoice)
for (item in items) {
arrayAdapter.add(item.getTitleItem())
}
builderSingle.setNeutralButton("전체 저장") { dialog, which ->
saveCalback.invoke(-1)
dialog.dismiss()
}
builderSingle.setNegativeButton("닫기",
DialogInterface.OnClickListener { dialog, which ->
dialog.dismiss() })
builderSingle.setAdapter(arrayAdapter,
DialogInterface.OnClickListener { dialog, position ->
val strName = arrayAdapter.getItem(position)
val builderInner: AlertDialog.Builder = AlertDialog.Builder(context)
builderInner.setMessage(strName)
builderInner.setTitle(choosedTitle.invoke(position))
builderInner.setNegativeButton("닫기") { dialog, which ->
}
// builderInner.setNeutralButton("자동 저장") { dialog, which ->
// saveCalback.invoke(position)
// }
builderInner.setPositiveButton("이동"){ dialog, which ->
chooedPositive.invoke(position)
dialog.dismiss()
}
builderInner.show().apply {
DialogManager.add(this)
}
})
builderSingle.create()?.apply{
setOnShowListener { d->
(d as? AlertDialog)?.let{
it.listView?.setSelection(firstPosition)
}
}
DialogManager.add(this)
}?.show()
}
}

View File

@ -1,19 +0,0 @@
package com.mime.dualscreenview.dialog
import android.app.Dialog
import androidx.activity.ComponentDialog
import java.lang.Exception
object DialogManager {
val dialogs = arrayListOf<ComponentDialog>()
fun add(item : ComponentDialog) = dialogs.add(item)
fun closeAll() {
for (dialog in dialogs) {
try {
dialog?.dismiss()
} catch(e : Exception) {
}
}
}
}

View File

@ -1,97 +0,0 @@
//package com.mime.dualscreenview.dialog
//
//import android.app.Dialog
//import android.content.Context
//import android.content.DialogInterface
//import android.graphics.Color
//import android.os.Bundle
//import android.view.LayoutInflater
//import android.view.View
//import android.view.ViewGroup
//import android.view.Window
//import android.widget.TextView
//import androidx.recyclerview.widget.GridLayoutManager
//import androidx.recyclerview.widget.RecyclerView
//import com.mime.dualscreenview.R
//import kotlin.random.Random
//
//interface StyleSelectInterface {
// fun onSelectStyle(bgColor : String, textColor : String)
//}
//class Stylez : Dialog {
// constructor(context: Context) : super(context) {initView(context)}
// constructor(context: Context, themeResId: Int) : super(context, themeResId) {initView(context)}
// constructor(
// context: Context,
// cancelable: Boolean,
// cancelListener: DialogInterface.OnCancelListener?
// ) : super(context, cancelable, cancelListener) {initView(context)}
//
// var styleSelectInterface : StyleSelectInterface? = null
//
// fun initView(context: Context) {
//
// }
//
// override fun onCreate(savedInstanceState: Bundle?) {
// super.onCreate(savedInstanceState)
// this.requestWindowFeature(Window.FEATURE_NO_TITLE);
// setCancelable(true)
// setContentView(R.layout.dialog_stylesz)
// val recyclerView: RecyclerView = findViewById(R.id.stylez_recyclerview)
// val adapterRe = AdapterRe(context, colorz)
// recyclerView.adapter = adapterRe
// recyclerView.layoutManager =
// GridLayoutManager(context, 2, GridLayoutManager.VERTICAL, false)
// }
//
// inner class AdapterRe(ctx: Context, myImageNameList: Array<Array<String>>) :
// RecyclerView.Adapter<StylezViewHolder>() {
// private val inflater: LayoutInflater
// private val myImageNameList: Array<Array<String>>
// private val ctx : Context
// init {
// inflater = LayoutInflater.from(ctx)
// this.ctx = ctx
// this.myImageNameList = myImageNameList
// }
//
// override fun onCreateViewHolder (
// parent: ViewGroup,
// viewType: Int
// ): StylezViewHolder {
// val view: View = inflater.inflate(R.layout.item_colorz, parent, false)
// return StylezViewHolder(view)
// }
//
// override fun onBindViewHolder(holder: StylezViewHolder, position: Int) {
// var colorz = myImageNameList.get(position)
// var sampleTextz = ctx.resources.getStringArray(R.array.sample_textz)
// holder?.setStyle(bgColor = colorz.get(1), textColor = colorz.get(0),sampleTextz.get(Random.nextInt(9876) % sampleTextz.size))
// }
//
//
// override fun getItemCount(): Int {
// return myImageNameList.size
// }
//
// }
//
// inner class StylezViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
// var textView: TextView
// var bg : View
// init {
// textView = itemView.findViewById(R.id.textview_sample)
// bg = itemView.findViewById(R.id.bg_sample)
// }
// fun setStyle(bgColor : String, textColor : String, sampleText : String ) {
// bg.setBackgroundColor(Color.parseColor(bgColor))
// textView.setTextColor(Color.parseColor(textColor))
// textView.text = sampleText
// itemView?.setOnClickListener { v ->
// styleSelectInterface?.onSelectStyle(bgColor,textColor)
// dismiss()
// }
// }
// }
//}

View File

@ -1,815 +0,0 @@
package com.mime.dualscreenview.view
import android.content.Context
import android.os.SystemClock
import android.util.Log
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
import com.mime.dualscreenview.common.Blog
import com.mime.dualscreenview.view.GestureAnalyser.GestureType
import kotlin.math.abs
import kotlin.math.pow
import kotlin.math.sqrt
enum class TouchArea {
Left,Center,Right, DoubleLeft, DoubleRight
}
class GestureAnalyser @JvmOverloads constructor(
swipeSlopeIntolerance: Int = 3,
doubleTapMaxDelayMillis: Int = 500,
doubleTapMaxDownMillis: Int = 100
) {
private val initialX = DoubleArray(5)
private val initialY = DoubleArray(5)
private val finalX = DoubleArray(5)
private val finalY = DoubleArray(5)
private val currentX = DoubleArray(5)
private val currentY = DoubleArray(5)
private val delX = DoubleArray(5)
private val delY = DoubleArray(5)
private var numFingers = 0
private var initialT: Long = 0
private var finalT: Long = 0
private var currentT: Long = 0
private var prevInitialT: Long = 0
private var prevFinalT: Long = 0
private var swipeSlopeIntolerance = 3
private val doubleTapMaxDelayMillis: Long
private val doubleTapMaxDownMillis: Long
init {
this.swipeSlopeIntolerance = swipeSlopeIntolerance
this.doubleTapMaxDownMillis = doubleTapMaxDownMillis.toLong()
this.doubleTapMaxDelayMillis = doubleTapMaxDelayMillis.toLong()
}
fun trackGesture(ev: MotionEvent) {
val n = ev.pointerCount
for (i in 0 until n) {
initialX[i] = ev.getX(i).toDouble()
initialY[i] = ev.getY(i).toDouble()
}
numFingers = n
initialT = SystemClock.uptimeMillis()
}
fun untrackGesture() {
numFingers = 0
prevFinalT = SystemClock.uptimeMillis()
prevInitialT = initialT
}
fun getGesture(ev: MotionEvent): GestureType {
var averageDistance = 0.0
for (i in 0 until numFingers) {
finalX[i] = ev.getX(i).toDouble()
finalY[i] = ev.getY(i).toDouble()
delX[i] = finalX[i] - initialX[i]
delY[i] = finalY[i] - initialY[i]
averageDistance += sqrt(
(finalX[i] - initialX[i]).pow(2.0) + (finalY[i] - initialY[i]).pow(
2.0
)
)
}
averageDistance /= numFingers.toDouble()
finalT = SystemClock.uptimeMillis()
val gt = GestureType()
gt.gestureFlag = calcGesture()
gt.gestureDuration = finalT - initialT
gt.gestureDistance = averageDistance
return gt
}
fun getOngoingGesture(ev: MotionEvent): Int {
for (i in 0 until numFingers) {
currentX[i] = ev.getX(i).toDouble()
currentY[i] = ev.getY(i).toDouble()
delX[i] = finalX[i] - initialX[i]
delY[i] = finalY[i] - initialY[i]
}
currentT = SystemClock.uptimeMillis()
return calcGesture()
}
private fun calcGesture(): Int {
if (isDoubleTap) {
return DOUBLE_TAP_1
}
if (numFingers == 1) {
if ((-(delY[0])) > (swipeSlopeIntolerance * (abs(
delX[0]
)))
) {
return SWIPE_1_UP
}
if (((delY[0])) > (swipeSlopeIntolerance * (abs(
delX[0]
)))
) {
return SWIPE_1_DOWN
}
if ((-(delX[0])) > (swipeSlopeIntolerance * (abs(
delY[0]
)))
) {
return SWIPE_1_LEFT
}
if (((delX[0])) > (swipeSlopeIntolerance * (abs(
delY[0]
)))
) {
return SWIPE_1_RIGHT
}
}
if (numFingers == 2) {
if (((-delY[0]) > (swipeSlopeIntolerance * abs(
delX[0]
))) && ((-delY[1]) > (swipeSlopeIntolerance * abs(
delX[1]
)))
) {
return SWIPE_2_UP
}
if (((delY[0]) > (swipeSlopeIntolerance * abs(
delX[0]
))) && ((delY[1]) > (swipeSlopeIntolerance * abs(
delX[1]
)))
) {
return SWIPE_2_DOWN
}
if (((-delX[0]) > (swipeSlopeIntolerance * abs(
delY[0]
))) && ((-delX[1]) > (swipeSlopeIntolerance * abs(
delY[1]
)))
) {
return SWIPE_2_LEFT
}
if (((delX[0]) > (swipeSlopeIntolerance * abs(
delY[0]
))) && ((delX[1]) > (swipeSlopeIntolerance * abs(
delY[1]
)))
) {
return SWIPE_2_RIGHT
}
if (finalFingDist(0, 1) > 2 * (initialFingDist(0, 1))) {
return UNPINCH_2
}
if (finalFingDist(0, 1) < 0.5 * (initialFingDist(0, 1))) {
return PINCH_2
}
}
if (numFingers == 3) {
if (((-delY[0]) > (swipeSlopeIntolerance * abs(
delX[0]
)))
&& ((-delY[1]) > (swipeSlopeIntolerance * abs(
delX[1]
)))
&& ((-delY[2]) > (swipeSlopeIntolerance * abs(
delX[2]
)))
) {
return SWIPE_3_UP
}
if (((delY[0]) > (swipeSlopeIntolerance * abs(
delX[0]
)))
&& ((delY[1]) > (swipeSlopeIntolerance * abs(
delX[1]
)))
&& ((delY[2]) > (swipeSlopeIntolerance * abs(
delX[2]
)))
) {
return SWIPE_3_DOWN
}
if (((-delX[0]) > (swipeSlopeIntolerance * abs(
delY[0]
)))
&& ((-delX[1]) > (swipeSlopeIntolerance * abs(
delY[1]
)))
&& ((-delX[2]) > (swipeSlopeIntolerance * abs(
delY[2]
)))
) {
return SWIPE_3_LEFT
}
if (((delX[0]) > (swipeSlopeIntolerance * abs(
delY[0]
)))
&& ((delX[1]) > (swipeSlopeIntolerance * abs(
delY[1]
)))
&& ((delX[2]) > (swipeSlopeIntolerance * abs(
delY[2]
)))
) {
return SWIPE_3_RIGHT
}
if ((finalFingDist(0, 1) > 1.75 * (initialFingDist(0, 1)))
&& (finalFingDist(1, 2) > 1.75 * (initialFingDist(1, 2)))
&& (finalFingDist(2, 0) > 1.75 * (initialFingDist(2, 0)))
) {
return UNPINCH_3
}
if ((finalFingDist(0, 1) < 0.66 * (initialFingDist(0, 1)))
&& (finalFingDist(1, 2) < 0.66 * (initialFingDist(1, 2)))
&& (finalFingDist(2, 0) < 0.66 * (initialFingDist(2, 0)))
) {
return PINCH_3
}
}
if (numFingers == 4) {
if (((-delY[0]) > (swipeSlopeIntolerance * abs(
delX[0]
)))
&& ((-delY[1]) > (swipeSlopeIntolerance * abs(
delX[1]
)))
&& ((-delY[2]) > (swipeSlopeIntolerance * abs(
delX[2]
)))
&& ((-delY[3]) > (swipeSlopeIntolerance * abs(
delX[3]
)))
) {
return SWIPE_4_UP
}
if (((delY[0]) > (swipeSlopeIntolerance * abs(
delX[0]
)))
&& ((delY[1]) > (swipeSlopeIntolerance * abs(
delX[1]
)))
&& ((delY[2]) > (swipeSlopeIntolerance * abs(
delX[2]
)))
&& ((delY[3]) > (swipeSlopeIntolerance * abs(
delX[3]
)))
) {
return SWIPE_4_DOWN
}
if (((-delX[0]) > (swipeSlopeIntolerance * abs(
delY[0]
)))
&& ((-delX[1]) > (swipeSlopeIntolerance * abs(
delY[1]
)))
&& ((-delX[2]) > (swipeSlopeIntolerance * abs(
delY[2]
)))
&& ((-delX[3]) > (swipeSlopeIntolerance * abs(
delY[3]
)))
) {
return SWIPE_4_LEFT
}
if (((delX[0]) > (swipeSlopeIntolerance * abs(
delY[0]
)))
&& ((delX[1]) > (swipeSlopeIntolerance * abs(
delY[1]
)))
&& ((delX[2]) > (swipeSlopeIntolerance * abs(
delY[2]
)))
&& ((delX[3]) > (swipeSlopeIntolerance * abs(
delY[3]
)))
) {
return SWIPE_4_RIGHT
}
if ((finalFingDist(0, 1) > 1.5 * (initialFingDist(0, 1)))
&& (finalFingDist(1, 2) > 1.5 * (initialFingDist(1, 2)))
&& (finalFingDist(2, 3) > 1.5 * (initialFingDist(2, 3)))
&& (finalFingDist(3, 0) > 1.5 * (initialFingDist(3, 0)))
) {
return UNPINCH_4
}
if ((finalFingDist(0, 1) < 0.8 * (initialFingDist(0, 1)))
&& (finalFingDist(1, 2) < 0.8 * (initialFingDist(1, 2)))
&& (finalFingDist(2, 3) < 0.8 * (initialFingDist(2, 3)))
&& (finalFingDist(3, 0) < 0.8 * (initialFingDist(3, 0)))
) {
return PINCH_4
}
}
return 0
}
private fun initialFingDist(fingNum1: Int, fingNum2: Int): Double {
return sqrt(
(initialX[fingNum1] - initialX[fingNum2]).pow(2.0) + (initialY[fingNum1] - initialY[fingNum2]).pow(
2.0
)
)
}
private fun finalFingDist(fingNum1: Int, fingNum2: Int): Double {
return sqrt(
(finalX[fingNum1] - finalX[fingNum2]).pow(2.0) + (finalY[fingNum1] - finalY[fingNum2]).pow(
2.0
)
)
}
val isDoubleTap: Boolean
get() = if (initialT - prevFinalT < doubleTapMaxDelayMillis && finalT - initialT < doubleTapMaxDownMillis && prevFinalT - prevInitialT < doubleTapMaxDownMillis) {
true
} else {
false
}
inner class GestureType {
var gestureFlag: Int = 0
var gestureDuration: Long = 0
var gestureDistance: Double = 0.0
}
companion object {
const val DEBUG: Boolean = true
// Finished gestures flags
const val SWIPE_1_UP: Int = 11
const val SWIPE_1_DOWN: Int = 12
const val SWIPE_1_LEFT: Int = 13
const val SWIPE_1_RIGHT: Int = 14
const val SWIPE_2_UP: Int = 21
const val SWIPE_2_DOWN: Int = 22
const val SWIPE_2_LEFT: Int = 23
const val SWIPE_2_RIGHT: Int = 24
const val SWIPE_3_UP: Int = 31
const val SWIPE_3_DOWN: Int = 32
const val SWIPE_3_LEFT: Int = 33
const val SWIPE_3_RIGHT: Int = 34
const val SWIPE_4_UP: Int = 41
const val SWIPE_4_DOWN: Int = 42
const val SWIPE_4_LEFT: Int = 43
const val SWIPE_4_RIGHT: Int = 44
const val PINCH_2: Int = 25
const val UNPINCH_2: Int = 26
const val PINCH_3: Int = 35
const val UNPINCH_3: Int = 36
const val PINCH_4: Int = 45
const val UNPINCH_4: Int = 46
const val DOUBLE_TAP_1: Int = 107
//Ongoing gesture flags
const val SWIPING_1_UP: Int = 101
const val SWIPING_1_DOWN: Int = 102
const val SWIPING_1_LEFT: Int = 103
const val SWIPING_1_RIGHT: Int = 104
const val SWIPING_2_UP: Int = 201
const val SWIPING_2_DOWN: Int = 202
const val SWIPING_2_LEFT: Int = 203
const val SWIPING_2_RIGHT: Int = 204
const val PINCHING: Int = 205
const val UNPINCHING: Int = 206
private const val TAG = "GestureAnalyser"
}
}
class SimpleFingerGestures : OnTouchListener {
private var debug = true
var consumeTouchEvents: Boolean = false
protected var tracking: BooleanArray = booleanArrayOf(false, false, false, false, false)
private var ga: GestureAnalyser
private var onFingerGestureListener: OnFingerGestureListener? = null
/**
* Constructor that creates an internal [in.championswimmer.sfg.lib.GestureAnalyser] object as well
*/
constructor() {
ga = GestureAnalyser()
}
constructor(
swipeSlopeIntolerance: Int,
doubleTapMaxDelayMillis: Int,
doubleTapMaxDownMillis: Int
) {
ga = GestureAnalyser(swipeSlopeIntolerance, doubleTapMaxDelayMillis, doubleTapMaxDownMillis)
}
fun setDebug(debug: Boolean) {
this.debug = debug
}
constructor(omfgl: OnFingerGestureListener?) {
ga = GestureAnalyser()
setOnFingerGestureListener(omfgl)
}
/**
* Register a callback to be invoked when multi-finger gestures take place
*
*
* <br></br>
*
*
* For the callbacks implemented via this, check the interface [in.championswimmer.sfg.lib.SimpleFingerGestures.OnFingerGestureListener]
*
*
* @param omfgl The callback that will run
*/
fun setOnFingerGestureListener(omfgl: OnFingerGestureListener?) {
onFingerGestureListener = omfgl
}
override fun onTouch(view: View, ev: MotionEvent): Boolean {
if (debug) Log.d(TAG, "onTouch")
when (ev.action and MotionEvent.ACTION_MASK) {
MotionEvent.ACTION_DOWN -> {
if (debug) Log.d(TAG, "ACTION_DOWN")
startTracking(0)
ga.trackGesture(ev)
return consumeTouchEvents
}
MotionEvent.ACTION_UP -> {
if (debug) Log.d(TAG, "ACTION_UP")
if (tracking[0]) {
doCallBack(ga.getGesture(ev))
}
stopTracking(0)
ga.untrackGesture()
return consumeTouchEvents
}
MotionEvent.ACTION_POINTER_DOWN -> {
if (debug) Log.d(TAG, "ACTION_POINTER_DOWN" + " " + "num" + ev.pointerCount)
startTracking(ev.pointerCount - 1)
ga.trackGesture(ev)
return consumeTouchEvents
}
MotionEvent.ACTION_POINTER_UP -> {
if (debug) Log.d(TAG, "ACTION_POINTER_UP" + " " + "num" + ev.pointerCount)
if (tracking[1]) {
doCallBack(ga.getGesture(ev))
}
stopTracking(ev.pointerCount - 1)
ga.untrackGesture()
return consumeTouchEvents
}
MotionEvent.ACTION_CANCEL -> {
if (debug) Log.d(TAG, "ACTION_CANCEL")
return true
}
MotionEvent.ACTION_MOVE -> {
if (debug) Log.d(TAG, "ACTION_MOVE")
return consumeTouchEvents
}
}
return consumeTouchEvents
}
private fun doCallBack(mGt: GestureType) {
when (mGt.gestureFlag) {
GestureAnalyser.SWIPE_1_UP -> onFingerGestureListener!!.onSwipeUp(
1,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_1_DOWN -> onFingerGestureListener!!.onSwipeDown(
1,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_1_LEFT -> onFingerGestureListener!!.onSwipeLeft(
1,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_1_RIGHT -> onFingerGestureListener!!.onSwipeRight(
1,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_2_UP -> onFingerGestureListener!!.onSwipeUp(
2,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_2_DOWN -> onFingerGestureListener!!.onSwipeDown(
2,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_2_LEFT -> onFingerGestureListener!!.onSwipeLeft(
2,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_2_RIGHT -> onFingerGestureListener!!.onSwipeRight(
2,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.PINCH_2 -> onFingerGestureListener!!.onPinch(
2,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.UNPINCH_2 -> onFingerGestureListener!!.onUnpinch(
2,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_3_UP -> onFingerGestureListener!!.onSwipeUp(
3,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_3_DOWN -> onFingerGestureListener!!.onSwipeDown(
3,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_3_LEFT -> onFingerGestureListener!!.onSwipeLeft(
3,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_3_RIGHT -> onFingerGestureListener!!.onSwipeRight(
3,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.PINCH_3 -> onFingerGestureListener!!.onPinch(
3,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.UNPINCH_3 -> onFingerGestureListener!!.onUnpinch(
3,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_4_UP -> onFingerGestureListener!!.onSwipeUp(
4,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_4_DOWN -> onFingerGestureListener!!.onSwipeDown(
4,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_4_LEFT -> onFingerGestureListener!!.onSwipeLeft(
4,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.SWIPE_4_RIGHT -> onFingerGestureListener!!.onSwipeRight(
4,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.PINCH_4 -> onFingerGestureListener!!.onPinch(
4,
mGt.gestureDuration,
mGt.gestureDistance
)
GestureAnalyser.UNPINCH_4 -> {
onFingerGestureListener!!.onUnpinch(4, mGt.gestureDuration, mGt.gestureDistance)
onFingerGestureListener!!.onDoubleTap(1)
}
GestureAnalyser.DOUBLE_TAP_1 -> onFingerGestureListener!!.onDoubleTap(1)
}
}
private fun startTracking(nthPointer: Int) {
for (i in 0..nthPointer) {
tracking[i] = true
}
}
private fun stopTracking(nthPointer: Int) {
for (i in nthPointer until tracking.size) {
tracking[i] = false
}
}
/**
* Interface definition for the callback to be invoked when 2-finger gestures are performed
*/
interface OnFingerGestureListener {
/**
* Called when user swipes **up** with two fingers
*
* @param fingers number of fingers involved in this gesture
* @param gestureDuration duration in milliSeconds
* @return
*/
fun onSwipeUp(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
/**
* Called when user swipes **down** with two fingers
*
* @param fingers number of fingers involved in this gesture
* @param gestureDuration duration in milliSeconds
* @return
*/
fun onSwipeDown(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
/**
* Called when user swipes **left** with two fingers
*
* @param fingers number of fingers involved in this gesture
* @param gestureDuration duration in milliSeconds
* @return
*/
fun onSwipeLeft(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
/**
* Called when user swipes **right** with two fingers
*
* @param fingers number of fingers involved in this gesture
* @param gestureDuration duration in milliSeconds
* @return
*/
fun onSwipeRight(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
/**
* Called when user **pinches** with two fingers (bring together)
*
* @param fingers number of fingers involved in this gesture
* @param gestureDuration duration in milliSeconds
* @return
*/
fun onPinch(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
/**
* Called when user **un-pinches** with two fingers (take apart)
*
* @param fingers number of fingers involved in this gesture
* @param gestureDuration duration in milliSeconds
* @return
*/
fun onUnpinch(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
fun onDoubleTap(fingers: Int): Boolean
}
companion object {
// Will see if these need to be used. For now just returning duration in milliS
const val GESTURE_SPEED_SLOW: Long = 1500
const val GESTURE_SPEED_MEDIUM: Long = 1000
const val GESTURE_SPEED_FAST: Long = 500
private const val TAG = "SimpleFingerGestures"
}
}
//abstract class OnSwipeTouchListener(val context: Context?) : View.OnTouchListener {
// companion object {
// private const val SWIPE_DISTANCE_THRESHOLD = 100
// private const val SWIPE_VELOCITY_THRESHOLD = 100
// }
// private val gestureDetector: GestureDetector
// abstract fun onSwipeLeft()
// abstract fun onSwipeRight()
// abstract fun onSwipeDown()
// abstract fun onSwipeUp()
// abstract fun onSingleTap(area : TouchArea)
// abstract fun onDoubleTap(area : TouchArea)
//
// override fun onTouch(v: View?, event: MotionEvent?): Boolean {
// if (event == null) {
// return false
// }
// return gestureDetector.onTouchEvent(event!!)
// }
//
//
// private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
//
// override fun onDown(e: MotionEvent): Boolean {
// return true
// }
//
// override fun onDoubleTapEvent(e: MotionEvent): Boolean {
// val width: Int = context?.resources?.displayMetrics?.widthPixels ?: 0
// val height: Int = context?.resources?.displayMetrics?.heightPixels ?: 0
// var touchArea : TouchArea = TouchArea.Center
// if(width > 0 && height > 0) {
// val centerAreaSize = width * 0.4
// var sideAreaSize = (width - centerAreaSize) * 0.5
// if(e.x < sideAreaSize) {
// touchArea = TouchArea.DoubleLeft
// } else if(e.x > sideAreaSize && e.x < width - sideAreaSize) {
//
// } else {
// touchArea = TouchArea.DoubleRight
// }
// }
// onDoubleTap(touchArea)
// return super.onDoubleTapEvent(e)
// }
//
// override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
// val width: Int = context?.resources?.displayMetrics?.widthPixels ?: 0
// val height: Int = context?.resources?.displayMetrics?.heightPixels ?: 0
// var touchArea : TouchArea = TouchArea.Center
// if(width > 0 && height > 0) {
// val centerAreaSize = width * 0.4
// var sideAreaSize = (width - centerAreaSize) * 0.5
// if(e.x < sideAreaSize) {
// touchArea = TouchArea.Left
// } else if(e.x > sideAreaSize && e.x < width - sideAreaSize) {
//
// } else {
// touchArea = TouchArea.Right
// }
// }
// onSingleTap(touchArea)
// return super.onSingleTapConfirmed(e)
// }
//
//// override fun onSingleTapUp(e: MotionEvent): Boolean {
////
//// return super.onSingleTapUp(e)
//// }
//
// override fun onFling(
// e1: MotionEvent?,
// e2: MotionEvent,
// velocityX: Float,
// velocityY: Float
// ): Boolean {
//Blog.LOGE("e1.pointerCount >> ${e1?.pointerCount}")
// Blog.LOGE("e2.pointerCount >> ${e2.pointerCount}")
// val distanceX = e2.x - (e1?.x ?: 0f)
// val distanceY = e2.y - (e1?.y ?: 0f)
// if (Math.abs(distanceX) > Math.abs(distanceY)
// && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD
// && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
// if (distanceX > 0) onSwipeRight() else onSwipeLeft()
// return true
// } else if (Math.abs(distanceY) > Math.abs(distanceX)
// && Math.abs(distanceY) > SWIPE_DISTANCE_THRESHOLD
// && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
// if (distanceY > 0) onSwipeDown() else onSwipeUp()
// return true
// } else {
//
// }
// return false
// }
// }
// init {
// gestureDetector = GestureDetector(context, GestureListener())
// }
//}

View File

@ -1,5 +0,0 @@
package com.mime.dualscreenview.view
interface PagedTextGenerateInterface {
fun completePagination(pageList: ArrayList<CharSequence>)
}

View File

@ -1,319 +0,0 @@
package com.mime.dualscreenview.view
import android.annotation.TargetApi
import android.content.Context
import android.graphics.Color
import android.graphics.Typeface
import android.os.Build
import android.os.Handler
import android.util.AttributeSet
import android.view.View
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.Guideline
import androidx.core.view.doOnLayout
import androidx.core.view.updateLayoutParams
import com.mime.dualscreenview.R
import com.mime.dualscreenview.common.Blog
class PagedTextLayout : ConstraintLayout , PagedTextGenerateInterface {
constructor(context: Context) : super(context) {initView(context)}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {initView(context)}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {initView(context)}
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {initView(context)}
var mainTextView : TextView? = null
var sencondTextView : TextView? = null
var demp : View? = null
var hiddenTextView : PagedTextView? = null
var guideLine : Guideline? = null
var pageList: ArrayList<CharSequence>? = null
var summaryText : String = ""
var text : String = ""
set(new) {
Blog.LOGE("field >> ${field}")
Blog.LOGE("new >> ${new}")
field = new
val summary = new.replace(" " ,"").replace("\n" ,"").substring(0,Math.min(30,new.length))
if (summary.equals(summaryText)) {
} else {
Blog.LOGE("field >> ${field}")
hiddenTextView?.setTxtF(field)
hiddenTextView?.visibility = VISIBLE
}
summaryText = summary
}
private val hanler = Handler()
var mPagedTextViewInterface : PagedTextViewInterface? = null
val touchTimeover = Runnable {
mPagedTextViewInterface?.onTimeoverTouch()
}
var currentPageTextView : TextView? = null
fun initView(context: Context) {
inflate(context, R.layout.layout_textviewer, this)
mainTextView = findViewById(R.id.first_view)
sencondTextView = findViewById(R.id.sencond_view)
demp = findViewById(R.id.demp)
currentPageTextView = findViewById(R.id.current_page)
hiddenTextView = findViewById(R.id.hidden_view)
hiddenTextView?.mPagedTextGenerateInterface = this
currentPageTextView?.text = ""
hanler.removeCallbacks(touchTimeover)
setOnLongClickListener { v ->
mPagedTextViewInterface?.onLongClick()
return@setOnLongClickListener false
}
setOnTouchListener(SimpleFingerGestures(omfgl = object : SimpleFingerGestures.OnFingerGestureListener{
override fun onSwipeUp(
fingers: Int,
gestureDuration: Long,
gestureDistance: Double
): Boolean {
mPagedTextViewInterface?.onSwipeUp(fingers)
return false
}
override fun onSwipeDown(
fingers: Int,
gestureDuration: Long,
gestureDistance: Double
): Boolean {
mPagedTextViewInterface?.onSwipeDown(fingers)
return false
}
override fun onSwipeLeft(
fingers: Int,
gestureDuration: Long,
gestureDistance: Double
): Boolean {
mPagedTextViewInterface?.onSwipeLeft(fingers)
return false
}
override fun onSwipeRight(
fingers: Int,
gestureDuration: Long,
gestureDistance: Double
): Boolean {
mPagedTextViewInterface?.onSwipeRight(fingers)
return false
}
override fun onPinch(
fingers: Int,
gestureDuration: Long,
gestureDistance: Double
): Boolean {
return false
}
override fun onUnpinch(
fingers: Int,
gestureDuration: Long,
gestureDistance: Double
): Boolean {
mPagedTextViewInterface?.onLongClick()
return false
}
override fun onDoubleTap(fingers: Int): Boolean {
hanler.removeCallbacks(touchTimeover)
mPagedTextViewInterface?.onTouch(TouchArea.Center)
hanler?.postDelayed(touchTimeover, 3000L)
return false
}
}))
// {
// override fun onSwipeUp() {
// mPagedTextViewInterface?.onLongClick()
// }
//
// override fun onSwipeDown() {
// mPagedTextViewInterface?.onLongClick()
// }
// override fun onSwipeLeft() {
// mPagedTextViewInterface?.onSwipeLeft()
// }
//
// override fun onSwipeRight() {
// mPagedTextViewInterface?.onSwipeRight()
// }
//
// override fun onSingleTap(touchArea: TouchArea) {
// if(TouchArea.Center.equals(touchArea)) {
// hanler.removeCallbacks(touchTimeover)
// mPagedTextViewInterface?.onTouch(touchArea)
// hanler?.postDelayed(touchTimeover, 3000L)
// } else {
// mPagedTextViewInterface?.onTouch(touchArea)
// }
// }
//
// override fun onDoubleTap(area: TouchArea) {
// if(TouchArea.Center.equals(area)) {
//// hanler.removeCallbacks(touchTimeover)
//// mPagedTextViewInterface?.onTouch(area)
//// hanler?.postDelayed(touchTimeover, 3000L)
// } else {
// mPagedTextViewInterface?.onTouch(area)
// }
// }
// })
}
fun layoutChange(needDualPage: Boolean) {
Blog.LOGD(log = "layoutChange>> ${this::class.java.name}")
if (needDualPage) {
sencondTextView?.visibility = VISIBLE
demp?.visibility = VISIBLE
} else {
sencondTextView?.visibility = GONE
demp?.visibility = GONE
}
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
Blog.LOGD(log = "onLayout>> ${this::class.java.name} changed >> ${changed}")
if(changed) {
hiddenTextView?.text = text
forceUpdateUI()
}
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
Blog.LOGD(log = "onSizeChanged>> ${this::class.java.name}")
if (w != oldw || oldh != h) {
postDelayed(Runnable {
layoutChange(w > (h * 0.7f))
},20)
}else {
}
}
var currentPage = 0
override fun completePagination(pageList: ArrayList<CharSequence>) {
Blog.LOGD(log = "completePagination>> ${this::class.java.name} >> pageList ${pageList}")
if(text.length > 0 && pageList!= null && pageList.size == 0) {
} else {
this.pageList = pageList
setPageBy(0)
}
hiddenTextView?.visibility = GONE
}
fun setColorStyle(colors : Array<String>) {
setBackgroundColor(Color.parseColor(colors.get(1)))
mainTextView?.setBackgroundColor(Color.parseColor(colors.get(1)))
sencondTextView?.setBackgroundColor(Color.parseColor(colors.get(1)))
mainTextView?.setTextColor(Color.parseColor(colors.get(0)))
sencondTextView?.setTextColor(Color.parseColor(colors.get(0)))
}
// fun setPagedTextViewInterface(pagedTextViewInterface: PagedTextViewInterface) = hiddenTextView?.setPagedTextViewInterface(pagedTextViewInterface)
// fun setText(replace: String) = hiddenTextView?.setText(replace)
fun setTextSize(fl: Float) {
hiddenTextView?.setTextSize(fl)
mainTextView?.setTextSize(fl)
sencondTextView?.setTextSize(fl)
}
fun next(page : Int) {
}
fun isDualPage() : Boolean {
return sencondTextView?.visibility == VISIBLE
}
fun setPageBy(num : Int) {
currentPage = num
var realPage = if(isDualPage()) currentPage * 2 else currentPage
Blog.LOGE("realPage = if(${pageList?.size} ?: 0 > ${realPage}) { realPage} else { ${(pageList?.size ?: 0) - 1 }}")
realPage = if(pageList?.size ?: 0 > realPage) { realPage} else { (pageList?.size ?: 0) - 1 }
currentPageTextView?.text = "${realPage + 1 }/${ pageList?.size ?: 0 + 1}"
mainTextView?.text = pageList?.get(realPage) ?: "NONE"
if(isDualPage()) {
realPage = realPage.inc()
sencondTextView?.text = if(pageList?.size ?: 0 > realPage) { pageList?.get(realPage)} else { ""}
} else {
sencondTextView?.text = ""
}
}
fun size(): Int = if(isDualPage()) Math.round((hiddenTextView?.size() ?:0) * 0.5f) else hiddenTextView?.size() ?: 0
fun getFastPageCount() = if(isDualPage()) 3 else 6
fun current(): Int = currentPage
fun doNext(fast : Boolean = false) {
if (fast) {
setPageBy(if((currentPage + getFastPageCount()) >= 0) {
currentPage + getFastPageCount()
} else {size()})
} else {
setPageBy(currentPage.inc())
}
}
fun doPrev(fast : Boolean = false) {
if (fast) {
setPageBy(if((currentPage - getFastPageCount()) >= 0) {
currentPage - getFastPageCount()
} else {0})
} else {
setPageBy(if(currentPage > 0 )currentPage.dec() else 0)
}
}
fun forceUpdateUI() {
hiddenTextView?.doUpdate()
}
override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
hiddenTextView?.setPadding(left,top,right, bottom)
mainTextView?.setPadding(left,top,right, bottom)
sencondTextView?.setPadding(left,top,right, bottom)
}
fun setTypeface(tf: Typeface?) {
hiddenTextView?.setTypeface(tf)
mainTextView?.setTypeface(tf)
sencondTextView?.setTypeface(tf)
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun setLetterSpacing(letterSpacing: Float) {
hiddenTextView?.letterSpacing = letterSpacing.times(0.01f)
mainTextView?.letterSpacing = letterSpacing.times(0.01f)
sencondTextView?.letterSpacing = letterSpacing.times(0.01f)
}
fun setLineSpacing(mult: Float) {
hiddenTextView?.setLineSpacing(1f, 1f.plus(mult.times(0.01f)))
mainTextView?.setLineSpacing(1f, 1f.plus(mult.times(0.01f)))
sencondTextView?.setLineSpacing(1f, 1f.plus(mult.times(0.01f)))
}
}

View File

@ -1,263 +0,0 @@
package com.mime.dualscreenview.view
import android.annotation.TargetApi
import android.content.Context
import android.graphics.Typeface
import android.os.Build
import android.text.Layout
import android.text.StaticLayout
import android.util.AttributeSet
import android.util.TypedValue
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.view.marginBottom
import androidx.core.view.marginLeft
import androidx.core.view.marginRight
import androidx.core.view.marginTop
import com.mime.dualscreenview.common.Blog
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import kotlin.math.min
class PagedTextView : AppCompatTextView {
private var needPaginate = false
private var isPaginating = false
private val pageList = arrayListOf<CharSequence>()
private var pageIndex: Int = 0
private var pageHeight: Int = 0
private var originalText: CharSequence = ""
var mPagedTextGenerateInterface : PagedTextGenerateInterface? = null
constructor(context: Context?) : super(context!!){initView(context)}
constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs){initView(context)}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context!!, attrs, defStyleAttr){initView(context)}
fun initView(context: Context?){
}
fun size(): Int = pageList.size
fun current() : Int = pageIndex
fun doPrev() {
if (pageIndex > 0 )
pageIndex = pageIndex - 1
setPageText()
}
fun doNext() {
if (pageIndex < pageList.size)
pageIndex = pageIndex + 1
setPageText()
}
fun next(index: Int) {
pageIndex = index
setPageText()
}
private fun setPageText() {
if(pageList.size > 0) {
isPaginating = true
text = pageList[pageIndex]
isPaginating = false
}
}
fun setTxtF(text: CharSequence?) {
needPaginate = true
this.setText(text , null)
}
override fun setText(text: CharSequence?, type: BufferType?) {
if (!isPaginating) {
needPaginate = true
originalText = text ?: ""
}
super.setText(text, type)
}
override fun setTextSize(size: Float) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, size)
}
override fun setTextSize(unit: Int, size: Float) {
super.setTextSize(unit, size)
paint.textSize = TypedValue.applyDimension(unit, size, context.resources.getDisplayMetrics())
needPaginate = true
}
override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
super.setPadding(left, top, right, bottom)
needPaginate = true
}
override fun setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) {
super.setPaddingRelative(start, top, end, bottom)
needPaginate = true
}
override fun setTextScaleX(size: Float) {
if (size != textScaleX) {
needPaginate = true
}
super.setTextScaleX(size)
}
override fun setTypeface(tf: Typeface?) {
if (typeface != null && tf != typeface) {
needPaginate = true
paint.typeface = tf
}
super.setTypeface(tf)
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
override fun setLetterSpacing(letterSpacing: Float) {
if (letterSpacing != this.letterSpacing) {
needPaginate = true
}
super.setLetterSpacing(letterSpacing)
}
override fun setHorizontallyScrolling(whether: Boolean) {
super.setHorizontallyScrolling(false)
}
override fun setLineSpacing(add: Float, mult: Float) {
if (add != lineSpacingExtra || mult != lineSpacingMultiplier) {
needPaginate = true
}
super.setLineSpacing(add, mult)
}
override fun setMaxLines(maxLines: Int) {
if (maxLines != this.maxLines) {
needPaginate = true
}
super.setMaxLines(maxLines)
}
override fun setLines(lines: Int) {
super.setLines(lines)
if (lines != this.lineCount) {
needPaginate = true
}
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
Blog.LOGD(log = "onSizeChanged>> ${this::class.java.name}")
pageHeight = ((h - (marginTop + marginBottom + paddingTop + paddingBottom)) * 1f).toInt()
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
Blog.LOGD(log = "onLayout>> ${this::class.java.name} changed >> ${changed}")
if (changed || needPaginate) {
paginate()
setPageText()
needPaginate = false
}
}
fun doUpdate() {
if (needPaginate && layout != null) {
paginate()
setPageText()
needPaginate = false
}
}
private fun paginate() {
if (layout != null) {
MainScope().launch {
pageList.clear()
Blog.LOGD(log = "paginate>> ${this::class.java.name} && ${layout.text}")
val layout = from(layout)
val lines = if(min(maxLines, layout.lineCount) > 10) {min(maxLines, layout.lineCount) - 1} else {min(maxLines, layout.lineCount)}
var startOffset = 0
val heightWithoutPaddings = pageHeight //- (marginTop + marginBottom + paddingTop + paddingBottom)
var height = heightWithoutPaddings
for (i in 0 until lines) {
if (height < layout.getLineBottom(i)) {
pageList.add(
layout.text.subSequence(startOffset, layout.getLineStart(i))
)
startOffset = layout.getLineStart(i)
height = layout.getLineTop(i) + heightWithoutPaddings
}
if (i == lines - 1) {
pageList.add(
if(layout.lineCount > i) {
layout.text.subSequence(startOffset, layout.getLineEnd(i + 1))
} else {
layout.text.subSequence(startOffset, layout.getLineEnd(i))
}
)
}
}
mPagedTextGenerateInterface?.completePagination(pageList)
}
}
}
private fun from(layout: Layout): Layout =
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
@Suppress("DEPRECATION")
(StaticLayout(
originalText,
paint,
layout.width,
layout.alignment,
lineSpacingMultiplier,
lineSpacingExtra,
includeFontPadding
))
} else {
StaticLayout.Builder
.obtain(originalText, 0, originalText.length, paint, ((layout.width - (paddingLeft + paddingRight + marginLeft + marginRight) * 0.85f)).toInt())
.setAlignment(layout.alignment)
.setLineSpacing(lineSpacingExtra, lineSpacingMultiplier)
.setIncludePad(includeFontPadding)
.setUseLineSpacingFromFallbacks()
.setBreakStrategy(breakStrategy)
.setHyphenationFrequency(hyphenationFrequency)
// .setJustificationMode()
.setMaxLines(maxLines)
.build()
}
private fun StaticLayout.Builder.setUseLineSpacingFromFallbacks(): StaticLayout.Builder {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
this.setUseLineSpacingFromFallbacks(isFallbackLineSpacing)
}
return this
}
private fun StaticLayout.Builder.setJustificationMode(): StaticLayout.Builder {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.setJustificationMode(justificationMode)
}
return this
}
}

View File

@ -1,11 +0,0 @@
package com.mime.dualscreenview.view
interface PagedTextViewInterface {
fun onTouch(touchArea: TouchArea)
fun onTimeoverTouch()
fun onSwipeLeft(touchCount : Int)
fun onSwipeRight(touchCount : Int)
fun onSwipeDown(touchCount : Int)
fun onSwipeUp(touchCount : Int)
fun onLongClick()
}

View File

@ -1,64 +0,0 @@
package com.mime.dualscreenview.view
import android.content.Context
import android.util.AttributeSet
import android.widget.Button
import androidx.appcompat.widget.AppCompatButton
import com.mime.dualscreenview.R
class ScopeEditor: SideButtonTextView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
var titleArray : Array<String>? = null
set(value) {
if(value != null && value.size < 1) {
Error("titleArray는 최소 한개 이상이여야됨.")
return
}
field = value
maxValue = field!!.size
}
var maxValue : Int = 1
set(value) {
if (value < 1) {
Error("maxValue는 무조건 0보다 커야하눈뎅....")
return
}
field = value
}
override var value : Int = 14
set(newValue) {
field = newValue
text_value?.text = displayFormat.format(titleArray?.get(field) ?:"defulat")
mValueChange?.invoke(field)
}
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
init {
// super.i
// inflate(context, R.layout.layout_steps_editor,this)
btn_decrement?.setOnClickListener { value = Math.abs(value.dec()).rem(maxValue) }
btn_increment?.setOnClickListener { value = value.inc().rem(maxValue) }
leftButtonTitle = "<"
rightButtonTitle = ">"
}
}

View File

@ -1,78 +0,0 @@
package com.mime.dualscreenview.view
import android.content.Context
import android.util.AttributeSet
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.widget.AppCompatButton
import androidx.constraintlayout.widget.ConstraintLayout
import com.mime.dualscreenview.R
import java.lang.Exception
open class SideButtonTextView : ConstraintLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
var leftButtonTitle : String = ""
set(value) {
field = value
btn_decrement?.text = field
}
var rightButtonTitle : String = ""
set(value) {
field = value
btn_increment?.text = field
}
open var value : Int = 14
set(newValue) {
field = newValue
text_value?.text = displayFormat.format(field)
mValueChange?.invoke(field)
}
var displayFormat = "글자 크기 : %d"
set(newValue) {
field = newValue
try {
text_value?.text = displayFormat.format(value)
} catch (e : Exception) {
}
}
var mValueChange : ValueChange? = null
set(newValue) {
field = newValue
if (newValue != null) {
newValue(value)
}
}
var btn_decrement : AppCompatButton? = null
var btn_increment : AppCompatButton? = null
var text_value : TextView? = null
init {
inflate(context, R.layout.layout_steps_editor,this)
btn_increment = findViewById(R.id.btn_increment)
btn_decrement = findViewById(R.id.btn_decrement)
text_value = findViewById(R.id.text_value)
btn_decrement?.setOnClickListener { value = value.dec() }
btn_increment?.setOnClickListener { value = value.inc() }
}
}

View File

@ -1,32 +0,0 @@
package com.mime.dualscreenview.view
import android.content.Context
import android.util.AttributeSet
import com.mime.dualscreenview.R
typealias ValueChange = (Int)->Unit
class StepsEditor : SideButtonTextView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
init {
// inflate(context, R.layout.layout_steps_editor,this)
btn_decrement?.setOnClickListener { value = value.dec() }
btn_increment?.setOnClickListener { value = value.inc() }
leftButtonTitle = "-"
rightButtonTitle = "+"
}
}

View File

@ -1,81 +0,0 @@
package com.mime.dualscreenview.webcontents
import android.util.Log
import android.webkit.*
import com.mime.dualscreenview.webcontents.contentsinfo.ActionByBool
import com.mime.dualscreenview.webcontents.contentsinfo.ContentsInfoInterface
import com.mime.dualscreenview.webcontents.contentsinfo.DidFindContents
abstract class BaseWebContents : ContentsInfoInterface {
open var lastNumber : Int = 221
var completeAction : ActionByBool? = null
// val definedActionCount = 5
// var completeActionCount = 0
// set(value) {
// field = value
// if(field == definedActionCount && completeAction != null) {
// completeAction?.invoke(true)
// }
// }
fun findListItem(webview: WebView, callBakItems : DidFindContents) {
webview.evaluateJavascript(getContentsList()) { result ->
callBakItems.invoke(result)
}
}
fun doOnloaded(webview: WebView, findContents : DidFindContents, completeAction : ActionByBool) {
// completeActionCount = 0
this.completeAction = completeAction
// webview.evaluateJavascript(getTitleJs()) { result : String? ->
// result?.let { resultString ->
// findTitle.invoke(resultString)
// }
// completeActionCount = completeActionCount + 1
// }
webview.evaluateJavascript(getFindContentsJs()) { result : String? ->
result?.let { resultString ->
checkCorrectContents(resultString)?.let { contents ->
if(resultString != null && !"null".equals(resultString) && !resultString.isNullOrEmpty()) {
findContents.invoke(contents)
} else {
findContents.invoke(null)
}
}
} ?: findContents.invoke(null)
// completeActionCount = completeActionCount + 1
}
// webview.evaluateJavascript("document.getElementById('${getNextButtonJs()}')") { result : String? ->
// result?.let { resultString ->
// Log.e("BaseWebContents", "getNextButtonJs() >> ${resultString}")
// if(resultString != null && !"null".equals(resultString)) {
// findNextButton.invoke(resultString)
// } else {
// findNextButton.invoke(null)
// }
// }
// completeActionCount = completeActionCount + 1
// }
// webview.evaluateJavascript("document.getElementById('${getPrevButtonJs()}')") { result : String? ->
// result?.let { resultString ->
// Log.e("BaseWebContents", "getPrevButtonJs() >> ${resultString}")
// if(resultString != null && !"null".equals(resultString)) {
// findPrevButton.invoke(resultString)
// }else {
// findPrevButton.invoke(null)
// }
// }
// completeActionCount = completeActionCount + 1
// }
webview.evaluateJavascript(onLoadedJs()) {
Log.e("BaseWebContents", "onLoadedJs() >> ${it}")
// completeActionCount = completeActionCount + 1
}
completeAction?.invoke(true)
}
}

View File

@ -1,251 +0,0 @@
package com.mime.dualscreenview.webcontents
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.graphics.Bitmap
import android.net.Uri
import android.net.http.SslError
import android.util.Log
import android.webkit.*
import androidx.core.net.toUri
import com.google.gson.Gson
import com.mime.dualscreenview.common.Blog
import com.mime.dualscreenview.common.PrefManager
import com.mime.dualscreenview.data.HistoryManager
import com.mime.dualscreenview.data.model.BookPageInfo
import com.mime.dualscreenview.data.model.BookPageInfos
import com.mime.dualscreenview.data.model.LastInfo
import com.mime.dualscreenview.webcontents.contentsinfo.Booktoki
import com.mime.dualscreenview.webcontents.contentsinfo.DidFindContents
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.realmListOf
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.json.JSONObject
import org.jsoup.Jsoup
import org.jsoup.select.Elements
open class BaseWebContentsViewer {
var currentContentsProvider : BaseWebContents? = null
lateinit var webview : WebView
lateinit var mainControllInterface : MainControllInterface
@JavascriptInterface
fun onBookInfo(jsonData : String) {
GlobalScope.launch {
try {
Blog.LOGE("BaseWebContentsViewer",jsonData)
val data: JSONObject = JSONObject(jsonData)
Blog.LOGE("BaseWebContentsViewer",data.toString())
mainControllInterface?.onBookInfos(jsonData)
} catch (e : Exception) {
}
}
}
@SuppressLint("JavascriptInterface")
constructor(webview : WebView, mainControllInterface : MainControllInterface ) {
this.webview = webview
this.mainControllInterface = mainControllInterface
webview.webChromeClient = rootWebChromeClient
webview.webViewClient = rootWebViewClient
webview.settings.textZoom = 100
webview.addJavascriptInterface(this,"PAgit")
webview.settings.javaScriptEnabled = true
webview.settings.javaScriptCanOpenWindowsAutomatically = false
webview.settings.loadWithOverviewMode = true
webview.settings.setPluginState(WebSettings.PluginState.ON)
webview.settings.domStorageEnabled = true
webview.clearCache(true);
try {
webview.removeJavascriptInterface("MyJavaScriptInterface")
}catch (e :Exception){e.printStackTrace()}
webview.addJavascriptInterface( BookHelper(),"MyJavaScriptInterface")
webview.clearHistory();
webview.clearSslPreferences();
WebView.setWebContentsDebuggingEnabled(true)
}
constructor()
fun loadContents(webContents: BaseWebContents) {
currentContentsProvider = webContents
currentContentsProvider?.let {
webview.loadUrl(it.getLastedDoamin())
}
}
val rootWebChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
}
}
fun findListItem(callBakItems : DidFindContents) {
currentContentsProvider?.findListItem(webview,callBakItems)
}
fun loadLastInfo(lastInfo: LastInfo) {
lastInfo?.let { last ->
currentContentsProvider = WebContentsManger.getBaseWebContentsBy(last.contentsName)
if (last.pageUrl.startsWith("https://")) {
webview.loadUrl(last.pageUrl)
} else {
try {
webview.loadUrl(PrefManager.getLastDomain().plus(last.pageUrl))
} catch (e : Exception) {
webview.loadUrl(PrefManager.getLastDomain())
}
}
}
}
val rootWebViewClient = object : WebViewClient() {
override fun shouldInterceptRequest(
view: WebView?,
request: WebResourceRequest?
): WebResourceResponse? {
Log.e("shouldInterceptRequest", " >>>> ${request?.url?.toString()} , ${request?.url?.toString()?.contains("gif")}")
if(request?.url?.toString()?.contains("gif") ?: false) {
return WebResourceResponse("text/javascript", "UTF-8", null);
}
// if(request?.url?.toString()?.contains(currentContentsProvider?.acccceptResourceKeyword() ?: "") == false && request?.url?.toString()?.contains(currentContentsProvider?.getLastedDoamin() ?: "") == false) {
// return WebResourceResponse("text/javascript", "UTF-8", null);
// }
return super.shouldInterceptRequest(view, request)
}
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
mainControllInterface?.onStartLoad()
}
override fun onReceivedSslError(
view: WebView?,
handler: SslErrorHandler?,
error: SslError?
) {
// super.onReceivedSslError(view, handler, error)
Blog.LOGE(log= "onReceivedSslError >> ${error}")
handler?.proceed()
}
override fun onReceivedHttpError(
view: WebView?,
request: WebResourceRequest?,
errorResponse: WebResourceResponse?
) {
Blog.LOGE(log= "onReceivedHttpError >> ${errorResponse}")
// super.onReceivedHttpError(view, request, errorResponse)
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
finishedUrl = url ?: ""
view?.let {
url?.toUri()?.let {
PrefManager.putLastDomain(it.scheme.plus("::/").plus(it.host))
}
if(url?.contains("/list/") ?: false && url?.contains("agit") ?: false){
findListItem {
Blog.LOGE("onPageFinished", url ?: "")
}
} else if (url?.contains("booktoki") ?: false){
// findListItem {
// Blog.LOGE("onPageFinished", url ?: "")
// }
}
view?.postDelayed({
view?.evaluateJavascript(
"function getAll() {\n" +
" MyJavaScriptInterface.sendValueFromHtml(document.getElementsByTagName('html')[0].innerHTML)" +
" };getAll()"
) { result ->
(result as? String)?.let {
}
}
}, 500L)
currentContentsProvider?.doOnloaded(it , { result ->
result?.let { mainControllInterface.onLoadedContents(it) }
} , { complete ->
if(complete) {
mainControllInterface?.completePageLoad(LastInfo().apply {
this.pageUrl = url?.toUri()?.path ?: currentContentsProvider?.getLastedDoamin() ?: ""
this.contentsName = currentContentsProvider?.getWebcontentsName() ?: ""
this.pageIndex = 0
})
}
})
}
}
}
var finishedUrl : String = ""
inner class BookHelper {
@JavascriptInterface
fun sendValueFromHtml(string: String) {
Jsoup.parse(string)?.let { html ->
val toon_intro = html.getElementById("toon_intro")
val view_padding = html.getElementsByClass("view-padding")
if (toon_intro != null) {
// Blog.LOGE("finishedUrl >>> ${finishedUrl} :::: ${html.title()}")
val bookPageInfos = BookPageInfos()
bookPageInfos.bookPageUrl = Uri.parse(finishedUrl).path
bookPageInfos.bookTitle = if (toon_intro.getElementsByTag("h3").size > 0) toon_intro.getElementsByTag("h3").get(0).text() else ""
bookPageInfos.pages = realmListOf<BookPageInfo>()
// Blog.LOGE("finishedUrl >>> ${finishedUrl} :::: bookPageInfos >>>> ${Gson().toJson(bookPageInfos)}")
val listParent = html.getElementById("list_type")
if (listParent != null) {
listParent.getElementsByClass("row").forEach { bookitem ->
// Blog.LOGE("finishedUrl >>> ${finishedUrl} :::: bookItemInfo ${bookitem}")
try {
val bookPageInfo = BookPageInfo()
bookPageInfo.bookTitle = bookPageInfos.bookTitle
bookPageInfo.chapterNum = bookitem.getElementsByClass("cell_num").getT().toInt()
bookPageInfo.chapterID = bookitem.getElementsByClass("cell_num").getT().toInt()
bookPageInfo.chapterTitle = bookitem.getElementsByTag("a").getT()
bookPageInfo.bookPageUrl = bookPageInfos.bookPageUrl
val href = bookitem.getElementsByTag("a").get(0).attr("href")
bookPageInfo.pathUrl = Uri.parse(href).path
bookPageInfos.pages.add(bookPageInfo)
}catch (nfe : NumberFormatException) {
nfe.printStackTrace()
}
}.apply {
HistoryManager.openRealm.writeBlocking {
copyToRealm(bookPageInfos, UpdatePolicy.ALL)
// Blog.LOGE("finishedUrl >>> ${finishedUrl} :::: bookPageInfos saved >>>> ${bookPageInfos.bookPageUrl}")
}
mainControllInterface.onBookInfos(bookPageInfos)
}
}
}else if (view_padding.size > 0){
// Blog.LOGE("finishedUrl >>> ${finishedUrl} :::: ${html.title()}")
val contents = view_padding.get(0).children().html().replace("<p>"," ").replace("</p>","\n\n")
// Blog.LOGE("finishedUrl >>> ${finishedUrl} :::: view_padding.get(0)\n${contents}")
if (contents.length > 20) {
Uri.parse(finishedUrl).path?.let {
HistoryManager.getBooPageInfoContentsSave(it, contents)
mainControllInterface.onLoadedContents(contents)
}
}
} else {
Blog.LOGE("finishedUrl >>> ${finishedUrl} :::: ${html.title()}")
Blog.LOGE("finishedUrl >>> ${finishedUrl} :::: whole body ${html}")
}
}
}
}
}
fun Elements.getT() = if (size > 0) get(0).text() else ""

View File

@ -1,5 +0,0 @@
//package com.mime.dualscreenview.webcontents
//
//typealias ActionByBool = (Boolean) -> Unit
//typealias DidFindContents = (String?) -> Unit
//typealias GotoSomeWhere = () -> Unit

View File

@ -1,22 +0,0 @@
package com.mime.dualscreenview.webcontents
import com.mime.dualscreenview.data.model.BookPageInfos
import com.mime.dualscreenview.data.model.LastInfo
import com.mime.dualscreenview.webcontents.contentsinfo.GotoSomeWhere
interface MainControllInterface {
fun onStartLoad()
fun completePageLoad(apply: LastInfo)
fun showNextBtn(finnd : Boolean, onClickAction: GotoSomeWhere)
fun showPrevBtn(finnd : Boolean,onClickAction: GotoSomeWhere)
fun showAlert(alert :String)
fun onLoadedContents(contents :String)
fun onFindTitle(contents :String)
fun onBookInfos(jsonString : String)
fun onBookInfos(infos : BookPageInfos)
}

View File

@ -1,20 +0,0 @@
package com.mime.dualscreenview.webcontents
import com.mime.dualscreenview.webcontents.contentsinfo.Agit
import com.mime.dualscreenview.webcontents.contentsinfo.Booktoki
import com.mime.dualscreenview.webcontents.contentsinfo.NewtokiOne
object WebContentsManger {
val allContentsList : ArrayList<BaseWebContents> = arrayListOf(NewtokiOne)
fun getBaseWebContentsBy(name : String) : BaseWebContents {
var correctContents : BaseWebContents = Booktoki
for (contents in allContentsList) {
if(name.equals(contents.getWebcontentsName())) {
correctContents = contents
break
}
}
return correctContents
}
}

View File

@ -1,138 +0,0 @@
package com.mime.dualscreenview.webcontents.contentsinfo
import com.mime.dualscreenview.webcontents.BaseWebContents
object Agit : BaseWebContents() {
override var lastNumber : Int = 664
override fun getWebcontentsName(): String {
return "Agit"
}
override fun getLastedDoamin(): String {
return String.format("https://agit%d.xyz/", lastNumber)
}
override fun getContentsList(): String {
return " var datasets = [];\n" +
" var pageNum = 0;\n" +
" var totalCount = 0;\n" +
" var currentIdx = 0;\n" +
" function getContentList() {\n" +
" \n" +
" if(document.getElementById('count_list') != undefined && totalCount <= 0) {\n" +
" totalCount = Number(document.getElementById('count_list').textContent);\n" +
" console.log(\"totalCount \" + totalCount);\n" +
" currentIdx = totalCount;\n" +
" }\n" +
" \n" +
" var bookTitle = document.getElementsByClassName('pt-2')[1].textContent;\n" +
" var bookPageUrl = new URL(location.href).pathname;\n" +
" var pages = document.getElementById('id_page_novel_c').childNodes;\n" +
" var list = document.getElementById('id_list_novel_c').childNodes;\n" +
" console.log(\"list.length >> \" + list.length);\n" +
" for (i = 0; i < list.length; i++) {\n" +
" var onclickValue = list[i].attributes['onclick'].value;\n" +
" var pageUrl = onclickValue.split('location.href=')[1].replace(';', '');\n" +
" var chapterTitle = list[i].childNodes[1].children[0].textContent;\n" +
" var chapterID = list[i].childNodes[1].getAttribute('data-wr-id-c');\n" +
" \n" +
" var data = {\n" +
" 'chapterID': Number(chapterID),\n" +
" 'idx': Number(currentIdx),\n" +
" 'pathUrl': pageUrl,\n" +
" 'bookPageUrl': bookPageUrl,\n" +
" 'chapterTitle': chapterTitle,\n" +
" 'bookTitle': bookTitle,\n" +
" };\n" +
" datasets.push(data);\n" +
" currentIdx = currentIdx - 1\n" +
" }\n" +
" \n" +
" \n" +
" \n" +
" var currentTime = 500;\n" +
" try { currentTime = new Date().valueOf() % 1000;\n" +
" \n" +
" } catch (e) {\n" +
" \n" +
" }\n" +
" \n" +
" console.log(\"pages.length >> \" + pages.length);\n" +
" console.log(\"datasets.length >> \" + datasets.length);\n" +
" console.log(\"totalCount >> \" + totalCount);\n" +
" console.log(\"pages.length >> \" + pages.length);\n" +
" \n" +
" if ((pages.length > pageNum) ||\n" +
" (totalCount > datasets.length)) {\n" +
" pageNum += 1;\n" +
" get_data_novel_list_c(pageNum);\n" +
" setTimeout(function() {\n" +
" getContentList();\n" +
" }, 2000 + currentTime);\n" +
" } else if ((pages.length == pageNum) ||\n" +
" (totalCount > 10 &&\n" +
" totalCount == datasets.length)) {\n" +
" datasets.sort((a, b) => b.idx < a.idx);\n" +
" var i = 0;\n" +
" datasets.forEach(function(item) {\n" +
" item['chapterNum'] = i;\n" +
" i = i + 1;\n" +
" } );\n" +
" \n" +
" PAgit.onBookInfo(JSON.stringify({\n" +
" 'bookTitle': bookTitle,\n" +
" 'bookPageUrl': new URL(location.href)\n" +
" .pathname,\n" +
" 'pages': datasets ,\n" +
" }));\n" +
" }\n" +
" }\n" +
" \n" +
" function wait(sec) {\n" +
" let start = Date.now(),\n" +
" now = start;\n" +
" while (now - start < sec * 1000) {\n" +
" now = Date.now();\n" +
" }\n" +
" }\n" +
" getContentList();"
}
override fun acccceptResourceKeyword(): String {
return "toki"
}
override fun getNextButtonJs(): String {
return "goNextBtn"
}
override fun getPrevButtonJs(): String {
return "goPrevBtn"
}
override fun getTitleJs(): String {
return "document.getElementsByClassName(\"toon-title\").length > 0 ? document.getElementsByClassName(\"toon-title\")[0].title : null"
}
override fun getFindContentsJs(): String {
return "document.getElementById('id_wr_content') != null ? document.getElementById('id_wr_content').innerText : null"
}
override fun checkCorrectContents(contents: String): String {
return if (contents != null && !contents.isNullOrEmpty()) {
contents
} else {
"fail load"
}
}
override fun onLoadedJs(): String {
return "if(document.getElementsByClassName(\"hd_pops\") != null && document.getElementsByClassName(\"hd_pops\").length > 0) document.getElementsByClassName(\"hd_pops\")[0].remove();" +
"if(document.getElementsByClassName(\"hd_pops\") != null && document.getElementsByClassName(\"hd_pops\").length > 0) document.getElementsByClassName(\"hd_pops\")[0].remove();" +
"if(document.getElementById(\"main-banner-view\") != null) document.getElementById(\"main-banner-view\").remove();" +
"if(document.getElementsByClassName(\"board-tail-banner\") != null && document.getElementsByClassName(\"board-tail-banner\").length > 0)document.getElementsByClassName(\"board-tail-banner\")[0].remove();" +
"if(document.getElementById(\"id_mbv\") != null)document.getElementById(\"id_mbv\").remove();"
}
}

View File

@ -1,95 +0,0 @@
package com.mime.dualscreenview.webcontents.contentsinfo
import com.mime.dualscreenview.webcontents.BaseWebContents
object Booktoki : BaseWebContents() {
override var lastNumber : Int = 351
override fun getWebcontentsName(): String {
return "Booktoki"
}
override fun getLastedDoamin(): String {
return String.format("https://booktoki%d.com/", lastNumber)
}
override fun getContentsList(): String {
return "function getList() {\n" +
" const contentsArray = [];\n" +
" var children = document.getElementsByClassName('list-body')[0].children;\n" +
" var maxCount = children.length;\n" +
" for (i= 0; i < maxCount; i++) {\n" +
" var chapterNum = children[i].getElementsByClassName('wr-num')[0].textContent;\n" +
" var pageUrl = children[i].getElementsByClassName('wr-subject')[0].getElementsByTagName('a')[0].href;\n" +
" if (pageUrl != null && pageUrl.length > 0 && pageUrl.startsWith(\"http\")) {\n" +
" pageUrl = new URL(pageUrl).pathname;\n" +
" }\n" +
" var chapterTitle = children[i].getElementsByClassName('wr-subject')[0].getElementsByTagName('a')[0].innerText;\n" +
" if(chapterTitle.split('\\n').length > 1) {\n" +
" chapterTitle = chapterTitle.split('\\n')[1];\n" +
" }\n" +
"\n" +
" var bookPageUrl = location.pathname;\n" +
" var bookTitle = document.getElementsByClassName('view-title')[0].getElementsByTagName('span')[0].innerText;\n" +
" var data = {\n" +
" 'chapterID': Number(chapterNum),\n" +
" 'chapterNum': Number(chapterNum),\n" +
" 'pathUrl': pageUrl,\n" +
" 'bookPageUrl': bookPageUrl,\n" +
" 'chapterTitle': chapterTitle,\n" +
" 'bookTitle': bookTitle,\n" +
" };\n" +
" contentsArray.push(\n" +
" data\n" +
" );\n" +
" }\n" +
" \n" +
" if(contentsArray.length > 0) {\n" +
" PAgit.onBookInfo(JSON.stringify({\n" +
" 'bookTitle': bookTitle,\n" +
" 'bookPageUrl': new URL(location.href).pathname,\n" +
" 'pages': contentsArray ,\n" +
" }));\n" +
" }\n" +
"}\n" +
"getList()\n" +
""
}
override fun acccceptResourceKeyword(): String {
return "toki"
}
override fun getNextButtonJs(): String {
return "goNextBtn"
}
override fun getPrevButtonJs(): String {
return "goPrevBtn"
}
override fun getTitleJs(): String {
return "document.getElementsByClassName(\"toon-title\").length > 0 ? document.getElementsByClassName(\"toon-title\")[0].title : null"
}
override fun getFindContentsJs(): String {
return "document.getElementById(\"novel_content\") != null ? document.getElementById(\"novel_content\").innerText : null"
}
override fun checkCorrectContents(contents: String): String {
return if (contents != null && !contents.isNullOrEmpty()) {
contents
} else {
"fail load"
}
}
// "if(document.getElementsByClassName(\"hd_pops\") != null && document.getElementsByClassName(\"hd_pops\").length > 0) document.getElementsByClassName(\"hd_pops\")[0].remove();" +
// "if(document.getElementsByClassName(\"hd_pops\") != null && document.getElementsByClassName(\"hd_pops\").length > 0) document.getElementsByClassName(\"hd_pops\")[0].remove();" +
// "if(document.getElementById(\"main-banner-view\") != null) document.getElementById(\"main-banner-view\").remove();" +
// "if(document.getElementsByClassName(\"board-tail-banner\") != null && document.getElementsByClassName(\"board-tail-banner\").length > 0)document.getElementsByClassName(\"board-tail-banner\")[0].remove();" +
// "if(document.getElementById(\"id_mbv\") != null)document.getElementById(\"id_mbv\").remove();"
override fun onLoadedJs(): String {
return ""
}
}

View File

@ -1,20 +0,0 @@
package com.mime.dualscreenview.webcontents.contentsinfo
typealias ActionByBool = (Boolean) -> Unit
typealias DidFindContents = (String?) -> Unit
typealias GotoSomeWhere = () -> Unit
interface ContentsInfoInterface {
fun getWebcontentsName() : String
fun getNextButtonJs() : String
fun getPrevButtonJs() : String
fun getTitleJs() : String
fun getFindContentsJs() : String
fun checkCorrectContents(contents: String) : String
fun getLastedDoamin() : String
fun onLoadedJs() : String
fun acccceptResourceKeyword() : String
fun getContentsList() : String
}

View File

@ -1,95 +0,0 @@
package com.mime.dualscreenview.webcontents.contentsinfo
import com.mime.dualscreenview.webcontents.BaseWebContents
object NewtokiOne : BaseWebContents() {
override var lastNumber : Int = 351
override fun getWebcontentsName(): String {
return "newtokione"
}
override fun getLastedDoamin(): String {
return "https://newtoki.one"
}
override fun getContentsList(): String {
return "function getList() {\n" +
" const contentsArray = [];\n" +
" var children = document.getElementsByClassName('list-body')[0].children;\n" +
" var maxCount = children.length;\n" +
" for (i= 0; i < maxCount; i++) {\n" +
" var chapterNum = children[i].getElementsByClassName('wr-num')[0].textContent;\n" +
" var pageUrl = children[i].getElementsByClassName('wr-subject')[0].getElementsByTagName('a')[0].href;\n" +
" if (pageUrl != null && pageUrl.length > 0 && pageUrl.startsWith(\"http\")) {\n" +
" pageUrl = new URL(pageUrl).pathname;\n" +
" }\n" +
" var chapterTitle = children[i].getElementsByClassName('wr-subject')[0].getElementsByTagName('a')[0].innerText;\n" +
" if(chapterTitle.split('\\n').length > 1) {\n" +
" chapterTitle = chapterTitle.split('\\n')[1];\n" +
" }\n" +
"\n" +
" var bookPageUrl = location.pathname;\n" +
" var bookTitle = document.getElementsByClassName('view-title')[0].getElementsByTagName('span')[0].innerText;\n" +
" var data = {\n" +
" 'chapterID': Number(chapterNum),\n" +
" 'chapterNum': Number(chapterNum),\n" +
" 'pathUrl': pageUrl,\n" +
" 'bookPageUrl': bookPageUrl,\n" +
" 'chapterTitle': chapterTitle,\n" +
" 'bookTitle': bookTitle,\n" +
" };\n" +
" contentsArray.push(\n" +
" data\n" +
" );\n" +
" }\n" +
" \n" +
" if(contentsArray.length > 0) {\n" +
" PAgit.onBookInfo(JSON.stringify({\n" +
" 'bookTitle': bookTitle,\n" +
" 'bookPageUrl': new URL(location.href).pathname,\n" +
" 'pages': contentsArray ,\n" +
" }));\n" +
" }\n" +
"}\n" +
"getList()\n" +
""
}
override fun acccceptResourceKeyword(): String {
return "toki"
}
override fun getNextButtonJs(): String {
return "goNextBtn"
}
override fun getPrevButtonJs(): String {
return "goPrevBtn"
}
override fun getTitleJs(): String {
return "document.getElementsByClassName(\"toon-title\").length > 0 ? document.getElementsByClassName(\"toon-title\")[0].title : null"
}
override fun getFindContentsJs(): String {
return "document.getElementById(\"novel_content\") != null ? document.getElementById(\"novel_content\").innerText : null"
}
override fun checkCorrectContents(contents: String): String {
return if (contents != null && !contents.isNullOrEmpty()) {
contents
} else {
"fail load"
}
}
// "if(document.getElementsByClassName(\"hd_pops\") != null && document.getElementsByClassName(\"hd_pops\").length > 0) document.getElementsByClassName(\"hd_pops\")[0].remove();" +
// "if(document.getElementsByClassName(\"hd_pops\") != null && document.getElementsByClassName(\"hd_pops\").length > 0) document.getElementsByClassName(\"hd_pops\")[0].remove();" +
// "if(document.getElementById(\"main-banner-view\") != null) document.getElementById(\"main-banner-view\").remove();" +
// "if(document.getElementsByClassName(\"board-tail-banner\") != null && document.getElementsByClassName(\"board-tail-banner\").length > 0)document.getElementsByClassName(\"board-tail-banner\")[0].remove();" +
// "if(document.getElementById(\"id_mbv\") != null)document.getElementById(\"id_mbv\").remove();"
override fun onLoadedJs(): String {
return ""
}
}

View File

@ -1,18 +0,0 @@
function getList() {
var children = document.getElementsByClassName('list-body')[0].children
var maxCount = children.length
const contentsArray = []
for (i= 0; i < maxCount; i++) {
children[i].getElementsByClassName('wr-num')
contentsArray.push(
{
'title' : children[i].text ,
'link' : children[i].value
}
)
}
contentsArray.reverse()
return {'list' :contentsArray}
}
getList()

View File

@ -1,30 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M17.921,1.505a1.5,1.5 0,0 1,-0.44 1.06L9.809,10.237a2.5,2.5 0,0 0,0 3.536l7.662,7.662a1.5,1.5 0,0 1,-2.121 2.121L7.688,15.9a5.506,5.506 0,0 1,0 -7.779L15.36,0.444a1.5,1.5 0,0 1,2.561 1.061Z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6.079,22.5a1.5,1.5 0,0 1,0.44 -1.06l7.672,-7.672a2.5,2.5 0,0 0,0 -3.536L6.529,2.565A1.5,1.5 0,0 1,8.65 0.444l7.662,7.661a5.506,5.506 0,0 1,0 7.779L8.64,23.556A1.5,1.5 0,0 1,6.079 22.5Z"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M2.849,23.55a2.954,2.954 0,0 0,3.266 -0.644L12,17.053l5.885,5.853a2.956,2.956 0,0 0,2.1 0.881,3.05 3.05,0 0,0 1.17,-0.237A2.953,2.953 0,0 0,23 20.779V5a5.006,5.006 0,0 0,-5 -5H6A5.006,5.006 0,0 0,1 5V20.779A2.953,2.953 0,0 0,2.849 23.55Z"/>
</vector>

View File

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape
android:innerRadiusRatio="2.71"
android:thicknessRatio="7.6"
android:shape="ring"
android:useLevel="false"
android:type="sweep">
<solid android:color="#9E9E9E" />
</shape>
</item>
<item android:id="@android:id/progress">
<rotate
android:fromDegrees="270"
android:toDegrees="270">
<shape
android:innerRadiusRatio="2.71"
android:thicknessRatio="7.6"
android:shape="ring"
android:angle="0"
android:type="sweep">
</shape>
</rotate>
</item>
</layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,15 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M256,319.84c-35.35,0 -64,28.65 -64,64v128h128v-128C320,348.49 291.35,319.84 256,319.84z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M362.67,383.84v128H448c35.35,0 64,-28.65 64,-64V253.26c0,-11.08 -4.3,-21.73 -12.01,-29.7l-181.29,-195.99c-31.99,-34.61 -85.98,-36.74 -120.59,-4.75c-1.64,1.52 -3.23,3.1 -4.75,4.75L12.4,223.5C4.45,231.5 -0,242.31 0,253.58v194.26c0,35.35 28.65,64 64,64h85.33v-128c0.4,-58.17 47.37,-105.68 104.07,-107.04C312.01,275.38 362.22,323.7 362.67,383.84z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M256,319.84c-35.35,0 -64,28.65 -64,64v128h128v-128C320,348.49 291.35,319.84 256,319.84z"/>
</vector>

View File

@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -1,15 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M22.713,4.077A2.993,2.993 0,0 0,20.41 3H4.242L4.2,2.649A3,3 0,0 0,1.222 0H1A1,1 0,0 0,1 2h0.222a1,1 0,0 1,0.993 0.883l1.376,11.7A5,5 0,0 0,8.557 19H19a1,1 0,0 0,0 -2H8.557a3,3 0,0 1,-2.82 -2h11.92a5,5 0,0 0,4.921 -4.113l0.785,-4.354A2.994,2.994 0,0 0,22.713 4.077Z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M7,22m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M17,22m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M34.28,384c17.65,30.63 56.78,41.15 87.4,23.5c0.02,-0.01 0.04,-0.02 0.06,-0.04l9.49,-5.48c17.92,15.33 38.52,27.22 60.76,35.07V448c0,35.35 28.65,64 64,64s64,-28.65 64,-64v-10.94c22.24,-7.86 42.84,-19.77 60.76,-35.12l9.54,5.5c30.63,17.67 69.79,7.17 87.47,-23.47c17.67,-30.63 7.17,-69.79 -23.47,-87.47l0,0l-9.47,-5.46c4.26,-23.2 4.26,-46.99 0,-70.19l9.47,-5.46c30.63,-17.67 41.14,-56.83 23.47,-87.47c-17.67,-30.63 -56.83,-41.14 -87.47,-23.47l-9.49,5.48C362.86,94.64 342.25,82.77 320,74.94V64c0,-35.35 -28.65,-64 -64,-64s-64,28.65 -64,64v10.94c-22.24,7.86 -42.84,19.77 -60.76,35.12l-9.54,-5.53C91.07,86.86 51.91,97.37 34.24,128s-7.17,69.79 23.47,87.47l0,0l9.47,5.46c-4.26,23.2 -4.26,46.99 0,70.19l-9.47,5.46C27.16,314.3 16.69,353.38 34.28,384zM256,170.67c47.13,0 85.33,38.21 85.33,85.33S303.13,341.33 256,341.33S170.67,303.13 170.67,256S208.87,170.67 256,170.67z"/>
</vector>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="10dp"/>
<solid android:color="#44ffffff"/>
<stroke android:color="@color/white" android:width="1dp"/>
</shape>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="320dp"
android:layout_gravity="center"
android:layout_height="420dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/style_dialog_title"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="0dp"
android:gravity="center"
android:layout_height="@dimen/main_top_height"/>
<androidx.recyclerview.widget.RecyclerView
app:layout_constraintTop_toBottomOf="@id/style_dialog_title"
android:id="@+id/stylez_recyclerview"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="0dp"
android:layout_height="0dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,182 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:id="@+id/intro_bg"
android:layout_height="match_parent"
tools:context=".activity.Intro">
<WebView
android:id="@+id/hidden_web"
android:layout_margin="60dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<WebView
android:id="@+id/menu_web"
android:layout_margin="20dp"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="@id/btn_left"
app:layout_constraintTop_toBottomOf="@id/textview_title" />
<androidx.constraintlayout.utils.widget.ImageFilterButton
android:id="@+id/btn_home"
android:layout_width="wrap_content"
android:layout_height="@dimen/main_top_height"
android:background="@android:color/transparent"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="@drawable/home"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/textview_title"
android:layout_width="0dp"
android:layout_height="@dimen/main_top_height"
android:text="@string/app_name"
android:gravity="center"
android:textSize="24sp"
app:layout_constraintRight_toLeftOf="@id/btn_list"
app:layout_constraintLeft_toRightOf="@id/btn_home"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.utils.widget.ImageFilterButton
android:background="@android:color/transparent"
android:id="@+id/btn_list"
android:layout_width="wrap_content"
android:layout_height="@dimen/main_top_height"
android:adjustViewBounds="true"
android:scaleType="centerInside"
android:src="@drawable/bookmark"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="@id/textview_title"
app:layout_constraintRight_toLeftOf="@+id/btn_history"
app:layout_constraintHorizontal_chainStyle="spread_inside"
/>
<!-- <androidx.constraintlayout.utils.widget.ImageFilterButton-->
<!-- android:id="@+id/btn_rotate"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="@dimen/main_top_height"-->
<!-- android:adjustViewBounds="true"-->
<!-- android:scaleType="centerInside"-->
<!-- android:visibility="gone"-->
<!-- android:src="@drawable/rotation"-->
<!-- android:background="#8FFF"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- app:layout_constraintLeft_toRightOf="@id/btn_list"-->
<!-- app:layout_constraintRight_toLeftOf="@+id/btn_history"-->
<!-- app:layout_constraintHorizontal_chainStyle="spread_inside"-->
<!-- />-->
<androidx.constraintlayout.utils.widget.ImageFilterButton
android:id="@+id/btn_history"
android:layout_width="wrap_content"
android:layout_height="@dimen/main_top_height"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="@drawable/saved"
android:background="@android:color/transparent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_chainStyle="spread_inside"
/>
<androidx.constraintlayout.utils.widget.ImageFilterButton
android:id="@+id/btn_left"
android:layout_width="wrap_content"
android:background="@android:color/transparent"
android:layout_height="@dimen/main_top_height"
android:tag="1"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:text="@string/display_the_second_screen"
android:visibility="visible"
android:src="@drawable/angle_left"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"
/>
<androidx.constraintlayout.utils.widget.ImageFilterButton
android:id="@+id/btn_setting"
android:layout_width="wrap_content"
android:src="@drawable/settings"
android:layout_height="@dimen/main_top_height"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:background="@android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/btn_left"
app:layout_constraintRight_toLeftOf="@+id/btn_right"
app:layout_constraintHorizontal_chainStyle="spread"
/>
<androidx.constraintlayout.utils.widget.ImageFilterButton
android:id="@+id/btn_right"
android:layout_width="wrap_content"
android:layout_height="@dimen/main_top_height"
android:layout_marginStart="16dp"
android:tag="0"
android:background="@android:color/transparent"
android:src="@drawable/angle_right"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_chainStyle="spread" />
<com.mime.dualscreenview.view.PagedTextLayout
android:id="@+id/paged_layer"
android:layout_margin="1dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
android:elevation="5dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="@id/btn_setting"
app:layout_constraintTop_toBottomOf="@id/textview_title" />
<ProgressBar
android:id="@+id/progress"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_marginTop="48dp"
android:indeterminate="false"
android:max="100"
android:progressBackgroundTint="#FBE7C6"
android:progressDrawable="@drawable/circle_progressbar"
android:progressTint="#edbf41"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Some files were not shown because too many files have changed in this diff Show More