Compare commits
No commits in common. "proto" and "main" have entirely different histories.
63
.gitignore
vendored
63
.gitignore
vendored
@ -1,50 +1,15 @@
|
||||
# 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
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
|
||||
# Generated by Windows
|
||||
Thumbs.db
|
||||
|
||||
# Applications
|
||||
*.app
|
||||
*.exe
|
||||
*.war
|
||||
|
||||
# Large media files
|
||||
*.mp4
|
||||
*.tiff
|
||||
*.avi
|
||||
*.flv
|
||||
*.mov
|
||||
*.wmv
|
||||
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
|
||||
11
README.md
Normal file
11
README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# 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
Normal file
1
app/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
||||
BIN
app/bs_debug.keystore
Normal file
BIN
app/bs_debug.keystore
Normal file
Binary file not shown.
74
app/build.gradle
Normal file
74
app/build.gradle
Normal file
@ -0,0 +1,74 @@
|
||||
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'
|
||||
|
||||
}
|
||||
21
app/proguard-rules.pro
vendored
Normal file
21
app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# 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
|
||||
44
app/src/main/AndroidManifest.xml
Normal file
44
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?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>
|
||||
12
app/src/main/java/com/mime/dualscreenview/BaseAppication.kt
Normal file
12
app/src/main/java/com/mime/dualscreenview/BaseAppication.kt
Normal file
@ -0,0 +1,12 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
181
app/src/main/java/com/mime/dualscreenview/activity/Base.kt
Normal file
181
app/src/main/java/com/mime/dualscreenview/activity/Base.kt
Normal file
@ -0,0 +1,181 @@
|
||||
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
|
||||
|
||||
}
|
||||
981
app/src/main/java/com/mime/dualscreenview/activity/Intro.kt
Normal file
981
app/src/main/java/com/mime/dualscreenview/activity/Intro.kt
Normal file
@ -0,0 +1,981 @@
|
||||
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"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.mime.dualscreenview.activity
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
class Main : Base() {
|
||||
|
||||
}
|
||||
123
app/src/main/java/com/mime/dualscreenview/activity/Settings.kt
Normal file
123
app/src/main/java/com/mime/dualscreenview/activity/Settings.kt
Normal file
@ -0,0 +1,123 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
54
app/src/main/java/com/mime/dualscreenview/common/BLog.kt
Normal file
54
app/src/main/java/com/mime/dualscreenview/common/BLog.kt
Normal file
@ -0,0 +1,54 @@
|
||||
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 -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
84
app/src/main/java/com/mime/dualscreenview/common/Definez.kt
Normal file
84
app/src/main/java/com/mime/dualscreenview/common/Definez.kt
Normal file
@ -0,0 +1,84 @@
|
||||
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
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
168
app/src/main/java/com/mime/dualscreenview/data/HistoryManager.kt
Normal file
168
app/src/main/java/com/mime/dualscreenview/data/HistoryManager.kt
Normal file
@ -0,0 +1,168 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
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 = ""
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
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
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
97
app/src/main/java/com/mime/dualscreenview/dialog/Stylez.kt
Normal file
97
app/src/main/java/com/mime/dualscreenview/dialog/Stylez.kt
Normal file
@ -0,0 +1,97 @@
|
||||
//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()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,815 @@
|
||||
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())
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,5 @@
|
||||
package com.mime.dualscreenview.view
|
||||
|
||||
interface PagedTextGenerateInterface {
|
||||
fun completePagination(pageList: ArrayList<CharSequence>)
|
||||
}
|
||||
@ -0,0 +1,319 @@
|
||||
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)))
|
||||
}
|
||||
}
|
||||
|
||||
263
app/src/main/java/com/mime/dualscreenview/view/PagedTextView.kt
Normal file
263
app/src/main/java/com/mime/dualscreenview/view/PagedTextView.kt
Normal file
@ -0,0 +1,263 @@
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
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()
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
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 = ">"
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
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() }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
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 = "+"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,251 @@
|
||||
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 ""
|
||||
@ -0,0 +1,5 @@
|
||||
//package com.mime.dualscreenview.webcontents
|
||||
//
|
||||
//typealias ActionByBool = (Boolean) -> Unit
|
||||
//typealias DidFindContents = (String?) -> Unit
|
||||
//typealias GotoSomeWhere = () -> Unit
|
||||
@ -0,0 +1,22 @@
|
||||
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)
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,138 @@
|
||||
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();"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
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 ""
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
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
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
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 ""
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
|
||||
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()
|
||||
30
app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Normal file
30
app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<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>
|
||||
9
app/src/main/res/drawable/angle_left.xml
Normal file
9
app/src/main/res/drawable/angle_left.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<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>
|
||||
9
app/src/main/res/drawable/angle_right.xml
Normal file
9
app/src/main/res/drawable/angle_right.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<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>
|
||||
9
app/src/main/res/drawable/bookmark.xml
Normal file
9
app/src/main/res/drawable/bookmark.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<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>
|
||||
27
app/src/main/res/drawable/circle_progressbar.xml
Normal file
27
app/src/main/res/drawable/circle_progressbar.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?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>
|
||||
BIN
app/src/main/res/drawable/history.png
Normal file
BIN
app/src/main/res/drawable/history.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
15
app/src/main/res/drawable/home.xml
Normal file
15
app/src/main/res/drawable/home.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<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>
|
||||
170
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
170
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@ -0,0 +1,170 @@
|
||||
<?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>
|
||||
BIN
app/src/main/res/drawable/invoice.png
Normal file
BIN
app/src/main/res/drawable/invoice.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
BIN
app/src/main/res/drawable/rotation.png
Normal file
BIN
app/src/main/res/drawable/rotation.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
15
app/src/main/res/drawable/saved.xml
Normal file
15
app/src/main/res/drawable/saved.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<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>
|
||||
9
app/src/main/res/drawable/settings.xml
Normal file
9
app/src/main/res/drawable/settings.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<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>
|
||||
6
app/src/main/res/drawable/simple_bg.xml
Normal file
6
app/src/main/res/drawable/simple_bg.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?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>
|
||||
BIN
app/src/main/res/font/cafe24oneprettynight.ttf
Normal file
BIN
app/src/main/res/font/cafe24oneprettynight.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/dovemayo.otf
Normal file
BIN
app/src/main/res/font/dovemayo.otf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/ebs_r.ttf
Normal file
BIN
app/src/main/res/font/ebs_r.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/gabia_solmee.ttf
Normal file
BIN
app/src/main/res/font/gabia_solmee.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/godomaum.ttf
Normal file
BIN
app/src/main/res/font/godomaum.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/jsarirang_hon.otf
Normal file
BIN
app/src/main/res/font/jsarirang_hon.otf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/jsarirang_ppuri.otf
Normal file
BIN
app/src/main/res/font/jsarirang_ppuri.otf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/jsdongkang_regular.otf
Normal file
BIN
app/src/main/res/font/jsdongkang_regular.otf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/kcc_kimhoon.ttf
Normal file
BIN
app/src/main/res/font/kcc_kimhoon.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/kcc_sonkeechung.otf
Normal file
BIN
app/src/main/res/font/kcc_sonkeechung.otf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/kccahnjunggeun.ttf
Normal file
BIN
app/src/main/res/font/kccahnjunggeun.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/kotra_bold.ttf
Normal file
BIN
app/src/main/res/font/kotra_bold.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/kotra_songeulssi.ttf
Normal file
BIN
app/src/main/res/font/kotra_songeulssi.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/kyobo_handwriting_2021sjy.otf
Normal file
BIN
app/src/main/res/font/kyobo_handwriting_2021sjy.otf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/mapoagape.ttf
Normal file
BIN
app/src/main/res/font/mapoagape.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/mapobackpacking.ttf
Normal file
BIN
app/src/main/res/font/mapobackpacking.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/mapodacapo.ttf
Normal file
BIN
app/src/main/res/font/mapodacapo.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/mapodpp.ttf
Normal file
BIN
app/src/main/res/font/mapodpp.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/mapodpp_2.ttf
Normal file
BIN
app/src/main/res/font/mapodpp_2.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/mapoflowerisland.ttf
Normal file
BIN
app/src/main/res/font/mapoflowerisland.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/mapogoldenpier.ttf
Normal file
BIN
app/src/main/res/font/mapogoldenpier.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/mapomaponaru.ttf
Normal file
BIN
app/src/main/res/font/mapomaponaru.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/mapopeacefull.ttf
Normal file
BIN
app/src/main/res/font/mapopeacefull.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/nnsgc_brhp.ttf
Normal file
BIN
app/src/main/res/font/nnsgc_brhp.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/nnsgc_gd_an_gd.ttf
Normal file
BIN
app/src/main/res/font/nnsgc_gd_an_gd.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/nnsgc_md.ttf
Normal file
BIN
app/src/main/res/font/nnsgc_md.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/nnsgc_wsjidyp.ttf
Normal file
BIN
app/src/main/res/font/nnsgc_wsjidyp.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/nnsgc_yjc.ttf
Normal file
BIN
app/src/main/res/font/nnsgc_yjc.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/on_jsuhl.ttf
Normal file
BIN
app/src/main/res/font/on_jsuhl.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/on_jsuhr.ttf
Normal file
BIN
app/src/main/res/font/on_jsuhr.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/on_sbsjl.ttf
Normal file
BIN
app/src/main/res/font/on_sbsjl.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/on_sbsjr.ttf
Normal file
BIN
app/src/main/res/font/on_sbsjr.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/on_treeususimgul.ttf
Normal file
BIN
app/src/main/res/font/on_treeususimgul.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/on_treeususimgul_r.ttf
Normal file
BIN
app/src/main/res/font/on_treeususimgul_r.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/on_wibsr.ttf
Normal file
BIN
app/src/main/res/font/on_wibsr.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/on_wisbl.ttf
Normal file
BIN
app/src/main/res/font/on_wisbl.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/on_ychyuhl.ttf
Normal file
BIN
app/src/main/res/font/on_ychyuhl.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/on_ychyuhr.ttf
Normal file
BIN
app/src/main/res/font/on_ychyuhr.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/ssshinb7.ttf
Normal file
BIN
app/src/main/res/font/ssshinb7.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/taebaek_milkyway.otf
Normal file
BIN
app/src/main/res/font/taebaek_milkyway.otf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/taefont_tsthlml.ttf
Normal file
BIN
app/src/main/res/font/taefont_tsthlml.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/tvn_jguiyg_light.ttf
Normal file
BIN
app/src/main/res/font/tvn_jguiyg_light.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/tvn_jguiyg_medium.ttf
Normal file
BIN
app/src/main/res/font/tvn_jguiyg_medium.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/wandohoper.ttf
Normal file
BIN
app/src/main/res/font/wandohoper.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/ylee_mortal_heart_immortal_memory.ttf
Normal file
BIN
app/src/main/res/font/ylee_mortal_heart_immortal_memory.ttf
Normal file
Binary file not shown.
24
app/src/main/res/layout/dialog_stylesz.xml
Normal file
24
app/src/main/res/layout/dialog_stylesz.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?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>
|
||||
182
app/src/main/res/layout/intro.xml
Normal file
182
app/src/main/res/layout/intro.xml
Normal file
@ -0,0 +1,182 @@
|
||||
<?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
Loading…
x
Reference in New Issue
Block a user