Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef8c51f7a6 |
@@ -1,15 +1,50 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
# These are some examples of commonly ignored file patterns.
|
||||
# You should customize this list as applicable to your project.
|
||||
# Learn more about .gitignore:
|
||||
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore
|
||||
|
||||
# Node artifact files
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
# Compiled Java class files
|
||||
*.class
|
||||
|
||||
# Compiled Python bytecode
|
||||
*.py[cod]
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
|
||||
# Package files
|
||||
*.jar
|
||||
|
||||
# Maven
|
||||
target/
|
||||
dist/
|
||||
|
||||
# JetBrains IDE
|
||||
.idea/
|
||||
|
||||
# Unit test reports
|
||||
TEST*.xml
|
||||
|
||||
# Generated by MacOS
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
|
||||
# Generated by Windows
|
||||
Thumbs.db
|
||||
|
||||
# Applications
|
||||
*.app
|
||||
*.exe
|
||||
*.war
|
||||
|
||||
# Large media files
|
||||
*.mp4
|
||||
*.tiff
|
||||
*.avi
|
||||
*.flv
|
||||
*.mov
|
||||
*.wmv
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# tokkiz
|
||||
|
||||
|
||||
resource from {
|
||||
https://www.flaticon.com/search/2?word=rotate&color=black&shape=fill
|
||||
}
|
||||
한글 폰트 from {
|
||||
https://gongu.copyright.or.kr/gongu/bbs/B0000018/list.do?menuNo=200195
|
||||
https://noonnu.cc/font_page/1075
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/build
|
||||
@@ -1,74 +0,0 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'io.realm.kotlin'
|
||||
// id 'kotlin-android-extensions'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'com.mime.dualscreenview'
|
||||
compileSdk 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.mime.dualscreenview"
|
||||
minSdk 24
|
||||
targetSdk 34
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
signingConfigs {
|
||||
|
||||
debug {
|
||||
storeFile = file("./bs_debug.keystore")
|
||||
storePassword = "android"
|
||||
keyAlias = "androiddebugkey"
|
||||
keyPassword = "android"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
exclude 'resources.arsc'
|
||||
exclude 'AndroidManifest.xml'
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
buildFeatures {
|
||||
dataBinding true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.13.1'
|
||||
implementation 'androidx.collection:collection-ktx:1.4.3'
|
||||
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1'
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
implementation 'com.google.code.gson:gson:2.10.1'
|
||||
|
||||
// implementation files('libs/DualScreen.jar')
|
||||
|
||||
implementation 'io.realm.kotlin:library-base:2.0.0'
|
||||
|
||||
|
||||
|
||||
// testImplementation 'junit:junit:4.13.2'
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.mime.dualscreenview
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.mime.dualscreenview", appContext.packageName)
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android: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: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>
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.mime.dualscreenview
|
||||
|
||||
import android.app.Application
|
||||
import io.realm.kotlin.Realm
|
||||
|
||||
class BaseAppication : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package com.mime.dualscreenview.activity
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.style.RelativeSizeSpan
|
||||
import android.view.Gravity
|
||||
import android.view.KeyEvent
|
||||
import android.view.KeyEvent.KEYCODE_BACK
|
||||
import android.view.KeyEvent.KEYCODE_MEDIA_FAST_FORWARD
|
||||
import android.view.KeyEvent.KEYCODE_MEDIA_NEXT
|
||||
import android.view.KeyEvent.KEYCODE_MEDIA_PREVIOUS
|
||||
import android.view.KeyEvent.KEYCODE_MEDIA_REWIND
|
||||
import android.view.KeyEvent.KEYCODE_VOLUME_DOWN
|
||||
import android.view.KeyEvent.KEYCODE_VOLUME_MUTE
|
||||
import android.view.KeyEvent.KEYCODE_VOLUME_UP
|
||||
import android.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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.mime.dualscreenview.activity
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
class Main : Base() {
|
||||
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
package com.mime.dualscreenview.activity
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.mime.dualscreenview.R
|
||||
import com.mime.dualscreenview.common.PairArray
|
||||
import com.mime.dualscreenview.common.colorz
|
||||
import com.mime.dualscreenview.common.getIndex
|
||||
import com.mime.dualscreenview.common.typesfacez
|
||||
import com.mime.dualscreenview.data.HistoryManager
|
||||
import com.mime.dualscreenview.data.model.ReaderConfig
|
||||
import com.mime.dualscreenview.databinding.SettingsBinding
|
||||
import io.realm.kotlin.UpdatePolicy
|
||||
import io.realm.kotlin.ext.query
|
||||
|
||||
class Settings : Base() {
|
||||
|
||||
lateinit var binding : SettingsBinding
|
||||
var readerConfig : ReaderConfig? = null
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = DataBindingUtil.setContentView(this, R.layout.settings)
|
||||
// setContentView(R.layout.settings)
|
||||
var realm = HistoryManager.openRealm
|
||||
realm.writeBlocking {
|
||||
this.query<ReaderConfig>()?.find()?.let {
|
||||
if (it.size > 0) {
|
||||
readerConfig = copyFromRealm(it.first())
|
||||
} else {
|
||||
readerConfig = ReaderConfig()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
binding.textSize.displayFormat = "글자 크기 : %d"
|
||||
binding.textSize.value = readerConfig?.textSize ?: 14
|
||||
binding.textSize.mValueChange = {
|
||||
binding.preview.textSize = it.toFloat() ;
|
||||
if (readerConfig?.textSize != it) {
|
||||
readerConfig?.textSize = it
|
||||
configSave()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
binding.pagePadding.displayFormat = "페이지 여백 : %d"
|
||||
binding.pagePadding.value = readerConfig?.padding ?: 5
|
||||
binding.pagePadding.mValueChange = {
|
||||
binding.preview.setPadding(it,it,it,it) ;
|
||||
if (readerConfig?.padding != it) {
|
||||
readerConfig?.padding = it
|
||||
configSave()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
binding.letterSpace.displayFormat = "자간 : %d"
|
||||
binding.letterSpace.value = readerConfig?.letterSpace ?: 1
|
||||
binding.letterSpace.mValueChange = {
|
||||
binding.preview.letterSpacing = it.times(0.01).toFloat() ;
|
||||
if (readerConfig?.letterSpace != it) {
|
||||
readerConfig?.letterSpace = it
|
||||
configSave()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
binding.lineSpace.displayFormat = "행간 : %d"
|
||||
binding.lineSpace.value = readerConfig?.lineSpace ?: 1
|
||||
binding.lineSpace.mValueChange = {
|
||||
binding.preview.setLineSpacing(1f, 1f.plus(it.times(0.01f))) ;
|
||||
if (readerConfig?.lineSpace != it) {
|
||||
readerConfig?.lineSpace = it
|
||||
configSave()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
binding.pageTypesface.displayFormat = "폰트 : %s"
|
||||
binding.pageTypesface.titleArray = typesfacez.map { it.first }.toTypedArray()
|
||||
binding.pageTypesface.value = getIndex(typesfacez as PairArray<Any>,readerConfig?.font ?: "")
|
||||
binding.pageTypesface.mValueChange = {
|
||||
val pair = typesfacez.get(it)
|
||||
binding.preview.setTypeface(resources.getFont(pair.second))
|
||||
if (readerConfig?.font != pair.first) {
|
||||
readerConfig?.font = pair.first ?: ""
|
||||
configSave()
|
||||
}
|
||||
}
|
||||
|
||||
binding.pageStyle.displayFormat = "스타일 : %s"
|
||||
binding.pageStyle.titleArray = colorz.map { it.first }.toTypedArray()
|
||||
binding.pageStyle.value = readerConfig?.style ?: 0
|
||||
binding.pageStyle.mValueChange = {
|
||||
val pair = colorz.get(it)
|
||||
binding.preview.setBackgroundColor(Color.parseColor(pair.second.last()))
|
||||
binding.preview.setTextColor(Color.parseColor(pair.second.first()))
|
||||
if (readerConfig?.style != it) {
|
||||
readerConfig?.style = it ?: 0
|
||||
configSave()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun configSave() {
|
||||
var realm = HistoryManager.openRealm
|
||||
realm.writeBlocking {
|
||||
copyToRealm(readerConfig!!, UpdatePolicy.ALL)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.mime.dualscreenview.common
|
||||
|
||||
import android.util.Log
|
||||
import com.mime.dualscreenview.BuildConfig
|
||||
import java.lang.Exception
|
||||
|
||||
|
||||
object Blog {
|
||||
val DEFAULT_TAG = "MyEBook_TAG"
|
||||
enum class BLogType {
|
||||
D,I,E
|
||||
}
|
||||
|
||||
fun LOGD(tag : String = DEFAULT_TAG, log: String){
|
||||
LOG(BLogType.D,tag,log)
|
||||
}
|
||||
|
||||
fun LOGI(tag : String = DEFAULT_TAG, log: String){
|
||||
LOG(BLogType.I,tag,log)
|
||||
}
|
||||
|
||||
fun LOGE(tag : String = DEFAULT_TAG, log: Throwable){
|
||||
LOG(BLogType.E,tag,log.toString())
|
||||
}
|
||||
|
||||
fun LOGE(tag : String = DEFAULT_TAG, log: Exception){
|
||||
LOG(BLogType.E,tag,log.toString())
|
||||
}
|
||||
|
||||
fun LOGE(tag : String = DEFAULT_TAG, log: String){
|
||||
LOG(BLogType.E,tag,log)
|
||||
}
|
||||
|
||||
fun LOGE(log: String){
|
||||
LOG(BLogType.E,DEFAULT_TAG,log)
|
||||
}
|
||||
|
||||
private fun LOG(type : BLogType, tag : String, log : String) {
|
||||
if (BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.contains("debug")) {
|
||||
when(type) {
|
||||
BLogType.D -> {
|
||||
Log.d(tag,log)
|
||||
}
|
||||
BLogType.I -> {
|
||||
Log.i(tag,log)
|
||||
}
|
||||
BLogType.E -> {
|
||||
Log.e(tag,log)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.mime.dualscreenview.common
|
||||
|
||||
import com.mime.dualscreenview.R
|
||||
|
||||
typealias PairArray<T> = Array<Pair<String,T>>
|
||||
val colorz : PairArray<Array<String>> = arrayOf<Pair<String,Array<String>>>(
|
||||
Pair("color set 01",arrayOf<String>("#E1F5FE", "#263238")),
|
||||
Pair("color set 02",arrayOf<String>("#F0F4C3", "#37474F")),
|
||||
Pair("color set 03",arrayOf<String>("#ECEFF1", "#455A64")),
|
||||
Pair("color set 04",arrayOf<String>("#E0F7FA", "#263238")),
|
||||
Pair("color set 05",arrayOf<String>("#F5F5F5", "#263238")),
|
||||
Pair("color set 06",arrayOf<String>("#ECEFF1", "#263238")),
|
||||
Pair("color set 07",arrayOf<String>("#F8BBD0", "#263238")),
|
||||
Pair("color set 08",arrayOf<String>("#E6EE9C", "#455A64")),
|
||||
Pair("color set 09",arrayOf<String>("#CFD8DC", "#455A64")),
|
||||
Pair("color set 10",arrayOf<String>("#FFF59D", "#37474F"))
|
||||
)
|
||||
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),
|
||||
)
|
||||
|
||||
@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
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
package com.mime.dualscreenview.data
|
||||
|
||||
import com.mime.dualscreenview.common.Blog
|
||||
import com.mime.dualscreenview.data.model.BookPageInfo
|
||||
import com.mime.dualscreenview.data.model.BookPageInfos
|
||||
import com.mime.dualscreenview.data.model.HistoryItem
|
||||
import com.mime.dualscreenview.data.model.LastInfo
|
||||
import com.mime.dualscreenview.data.model.ReaderConfig
|
||||
import io.realm.kotlin.Realm
|
||||
import io.realm.kotlin.RealmConfiguration
|
||||
import io.realm.kotlin.UpdatePolicy
|
||||
import io.realm.kotlin.log.LogLevel
|
||||
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 getBooInfo(url : String ,callback : (BookPageInfos?)->Unit) {
|
||||
openRealm.apply{
|
||||
Blog.LOGE("get ${url}" )
|
||||
Blog.LOGE("get ${this.query(BookPageInfo::class).count().find()}" )
|
||||
var bookPageInfo = this.query(BookPageInfo::class).query("pathUrl == $0","${url}").find()
|
||||
if (bookPageInfo != null && bookPageInfo.count() > 0) {
|
||||
Blog.LOGE("get ${bookPageInfo}" )
|
||||
this.query(BookPageInfos::class,"bookPageUrl == $0",bookPageInfo.first().bookPageUrl).find().first().let {
|
||||
Blog.LOGE("get ${it} , ${it?.pages}" )
|
||||
callback.invoke(this.copyFromRealm(it))
|
||||
}
|
||||
} else {
|
||||
callback.invoke(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getBooPageInfo(url : String ,callback : (BookPageInfo?)->Unit) {
|
||||
openRealm.apply{
|
||||
Blog.LOGE("get ${url}" )
|
||||
Blog.LOGE("get ${this.query(BookPageInfo::class).count().find()}" )
|
||||
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(url : String, contents : String) {
|
||||
openRealm.writeBlocking {
|
||||
Blog.LOGE("get ${url}")
|
||||
Blog.LOGE("get ${query(BookPageInfo::class).count().find()}")
|
||||
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(url : String ,callback : (BookPageInfo?)->Unit) {
|
||||
openRealm.apply{
|
||||
Blog.LOGE("getNextPage ${url}" )
|
||||
Blog.LOGE("getNextPage ${this.query(BookPageInfo::class).count().find()}" )
|
||||
var bookPageInfo = this.query(BookPageInfo::class).query("pathUrl == $0","${url}").find()?.first()
|
||||
Blog.LOGE("getNextPage 1 ${bookPageInfo}" )
|
||||
if (bookPageInfo != null) {
|
||||
Blog.LOGE("getNextPage 2 ${bookPageInfo.chapterNum}" )
|
||||
Blog.LOGE("getNextPage 2 ${bookPageInfo.bookPageUrl}" )
|
||||
var results = this.query(BookPageInfo::class).query("chapterNum == $0",bookPageInfo.chapterNum + 1).query("bookPageUrl == $0","${bookPageInfo.bookPageUrl}").find()
|
||||
if(results.size > 0) {
|
||||
results.first().let {
|
||||
Blog.LOGE("getNextPage 2 ${it.pathUrl}" )
|
||||
callback.invoke(it)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getPrevPage(url : String ,callback : (BookPageInfo?)->Unit) {
|
||||
openRealm.apply{
|
||||
Blog.LOGE("getPrevPage ${url}" )
|
||||
Blog.LOGE("getPrevPage ${this.query(BookPageInfo::class).count().find()}" )
|
||||
var bookPageInfo = this.query(BookPageInfo::class).query("pathUrl == $0","${url}").find()?.first()
|
||||
Blog.LOGE("getNextPage ${bookPageInfo}" )
|
||||
if (bookPageInfo != null) {
|
||||
Blog.LOGE("getNextPage 2 ${bookPageInfo.chapterNum}" )
|
||||
Blog.LOGE("getNextPage 2 ${bookPageInfo.bookPageUrl}" )
|
||||
var results = this.query(BookPageInfo::class).query("chapterNum == $0 && bookPageUrl == $1",bookPageInfo.chapterNum - 1,"${bookPageInfo.bookPageUrl}").find()
|
||||
if(results.size > 0) {
|
||||
results.first()?.let {
|
||||
callback.invoke(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
package com.mime.dualscreenview.data.model
|
||||
|
||||
import io.realm.kotlin.ext.realmListOf
|
||||
import io.realm.kotlin.types.RealmList
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.Ignore
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
|
||||
|
||||
|
||||
class BookPageInfosJ {
|
||||
var bookTitle : String = ""
|
||||
var bookPageUrl : String = ""
|
||||
|
||||
var pages : ArrayList<BookPageInfoJ> = arrayListOf<BookPageInfoJ>()
|
||||
|
||||
fun getTitleArray() : ArrayList<String> {
|
||||
var arrayList = ArrayList<String>()
|
||||
pages.forEach { arrayList.add(it.bookTitle ?: "") }
|
||||
return arrayList
|
||||
}
|
||||
|
||||
fun getR() : BookPageInfos{
|
||||
var r = BookPageInfos()
|
||||
r.bookTitle = this.bookTitle
|
||||
r.bookPageUrl = this.bookPageUrl
|
||||
|
||||
return r
|
||||
}
|
||||
}
|
||||
class BookPageInfoJ {
|
||||
var chapterID : Int = 0
|
||||
var contents : String? = ""
|
||||
var bookPageUrl : String? = ""
|
||||
var chapterTitle : String? = ""
|
||||
var bookTitle : String? = ""
|
||||
var chapterNum : Int = 0
|
||||
var lastPage : Int? = 0
|
||||
var pathUrl : String? = ""
|
||||
|
||||
fun getRealm() : BookPageInfo {
|
||||
var r = BookPageInfo()
|
||||
r.chapterID = this.chapterID
|
||||
r.contents = this.contents
|
||||
r.bookPageUrl = this.bookPageUrl ?: ""
|
||||
r.chapterTitle = this.chapterTitle
|
||||
r.bookTitle = this.bookTitle ?: ""
|
||||
r.chapterNum = this.chapterNum
|
||||
r.lastPage = this.lastPage
|
||||
r.pathUrl = this.pathUrl?.replace("'","")
|
||||
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BookPageInfos : RealmObject {
|
||||
|
||||
var bookTitle : String = ""
|
||||
|
||||
@PrimaryKey
|
||||
var bookPageUrl : String? = ""
|
||||
var pages : RealmList<BookPageInfo> = realmListOf()
|
||||
|
||||
fun getTitleArray() : ArrayList<String> {
|
||||
var arrayList = ArrayList<String>()
|
||||
pages.forEach {
|
||||
arrayList.add(it.getTitleItem())}
|
||||
return arrayList
|
||||
}
|
||||
|
||||
fun sort() {
|
||||
val comparator : Comparator<BookPageInfo> = compareBy { it.chapterID }
|
||||
pages.sortWith(comparator)
|
||||
}
|
||||
|
||||
fun hasItem(item: BookPageInfo) : Boolean {
|
||||
var hasItem = false
|
||||
for (c in pages) {
|
||||
if (!hasItem) {
|
||||
hasItem = c.pathUrl.equals(item.pathUrl)
|
||||
}
|
||||
}
|
||||
return hasItem
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
class BookPageInfo : RealmObject {
|
||||
|
||||
var chapterID : Int = 0
|
||||
var contents : String? = ""
|
||||
|
||||
var bookPageUrl : String? = ""
|
||||
var chapterTitle : String? = ""
|
||||
var bookTitle : String? = ""
|
||||
var chapterNum : Int = 0
|
||||
var lastPage : Int? = 0
|
||||
|
||||
@PrimaryKey
|
||||
var pathUrl : String? = ""
|
||||
|
||||
fun getTitleItem() : String {
|
||||
var result = StringBuilder()
|
||||
result.append(if ((contents?.length ?: 0) > 10) {
|
||||
"S:[0] "
|
||||
} else {
|
||||
"[X] "
|
||||
})
|
||||
|
||||
result.append(chapterTitle?: "")
|
||||
|
||||
result.append(if ((lastPage ?: 0) > 0) {
|
||||
" [0] "
|
||||
} else {
|
||||
" [X] "
|
||||
})
|
||||
|
||||
return result.toString()
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.mime.dualscreenview.data.model
|
||||
|
||||
import android.content.pm.ActivityInfo
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
|
||||
|
||||
class LastInfo : RealmObject {
|
||||
@PrimaryKey
|
||||
var _id : String = "UniqLastId"
|
||||
var pageUrl : String = ""
|
||||
var title : String = ""
|
||||
var chapter : Int = 0
|
||||
var pageIndex : Int = 0
|
||||
var contentsName : String = ""
|
||||
var displayOrientation : Int = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
|
||||
fun makeHistoryItem() : HistoryItem = HistoryItem().apply {
|
||||
title = this@LastInfo.title
|
||||
pageUrl = this@LastInfo.pageUrl
|
||||
chapter = this@LastInfo.chapter
|
||||
pageIndex = this@LastInfo.pageIndex
|
||||
contentsName = this@LastInfo.contentsName
|
||||
displayOrientation = this@LastInfo.displayOrientation
|
||||
}
|
||||
}
|
||||
class HistoryItem : RealmObject {
|
||||
@PrimaryKey
|
||||
var title : String = ""
|
||||
var pageUrl : String = ""
|
||||
var chapter : Int = 0
|
||||
var pageIndex : Int = 0
|
||||
var contentsName : String = ""
|
||||
var displayOrientation : Int = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
|
||||
fun makeLastInfo() = LastInfo().apply{
|
||||
_id = "UniqLastId"
|
||||
title = this@HistoryItem.title
|
||||
pageUrl = this@HistoryItem.pageUrl
|
||||
chapter = this@HistoryItem.chapter
|
||||
pageIndex = this@HistoryItem.pageIndex
|
||||
contentsName = this@HistoryItem.contentsName
|
||||
displayOrientation = this@HistoryItem.displayOrientation
|
||||
}
|
||||
fun putHistory(bookPageInfo: BookPageInfo? , currentPath : String) : HistoryItem {
|
||||
title = bookPageInfo?.bookTitle ?: SimpleDateFormat("YY-mm-DD-HH:mm").format(Date())
|
||||
pageUrl = bookPageInfo?.pathUrl ?: ""
|
||||
chapter = bookPageInfo?.chapterNum ?: 0
|
||||
pageIndex = bookPageInfo?.lastPage ?: 0
|
||||
contentsName = bookPageInfo?.chapterTitle ?: ""
|
||||
return this
|
||||
}
|
||||
}
|
||||
class Bookmark() : RealmObject {
|
||||
@PrimaryKey
|
||||
var pageUrl : String = ""
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.mime.dualscreenview.data.model
|
||||
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
|
||||
class ReaderConfig : RealmObject {
|
||||
@PrimaryKey
|
||||
var id : String? = "ReaderConfig"
|
||||
var textSize : Int? = 14
|
||||
var textColor : String? = "#FFFFFF"
|
||||
var bgColor : String? = "#000000"
|
||||
var style : Int? = 0
|
||||
var lineSpace : Int? = 1
|
||||
var letterSpace : Int? = 1
|
||||
var font : String? = ""
|
||||
var padding : Int? = 5
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.mime.dualscreenview.dialog
|
||||
|
||||
import android.R
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.widget.ArrayAdapter
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.mime.dualscreenview.data.model.BookPageInfo
|
||||
|
||||
object DefaultList {
|
||||
fun showDefaultList(context: Context, title : String, items : Collection<BookPageInfo>, firstPosition : Int, choosedTitle : (Int)->String, chooedPositive : (Int)->Unit, saveCalback : (Int)->Unit ) {
|
||||
val builderSingle: AlertDialog.Builder = AlertDialog.Builder(context)
|
||||
builderSingle.setTitle(title)
|
||||
val arrayAdapter =
|
||||
ArrayAdapter<String>(context, R.layout.select_dialog_singlechoice)
|
||||
for (item in items) {
|
||||
arrayAdapter.add(item.getTitleItem())
|
||||
}
|
||||
builderSingle.setNeutralButton("전체 저장") { dialog, which ->
|
||||
saveCalback.invoke(-1)
|
||||
dialog.dismiss()
|
||||
}
|
||||
builderSingle.setNegativeButton("닫기",
|
||||
DialogInterface.OnClickListener { dialog, which ->
|
||||
dialog.dismiss() })
|
||||
builderSingle.setAdapter(arrayAdapter,
|
||||
DialogInterface.OnClickListener { dialog, position ->
|
||||
val strName = arrayAdapter.getItem(position)
|
||||
val builderInner: AlertDialog.Builder = AlertDialog.Builder(context)
|
||||
builderInner.setMessage(strName)
|
||||
builderInner.setTitle(choosedTitle.invoke(position))
|
||||
builderInner.setNegativeButton("닫기") { dialog, which ->
|
||||
|
||||
}
|
||||
// builderInner.setNeutralButton("자동 저장") { dialog, which ->
|
||||
// saveCalback.invoke(position)
|
||||
// }
|
||||
builderInner.setPositiveButton("이동"){ dialog, which ->
|
||||
chooedPositive.invoke(position)
|
||||
dialog.dismiss()
|
||||
}
|
||||
builderInner.show().apply {
|
||||
DialogManager.add(this)
|
||||
}
|
||||
})
|
||||
builderSingle.create()?.apply{
|
||||
setOnShowListener { d->
|
||||
(d as? AlertDialog)?.let{
|
||||
it.listView?.setSelection(firstPosition)
|
||||
}
|
||||
}
|
||||
DialogManager.add(this)
|
||||
}?.show()
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.mime.dualscreenview.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import androidx.activity.ComponentDialog
|
||||
import java.lang.Exception
|
||||
|
||||
object DialogManager {
|
||||
val dialogs = arrayListOf<ComponentDialog>()
|
||||
fun add(item : ComponentDialog) = dialogs.add(item)
|
||||
fun closeAll() {
|
||||
for (dialog in dialogs) {
|
||||
try {
|
||||
dialog?.dismiss()
|
||||
} catch(e : Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
//package com.mime.dualscreenview.dialog
|
||||
//
|
||||
//import android.app.Dialog
|
||||
//import android.content.Context
|
||||
//import android.content.DialogInterface
|
||||
//import android.graphics.Color
|
||||
//import android.os.Bundle
|
||||
//import android.view.LayoutInflater
|
||||
//import android.view.View
|
||||
//import android.view.ViewGroup
|
||||
//import android.view.Window
|
||||
//import android.widget.TextView
|
||||
//import androidx.recyclerview.widget.GridLayoutManager
|
||||
//import androidx.recyclerview.widget.RecyclerView
|
||||
//import com.mime.dualscreenview.R
|
||||
//import kotlin.random.Random
|
||||
//
|
||||
//interface StyleSelectInterface {
|
||||
// fun onSelectStyle(bgColor : String, textColor : String)
|
||||
//}
|
||||
//class Stylez : Dialog {
|
||||
// constructor(context: Context) : super(context) {initView(context)}
|
||||
// constructor(context: Context, themeResId: Int) : super(context, themeResId) {initView(context)}
|
||||
// constructor(
|
||||
// context: Context,
|
||||
// cancelable: Boolean,
|
||||
// cancelListener: DialogInterface.OnCancelListener?
|
||||
// ) : super(context, cancelable, cancelListener) {initView(context)}
|
||||
//
|
||||
// var styleSelectInterface : StyleSelectInterface? = null
|
||||
//
|
||||
// fun initView(context: Context) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// super.onCreate(savedInstanceState)
|
||||
// this.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
// setCancelable(true)
|
||||
// setContentView(R.layout.dialog_stylesz)
|
||||
// val recyclerView: RecyclerView = findViewById(R.id.stylez_recyclerview)
|
||||
// val adapterRe = AdapterRe(context, colorz)
|
||||
// recyclerView.adapter = adapterRe
|
||||
// recyclerView.layoutManager =
|
||||
// GridLayoutManager(context, 2, GridLayoutManager.VERTICAL, false)
|
||||
// }
|
||||
//
|
||||
// inner class AdapterRe(ctx: Context, myImageNameList: Array<Array<String>>) :
|
||||
// RecyclerView.Adapter<StylezViewHolder>() {
|
||||
// private val inflater: LayoutInflater
|
||||
// private val myImageNameList: Array<Array<String>>
|
||||
// private val ctx : Context
|
||||
// init {
|
||||
// inflater = LayoutInflater.from(ctx)
|
||||
// this.ctx = ctx
|
||||
// this.myImageNameList = myImageNameList
|
||||
// }
|
||||
//
|
||||
// override fun onCreateViewHolder (
|
||||
// parent: ViewGroup,
|
||||
// viewType: Int
|
||||
// ): StylezViewHolder {
|
||||
// val view: View = inflater.inflate(R.layout.item_colorz, parent, false)
|
||||
// return StylezViewHolder(view)
|
||||
// }
|
||||
//
|
||||
// override fun onBindViewHolder(holder: StylezViewHolder, position: Int) {
|
||||
// var colorz = myImageNameList.get(position)
|
||||
// var sampleTextz = ctx.resources.getStringArray(R.array.sample_textz)
|
||||
// holder?.setStyle(bgColor = colorz.get(1), textColor = colorz.get(0),sampleTextz.get(Random.nextInt(9876) % sampleTextz.size))
|
||||
// }
|
||||
//
|
||||
//
|
||||
// override fun getItemCount(): Int {
|
||||
// return myImageNameList.size
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// inner class StylezViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
// var textView: TextView
|
||||
// var bg : View
|
||||
// init {
|
||||
// textView = itemView.findViewById(R.id.textview_sample)
|
||||
// bg = itemView.findViewById(R.id.bg_sample)
|
||||
// }
|
||||
// fun setStyle(bgColor : String, textColor : String, sampleText : String ) {
|
||||
// bg.setBackgroundColor(Color.parseColor(bgColor))
|
||||
// textView.setTextColor(Color.parseColor(textColor))
|
||||
// textView.text = sampleText
|
||||
// itemView?.setOnClickListener { v ->
|
||||
// styleSelectInterface?.onSelectStyle(bgColor,textColor)
|
||||
// dismiss()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,815 +0,0 @@
|
||||
package com.mime.dualscreenview.view
|
||||
|
||||
import android.content.Context
|
||||
import android.os.SystemClock
|
||||
import android.util.Log
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.View.OnTouchListener
|
||||
import com.mime.dualscreenview.common.Blog
|
||||
import com.mime.dualscreenview.view.GestureAnalyser.GestureType
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
|
||||
enum class TouchArea {
|
||||
Left,Center,Right, DoubleLeft, DoubleRight
|
||||
}
|
||||
|
||||
class GestureAnalyser @JvmOverloads constructor(
|
||||
swipeSlopeIntolerance: Int = 3,
|
||||
doubleTapMaxDelayMillis: Int = 500,
|
||||
doubleTapMaxDownMillis: Int = 100
|
||||
) {
|
||||
private val initialX = DoubleArray(5)
|
||||
private val initialY = DoubleArray(5)
|
||||
private val finalX = DoubleArray(5)
|
||||
private val finalY = DoubleArray(5)
|
||||
private val currentX = DoubleArray(5)
|
||||
private val currentY = DoubleArray(5)
|
||||
private val delX = DoubleArray(5)
|
||||
private val delY = DoubleArray(5)
|
||||
|
||||
private var numFingers = 0
|
||||
private var initialT: Long = 0
|
||||
private var finalT: Long = 0
|
||||
private var currentT: Long = 0
|
||||
|
||||
private var prevInitialT: Long = 0
|
||||
private var prevFinalT: Long = 0
|
||||
|
||||
private var swipeSlopeIntolerance = 3
|
||||
|
||||
private val doubleTapMaxDelayMillis: Long
|
||||
private val doubleTapMaxDownMillis: Long
|
||||
|
||||
init {
|
||||
this.swipeSlopeIntolerance = swipeSlopeIntolerance
|
||||
this.doubleTapMaxDownMillis = doubleTapMaxDownMillis.toLong()
|
||||
this.doubleTapMaxDelayMillis = doubleTapMaxDelayMillis.toLong()
|
||||
}
|
||||
|
||||
fun trackGesture(ev: MotionEvent) {
|
||||
val n = ev.pointerCount
|
||||
for (i in 0 until n) {
|
||||
initialX[i] = ev.getX(i).toDouble()
|
||||
initialY[i] = ev.getY(i).toDouble()
|
||||
}
|
||||
numFingers = n
|
||||
initialT = SystemClock.uptimeMillis()
|
||||
}
|
||||
|
||||
fun untrackGesture() {
|
||||
numFingers = 0
|
||||
prevFinalT = SystemClock.uptimeMillis()
|
||||
prevInitialT = initialT
|
||||
}
|
||||
|
||||
fun getGesture(ev: MotionEvent): GestureType {
|
||||
var averageDistance = 0.0
|
||||
for (i in 0 until numFingers) {
|
||||
finalX[i] = ev.getX(i).toDouble()
|
||||
finalY[i] = ev.getY(i).toDouble()
|
||||
delX[i] = finalX[i] - initialX[i]
|
||||
delY[i] = finalY[i] - initialY[i]
|
||||
|
||||
averageDistance += sqrt(
|
||||
(finalX[i] - initialX[i]).pow(2.0) + (finalY[i] - initialY[i]).pow(
|
||||
2.0
|
||||
)
|
||||
)
|
||||
}
|
||||
averageDistance /= numFingers.toDouble()
|
||||
|
||||
finalT = SystemClock.uptimeMillis()
|
||||
val gt = GestureType()
|
||||
gt.gestureFlag = calcGesture()
|
||||
gt.gestureDuration = finalT - initialT
|
||||
gt.gestureDistance = averageDistance
|
||||
return gt
|
||||
}
|
||||
|
||||
fun getOngoingGesture(ev: MotionEvent): Int {
|
||||
for (i in 0 until numFingers) {
|
||||
currentX[i] = ev.getX(i).toDouble()
|
||||
currentY[i] = ev.getY(i).toDouble()
|
||||
delX[i] = finalX[i] - initialX[i]
|
||||
delY[i] = finalY[i] - initialY[i]
|
||||
}
|
||||
currentT = SystemClock.uptimeMillis()
|
||||
return calcGesture()
|
||||
}
|
||||
|
||||
private fun calcGesture(): Int {
|
||||
if (isDoubleTap) {
|
||||
return DOUBLE_TAP_1
|
||||
}
|
||||
|
||||
if (numFingers == 1) {
|
||||
if ((-(delY[0])) > (swipeSlopeIntolerance * (abs(
|
||||
delX[0]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_1_UP
|
||||
}
|
||||
|
||||
if (((delY[0])) > (swipeSlopeIntolerance * (abs(
|
||||
delX[0]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_1_DOWN
|
||||
}
|
||||
|
||||
if ((-(delX[0])) > (swipeSlopeIntolerance * (abs(
|
||||
delY[0]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_1_LEFT
|
||||
}
|
||||
|
||||
if (((delX[0])) > (swipeSlopeIntolerance * (abs(
|
||||
delY[0]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_1_RIGHT
|
||||
}
|
||||
}
|
||||
if (numFingers == 2) {
|
||||
if (((-delY[0]) > (swipeSlopeIntolerance * abs(
|
||||
delX[0]
|
||||
))) && ((-delY[1]) > (swipeSlopeIntolerance * abs(
|
||||
delX[1]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_2_UP
|
||||
}
|
||||
if (((delY[0]) > (swipeSlopeIntolerance * abs(
|
||||
delX[0]
|
||||
))) && ((delY[1]) > (swipeSlopeIntolerance * abs(
|
||||
delX[1]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_2_DOWN
|
||||
}
|
||||
if (((-delX[0]) > (swipeSlopeIntolerance * abs(
|
||||
delY[0]
|
||||
))) && ((-delX[1]) > (swipeSlopeIntolerance * abs(
|
||||
delY[1]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_2_LEFT
|
||||
}
|
||||
if (((delX[0]) > (swipeSlopeIntolerance * abs(
|
||||
delY[0]
|
||||
))) && ((delX[1]) > (swipeSlopeIntolerance * abs(
|
||||
delY[1]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_2_RIGHT
|
||||
}
|
||||
if (finalFingDist(0, 1) > 2 * (initialFingDist(0, 1))) {
|
||||
return UNPINCH_2
|
||||
}
|
||||
if (finalFingDist(0, 1) < 0.5 * (initialFingDist(0, 1))) {
|
||||
return PINCH_2
|
||||
}
|
||||
}
|
||||
if (numFingers == 3) {
|
||||
if (((-delY[0]) > (swipeSlopeIntolerance * abs(
|
||||
delX[0]
|
||||
)))
|
||||
&& ((-delY[1]) > (swipeSlopeIntolerance * abs(
|
||||
delX[1]
|
||||
)))
|
||||
&& ((-delY[2]) > (swipeSlopeIntolerance * abs(
|
||||
delX[2]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_3_UP
|
||||
}
|
||||
if (((delY[0]) > (swipeSlopeIntolerance * abs(
|
||||
delX[0]
|
||||
)))
|
||||
&& ((delY[1]) > (swipeSlopeIntolerance * abs(
|
||||
delX[1]
|
||||
)))
|
||||
&& ((delY[2]) > (swipeSlopeIntolerance * abs(
|
||||
delX[2]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_3_DOWN
|
||||
}
|
||||
if (((-delX[0]) > (swipeSlopeIntolerance * abs(
|
||||
delY[0]
|
||||
)))
|
||||
&& ((-delX[1]) > (swipeSlopeIntolerance * abs(
|
||||
delY[1]
|
||||
)))
|
||||
&& ((-delX[2]) > (swipeSlopeIntolerance * abs(
|
||||
delY[2]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_3_LEFT
|
||||
}
|
||||
if (((delX[0]) > (swipeSlopeIntolerance * abs(
|
||||
delY[0]
|
||||
)))
|
||||
&& ((delX[1]) > (swipeSlopeIntolerance * abs(
|
||||
delY[1]
|
||||
)))
|
||||
&& ((delX[2]) > (swipeSlopeIntolerance * abs(
|
||||
delY[2]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_3_RIGHT
|
||||
}
|
||||
|
||||
if ((finalFingDist(0, 1) > 1.75 * (initialFingDist(0, 1)))
|
||||
&& (finalFingDist(1, 2) > 1.75 * (initialFingDist(1, 2)))
|
||||
&& (finalFingDist(2, 0) > 1.75 * (initialFingDist(2, 0)))
|
||||
) {
|
||||
return UNPINCH_3
|
||||
}
|
||||
if ((finalFingDist(0, 1) < 0.66 * (initialFingDist(0, 1)))
|
||||
&& (finalFingDist(1, 2) < 0.66 * (initialFingDist(1, 2)))
|
||||
&& (finalFingDist(2, 0) < 0.66 * (initialFingDist(2, 0)))
|
||||
) {
|
||||
return PINCH_3
|
||||
}
|
||||
}
|
||||
if (numFingers == 4) {
|
||||
if (((-delY[0]) > (swipeSlopeIntolerance * abs(
|
||||
delX[0]
|
||||
)))
|
||||
&& ((-delY[1]) > (swipeSlopeIntolerance * abs(
|
||||
delX[1]
|
||||
)))
|
||||
&& ((-delY[2]) > (swipeSlopeIntolerance * abs(
|
||||
delX[2]
|
||||
)))
|
||||
&& ((-delY[3]) > (swipeSlopeIntolerance * abs(
|
||||
delX[3]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_4_UP
|
||||
}
|
||||
if (((delY[0]) > (swipeSlopeIntolerance * abs(
|
||||
delX[0]
|
||||
)))
|
||||
&& ((delY[1]) > (swipeSlopeIntolerance * abs(
|
||||
delX[1]
|
||||
)))
|
||||
&& ((delY[2]) > (swipeSlopeIntolerance * abs(
|
||||
delX[2]
|
||||
)))
|
||||
&& ((delY[3]) > (swipeSlopeIntolerance * abs(
|
||||
delX[3]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_4_DOWN
|
||||
}
|
||||
if (((-delX[0]) > (swipeSlopeIntolerance * abs(
|
||||
delY[0]
|
||||
)))
|
||||
&& ((-delX[1]) > (swipeSlopeIntolerance * abs(
|
||||
delY[1]
|
||||
)))
|
||||
&& ((-delX[2]) > (swipeSlopeIntolerance * abs(
|
||||
delY[2]
|
||||
)))
|
||||
&& ((-delX[3]) > (swipeSlopeIntolerance * abs(
|
||||
delY[3]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_4_LEFT
|
||||
}
|
||||
if (((delX[0]) > (swipeSlopeIntolerance * abs(
|
||||
delY[0]
|
||||
)))
|
||||
&& ((delX[1]) > (swipeSlopeIntolerance * abs(
|
||||
delY[1]
|
||||
)))
|
||||
&& ((delX[2]) > (swipeSlopeIntolerance * abs(
|
||||
delY[2]
|
||||
)))
|
||||
&& ((delX[3]) > (swipeSlopeIntolerance * abs(
|
||||
delY[3]
|
||||
)))
|
||||
) {
|
||||
return SWIPE_4_RIGHT
|
||||
}
|
||||
if ((finalFingDist(0, 1) > 1.5 * (initialFingDist(0, 1)))
|
||||
&& (finalFingDist(1, 2) > 1.5 * (initialFingDist(1, 2)))
|
||||
&& (finalFingDist(2, 3) > 1.5 * (initialFingDist(2, 3)))
|
||||
&& (finalFingDist(3, 0) > 1.5 * (initialFingDist(3, 0)))
|
||||
) {
|
||||
return UNPINCH_4
|
||||
}
|
||||
if ((finalFingDist(0, 1) < 0.8 * (initialFingDist(0, 1)))
|
||||
&& (finalFingDist(1, 2) < 0.8 * (initialFingDist(1, 2)))
|
||||
&& (finalFingDist(2, 3) < 0.8 * (initialFingDist(2, 3)))
|
||||
&& (finalFingDist(3, 0) < 0.8 * (initialFingDist(3, 0)))
|
||||
) {
|
||||
return PINCH_4
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private fun initialFingDist(fingNum1: Int, fingNum2: Int): Double {
|
||||
return sqrt(
|
||||
(initialX[fingNum1] - initialX[fingNum2]).pow(2.0) + (initialY[fingNum1] - initialY[fingNum2]).pow(
|
||||
2.0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun finalFingDist(fingNum1: Int, fingNum2: Int): Double {
|
||||
return sqrt(
|
||||
(finalX[fingNum1] - finalX[fingNum2]).pow(2.0) + (finalY[fingNum1] - finalY[fingNum2]).pow(
|
||||
2.0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val isDoubleTap: Boolean
|
||||
get() = if (initialT - prevFinalT < doubleTapMaxDelayMillis && finalT - initialT < doubleTapMaxDownMillis && prevFinalT - prevInitialT < doubleTapMaxDownMillis) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
inner class GestureType {
|
||||
var gestureFlag: Int = 0
|
||||
var gestureDuration: Long = 0
|
||||
|
||||
var gestureDistance: Double = 0.0
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val DEBUG: Boolean = true
|
||||
|
||||
// Finished gestures flags
|
||||
const val SWIPE_1_UP: Int = 11
|
||||
const val SWIPE_1_DOWN: Int = 12
|
||||
const val SWIPE_1_LEFT: Int = 13
|
||||
const val SWIPE_1_RIGHT: Int = 14
|
||||
const val SWIPE_2_UP: Int = 21
|
||||
const val SWIPE_2_DOWN: Int = 22
|
||||
const val SWIPE_2_LEFT: Int = 23
|
||||
const val SWIPE_2_RIGHT: Int = 24
|
||||
const val SWIPE_3_UP: Int = 31
|
||||
const val SWIPE_3_DOWN: Int = 32
|
||||
const val SWIPE_3_LEFT: Int = 33
|
||||
const val SWIPE_3_RIGHT: Int = 34
|
||||
const val SWIPE_4_UP: Int = 41
|
||||
const val SWIPE_4_DOWN: Int = 42
|
||||
const val SWIPE_4_LEFT: Int = 43
|
||||
const val SWIPE_4_RIGHT: Int = 44
|
||||
const val PINCH_2: Int = 25
|
||||
const val UNPINCH_2: Int = 26
|
||||
const val PINCH_3: Int = 35
|
||||
const val UNPINCH_3: Int = 36
|
||||
const val PINCH_4: Int = 45
|
||||
const val UNPINCH_4: Int = 46
|
||||
|
||||
const val DOUBLE_TAP_1: Int = 107
|
||||
|
||||
//Ongoing gesture flags
|
||||
const val SWIPING_1_UP: Int = 101
|
||||
const val SWIPING_1_DOWN: Int = 102
|
||||
const val SWIPING_1_LEFT: Int = 103
|
||||
const val SWIPING_1_RIGHT: Int = 104
|
||||
const val SWIPING_2_UP: Int = 201
|
||||
const val SWIPING_2_DOWN: Int = 202
|
||||
const val SWIPING_2_LEFT: Int = 203
|
||||
const val SWIPING_2_RIGHT: Int = 204
|
||||
const val PINCHING: Int = 205
|
||||
const val UNPINCHING: Int = 206
|
||||
private const val TAG = "GestureAnalyser"
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleFingerGestures : OnTouchListener {
|
||||
private var debug = true
|
||||
var consumeTouchEvents: Boolean = false
|
||||
|
||||
protected var tracking: BooleanArray = booleanArrayOf(false, false, false, false, false)
|
||||
private var ga: GestureAnalyser
|
||||
private var onFingerGestureListener: OnFingerGestureListener? = null
|
||||
|
||||
|
||||
/**
|
||||
* Constructor that creates an internal [in.championswimmer.sfg.lib.GestureAnalyser] object as well
|
||||
*/
|
||||
constructor() {
|
||||
ga = GestureAnalyser()
|
||||
}
|
||||
|
||||
constructor(
|
||||
swipeSlopeIntolerance: Int,
|
||||
doubleTapMaxDelayMillis: Int,
|
||||
doubleTapMaxDownMillis: Int
|
||||
) {
|
||||
ga = GestureAnalyser(swipeSlopeIntolerance, doubleTapMaxDelayMillis, doubleTapMaxDownMillis)
|
||||
}
|
||||
|
||||
fun setDebug(debug: Boolean) {
|
||||
this.debug = debug
|
||||
}
|
||||
|
||||
constructor(omfgl: OnFingerGestureListener?) {
|
||||
ga = GestureAnalyser()
|
||||
setOnFingerGestureListener(omfgl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when multi-finger gestures take place
|
||||
*
|
||||
*
|
||||
* <br></br>
|
||||
*
|
||||
*
|
||||
* For the callbacks implemented via this, check the interface [in.championswimmer.sfg.lib.SimpleFingerGestures.OnFingerGestureListener]
|
||||
*
|
||||
*
|
||||
* @param omfgl The callback that will run
|
||||
*/
|
||||
fun setOnFingerGestureListener(omfgl: OnFingerGestureListener?) {
|
||||
onFingerGestureListener = omfgl
|
||||
}
|
||||
|
||||
|
||||
override fun onTouch(view: View, ev: MotionEvent): Boolean {
|
||||
if (debug) Log.d(TAG, "onTouch")
|
||||
when (ev.action and MotionEvent.ACTION_MASK) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
if (debug) Log.d(TAG, "ACTION_DOWN")
|
||||
startTracking(0)
|
||||
ga.trackGesture(ev)
|
||||
return consumeTouchEvents
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP -> {
|
||||
if (debug) Log.d(TAG, "ACTION_UP")
|
||||
if (tracking[0]) {
|
||||
doCallBack(ga.getGesture(ev))
|
||||
}
|
||||
stopTracking(0)
|
||||
ga.untrackGesture()
|
||||
return consumeTouchEvents
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
if (debug) Log.d(TAG, "ACTION_POINTER_DOWN" + " " + "num" + ev.pointerCount)
|
||||
startTracking(ev.pointerCount - 1)
|
||||
ga.trackGesture(ev)
|
||||
return consumeTouchEvents
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_POINTER_UP -> {
|
||||
if (debug) Log.d(TAG, "ACTION_POINTER_UP" + " " + "num" + ev.pointerCount)
|
||||
if (tracking[1]) {
|
||||
doCallBack(ga.getGesture(ev))
|
||||
}
|
||||
stopTracking(ev.pointerCount - 1)
|
||||
ga.untrackGesture()
|
||||
return consumeTouchEvents
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
if (debug) Log.d(TAG, "ACTION_CANCEL")
|
||||
return true
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (debug) Log.d(TAG, "ACTION_MOVE")
|
||||
return consumeTouchEvents
|
||||
}
|
||||
}
|
||||
return consumeTouchEvents
|
||||
}
|
||||
|
||||
private fun doCallBack(mGt: GestureType) {
|
||||
when (mGt.gestureFlag) {
|
||||
GestureAnalyser.SWIPE_1_UP -> onFingerGestureListener!!.onSwipeUp(
|
||||
1,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_1_DOWN -> onFingerGestureListener!!.onSwipeDown(
|
||||
1,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_1_LEFT -> onFingerGestureListener!!.onSwipeLeft(
|
||||
1,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_1_RIGHT -> onFingerGestureListener!!.onSwipeRight(
|
||||
1,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_2_UP -> onFingerGestureListener!!.onSwipeUp(
|
||||
2,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_2_DOWN -> onFingerGestureListener!!.onSwipeDown(
|
||||
2,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_2_LEFT -> onFingerGestureListener!!.onSwipeLeft(
|
||||
2,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_2_RIGHT -> onFingerGestureListener!!.onSwipeRight(
|
||||
2,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.PINCH_2 -> onFingerGestureListener!!.onPinch(
|
||||
2,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.UNPINCH_2 -> onFingerGestureListener!!.onUnpinch(
|
||||
2,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_3_UP -> onFingerGestureListener!!.onSwipeUp(
|
||||
3,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_3_DOWN -> onFingerGestureListener!!.onSwipeDown(
|
||||
3,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_3_LEFT -> onFingerGestureListener!!.onSwipeLeft(
|
||||
3,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_3_RIGHT -> onFingerGestureListener!!.onSwipeRight(
|
||||
3,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.PINCH_3 -> onFingerGestureListener!!.onPinch(
|
||||
3,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.UNPINCH_3 -> onFingerGestureListener!!.onUnpinch(
|
||||
3,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_4_UP -> onFingerGestureListener!!.onSwipeUp(
|
||||
4,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_4_DOWN -> onFingerGestureListener!!.onSwipeDown(
|
||||
4,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_4_LEFT -> onFingerGestureListener!!.onSwipeLeft(
|
||||
4,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.SWIPE_4_RIGHT -> onFingerGestureListener!!.onSwipeRight(
|
||||
4,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.PINCH_4 -> onFingerGestureListener!!.onPinch(
|
||||
4,
|
||||
mGt.gestureDuration,
|
||||
mGt.gestureDistance
|
||||
)
|
||||
|
||||
GestureAnalyser.UNPINCH_4 -> {
|
||||
onFingerGestureListener!!.onUnpinch(4, mGt.gestureDuration, mGt.gestureDistance)
|
||||
onFingerGestureListener!!.onDoubleTap(1)
|
||||
}
|
||||
|
||||
GestureAnalyser.DOUBLE_TAP_1 -> onFingerGestureListener!!.onDoubleTap(1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startTracking(nthPointer: Int) {
|
||||
for (i in 0..nthPointer) {
|
||||
tracking[i] = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopTracking(nthPointer: Int) {
|
||||
for (i in nthPointer until tracking.size) {
|
||||
tracking[i] = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface definition for the callback to be invoked when 2-finger gestures are performed
|
||||
*/
|
||||
interface OnFingerGestureListener {
|
||||
/**
|
||||
* Called when user swipes **up** with two fingers
|
||||
*
|
||||
* @param fingers number of fingers involved in this gesture
|
||||
* @param gestureDuration duration in milliSeconds
|
||||
* @return
|
||||
*/
|
||||
fun onSwipeUp(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
|
||||
|
||||
/**
|
||||
* Called when user swipes **down** with two fingers
|
||||
*
|
||||
* @param fingers number of fingers involved in this gesture
|
||||
* @param gestureDuration duration in milliSeconds
|
||||
* @return
|
||||
*/
|
||||
fun onSwipeDown(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
|
||||
|
||||
/**
|
||||
* Called when user swipes **left** with two fingers
|
||||
*
|
||||
* @param fingers number of fingers involved in this gesture
|
||||
* @param gestureDuration duration in milliSeconds
|
||||
* @return
|
||||
*/
|
||||
fun onSwipeLeft(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
|
||||
|
||||
/**
|
||||
* Called when user swipes **right** with two fingers
|
||||
*
|
||||
* @param fingers number of fingers involved in this gesture
|
||||
* @param gestureDuration duration in milliSeconds
|
||||
* @return
|
||||
*/
|
||||
fun onSwipeRight(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
|
||||
|
||||
/**
|
||||
* Called when user **pinches** with two fingers (bring together)
|
||||
*
|
||||
* @param fingers number of fingers involved in this gesture
|
||||
* @param gestureDuration duration in milliSeconds
|
||||
* @return
|
||||
*/
|
||||
fun onPinch(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
|
||||
|
||||
/**
|
||||
* Called when user **un-pinches** with two fingers (take apart)
|
||||
*
|
||||
* @param fingers number of fingers involved in this gesture
|
||||
* @param gestureDuration duration in milliSeconds
|
||||
* @return
|
||||
*/
|
||||
fun onUnpinch(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean
|
||||
|
||||
fun onDoubleTap(fingers: Int): Boolean
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Will see if these need to be used. For now just returning duration in milliS
|
||||
const val GESTURE_SPEED_SLOW: Long = 1500
|
||||
const val GESTURE_SPEED_MEDIUM: Long = 1000
|
||||
const val GESTURE_SPEED_FAST: Long = 500
|
||||
private const val TAG = "SimpleFingerGestures"
|
||||
}
|
||||
}
|
||||
|
||||
//abstract class OnSwipeTouchListener(val context: Context?) : View.OnTouchListener {
|
||||
// companion object {
|
||||
// private const val SWIPE_DISTANCE_THRESHOLD = 100
|
||||
// private const val SWIPE_VELOCITY_THRESHOLD = 100
|
||||
// }
|
||||
// private val gestureDetector: GestureDetector
|
||||
// abstract fun onSwipeLeft()
|
||||
// abstract fun onSwipeRight()
|
||||
// abstract fun onSwipeDown()
|
||||
// abstract fun onSwipeUp()
|
||||
// abstract fun onSingleTap(area : TouchArea)
|
||||
// abstract fun onDoubleTap(area : TouchArea)
|
||||
//
|
||||
// override fun onTouch(v: View?, event: MotionEvent?): Boolean {
|
||||
// if (event == null) {
|
||||
// return false
|
||||
// }
|
||||
// return gestureDetector.onTouchEvent(event!!)
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
|
||||
//
|
||||
// override fun onDown(e: MotionEvent): Boolean {
|
||||
// return true
|
||||
// }
|
||||
//
|
||||
// override fun onDoubleTapEvent(e: MotionEvent): Boolean {
|
||||
// val width: Int = context?.resources?.displayMetrics?.widthPixels ?: 0
|
||||
// val height: Int = context?.resources?.displayMetrics?.heightPixels ?: 0
|
||||
// var touchArea : TouchArea = TouchArea.Center
|
||||
// if(width > 0 && height > 0) {
|
||||
// val centerAreaSize = width * 0.4
|
||||
// var sideAreaSize = (width - centerAreaSize) * 0.5
|
||||
// if(e.x < sideAreaSize) {
|
||||
// touchArea = TouchArea.DoubleLeft
|
||||
// } else if(e.x > sideAreaSize && e.x < width - sideAreaSize) {
|
||||
//
|
||||
// } else {
|
||||
// touchArea = TouchArea.DoubleRight
|
||||
// }
|
||||
// }
|
||||
// onDoubleTap(touchArea)
|
||||
// return super.onDoubleTapEvent(e)
|
||||
// }
|
||||
//
|
||||
// override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
||||
// val width: Int = context?.resources?.displayMetrics?.widthPixels ?: 0
|
||||
// val height: Int = context?.resources?.displayMetrics?.heightPixels ?: 0
|
||||
// var touchArea : TouchArea = TouchArea.Center
|
||||
// if(width > 0 && height > 0) {
|
||||
// val centerAreaSize = width * 0.4
|
||||
// var sideAreaSize = (width - centerAreaSize) * 0.5
|
||||
// if(e.x < sideAreaSize) {
|
||||
// touchArea = TouchArea.Left
|
||||
// } else if(e.x > sideAreaSize && e.x < width - sideAreaSize) {
|
||||
//
|
||||
// } else {
|
||||
// touchArea = TouchArea.Right
|
||||
// }
|
||||
// }
|
||||
// onSingleTap(touchArea)
|
||||
// return super.onSingleTapConfirmed(e)
|
||||
// }
|
||||
//
|
||||
//// override fun onSingleTapUp(e: MotionEvent): Boolean {
|
||||
////
|
||||
//// return super.onSingleTapUp(e)
|
||||
//// }
|
||||
//
|
||||
// override fun onFling(
|
||||
// e1: MotionEvent?,
|
||||
// e2: MotionEvent,
|
||||
// velocityX: Float,
|
||||
// velocityY: Float
|
||||
// ): Boolean {
|
||||
//Blog.LOGE("e1.pointerCount >> ${e1?.pointerCount}")
|
||||
// Blog.LOGE("e2.pointerCount >> ${e2.pointerCount}")
|
||||
// val distanceX = e2.x - (e1?.x ?: 0f)
|
||||
// val distanceY = e2.y - (e1?.y ?: 0f)
|
||||
// if (Math.abs(distanceX) > Math.abs(distanceY)
|
||||
// && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD
|
||||
// && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
|
||||
// if (distanceX > 0) onSwipeRight() else onSwipeLeft()
|
||||
// return true
|
||||
// } else if (Math.abs(distanceY) > Math.abs(distanceX)
|
||||
// && Math.abs(distanceY) > SWIPE_DISTANCE_THRESHOLD
|
||||
// && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
|
||||
// if (distanceY > 0) onSwipeDown() else onSwipeUp()
|
||||
// return true
|
||||
// } else {
|
||||
//
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
// init {
|
||||
// gestureDetector = GestureDetector(context, GestureListener())
|
||||
// }
|
||||
//}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.mime.dualscreenview.view
|
||||
|
||||
interface PagedTextGenerateInterface {
|
||||
fun completePagination(pageList: ArrayList<CharSequence>)
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
package com.mime.dualscreenview.view
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.Guideline
|
||||
import androidx.core.view.doOnLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.mime.dualscreenview.R
|
||||
import com.mime.dualscreenview.common.Blog
|
||||
|
||||
class PagedTextLayout : ConstraintLayout , PagedTextGenerateInterface {
|
||||
constructor(context: Context) : super(context) {initView(context)}
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {initView(context)}
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
) {initView(context)}
|
||||
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes) {initView(context)}
|
||||
var mainTextView : TextView? = null
|
||||
var sencondTextView : TextView? = null
|
||||
var demp : View? = null
|
||||
var hiddenTextView : PagedTextView? = null
|
||||
var guideLine : Guideline? = null
|
||||
var pageList: ArrayList<CharSequence>? = null
|
||||
var text : String = ""
|
||||
set(new) {
|
||||
Blog.LOGE("field >> ${field}")
|
||||
Blog.LOGE("new >> ${new}")
|
||||
field = new
|
||||
Blog.LOGE("field >> ${field}")
|
||||
hiddenTextView?.setTxtF(field)
|
||||
hiddenTextView?.visibility = VISIBLE
|
||||
}
|
||||
|
||||
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() {
|
||||
// mPagedTextViewInterface?.onTouch(TouchArea.Center)
|
||||
hiddenTextView?.doUpdate()
|
||||
// hanler?.postDelayed(touchTimeover, 3000L)
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,254 +0,0 @@
|
||||
package com.mime.dualscreenview.view
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.os.Build
|
||||
import android.text.Layout
|
||||
import android.text.StaticLayout
|
||||
import android.util.AttributeSet
|
||||
import 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(unit: Int, size: Float) {
|
||||
super.setTextSize(unit, size)
|
||||
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
|
||||
}
|
||||
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)) * 0.8f).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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.mime.dualscreenview.view
|
||||
|
||||
interface PagedTextViewInterface {
|
||||
fun onTouch(touchArea: TouchArea)
|
||||
fun onTimeoverTouch()
|
||||
fun onSwipeLeft(touchCount : Int)
|
||||
fun onSwipeRight(touchCount : Int)
|
||||
fun onSwipeDown(touchCount : Int)
|
||||
fun onSwipeUp(touchCount : Int)
|
||||
fun onLongClick()
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package com.mime.dualscreenview.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.Button
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import com.mime.dualscreenview.R
|
||||
|
||||
class ScopeEditor: SideButtonTextView {
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
)
|
||||
var titleArray : Array<String>? = null
|
||||
set(value) {
|
||||
if(value != null && value.size < 1) {
|
||||
Error("titleArray는 최소 한개 이상이여야됨.")
|
||||
return
|
||||
}
|
||||
field = value
|
||||
maxValue = field!!.size
|
||||
}
|
||||
|
||||
var maxValue : Int = 1
|
||||
set(value) {
|
||||
if (value < 1) {
|
||||
Error("maxValue는 무조건 0보다 커야하눈뎅....")
|
||||
return
|
||||
}
|
||||
field = value
|
||||
}
|
||||
|
||||
override var value : Int = 14
|
||||
set(newValue) {
|
||||
field = newValue
|
||||
text_value?.text = displayFormat.format(titleArray?.get(field) ?:"defulat")
|
||||
mValueChange?.invoke(field)
|
||||
}
|
||||
|
||||
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes)
|
||||
|
||||
|
||||
|
||||
init {
|
||||
// super.i
|
||||
// inflate(context, R.layout.layout_steps_editor,this)
|
||||
btn_decrement?.setOnClickListener { value = Math.abs(value.dec()).rem(maxValue) }
|
||||
btn_increment?.setOnClickListener { value = value.inc().rem(maxValue) }
|
||||
leftButtonTitle = "<"
|
||||
rightButtonTitle = ">"
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package com.mime.dualscreenview.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import com.mime.dualscreenview.R
|
||||
|
||||
import java.lang.Exception
|
||||
|
||||
open class SideButtonTextView : ConstraintLayout {
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
)
|
||||
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes)
|
||||
|
||||
var leftButtonTitle : String = ""
|
||||
set(value) {
|
||||
field = value
|
||||
btn_decrement?.text = field
|
||||
}
|
||||
|
||||
var rightButtonTitle : String = ""
|
||||
set(value) {
|
||||
field = value
|
||||
btn_increment?.text = field
|
||||
}
|
||||
|
||||
open var value : Int = 14
|
||||
set(newValue) {
|
||||
field = newValue
|
||||
text_value?.text = displayFormat.format(field)
|
||||
mValueChange?.invoke(field)
|
||||
}
|
||||
|
||||
var displayFormat = "글자 크기 : %d"
|
||||
set(newValue) {
|
||||
field = newValue
|
||||
try {
|
||||
text_value?.text = displayFormat.format(value)
|
||||
} catch (e : Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var mValueChange : ValueChange? = null
|
||||
set(newValue) {
|
||||
field = newValue
|
||||
if (newValue != null) {
|
||||
newValue(value)
|
||||
}
|
||||
}
|
||||
|
||||
var btn_decrement : AppCompatButton? = null
|
||||
var btn_increment : AppCompatButton? = null
|
||||
var text_value : TextView? = null
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.layout_steps_editor,this)
|
||||
btn_increment = findViewById(R.id.btn_increment)
|
||||
btn_decrement = findViewById(R.id.btn_decrement)
|
||||
text_value = findViewById(R.id.text_value)
|
||||
btn_decrement?.setOnClickListener { value = value.dec() }
|
||||
btn_increment?.setOnClickListener { value = value.inc() }
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.mime.dualscreenview.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import com.mime.dualscreenview.R
|
||||
|
||||
typealias ValueChange = (Int)->Unit
|
||||
|
||||
class StepsEditor : SideButtonTextView {
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
)
|
||||
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
defStyleAttr: Int,
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes)
|
||||
|
||||
init {
|
||||
// inflate(context, R.layout.layout_steps_editor,this)
|
||||
btn_decrement?.setOnClickListener { value = value.dec() }
|
||||
btn_increment?.setOnClickListener { value = value.inc() }
|
||||
leftButtonTitle = "-"
|
||||
rightButtonTitle = "+"
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.mime.dualscreenview.webcontents
|
||||
|
||||
import android.util.Log
|
||||
import android.webkit.*
|
||||
import com.mime.dualscreenview.webcontents.contentsinfo.ActionByBool
|
||||
import com.mime.dualscreenview.webcontents.contentsinfo.ContentsInfoInterface
|
||||
import com.mime.dualscreenview.webcontents.contentsinfo.DidFindContents
|
||||
|
||||
|
||||
abstract class BaseWebContents : ContentsInfoInterface {
|
||||
open var lastNumber : Int = 221
|
||||
var completeAction : ActionByBool? = null
|
||||
val definedActionCount = 5
|
||||
var completeActionCount = 0
|
||||
set(value) {
|
||||
field = value
|
||||
if(field == definedActionCount && completeAction != null) {
|
||||
completeAction?.invoke(true)
|
||||
}
|
||||
}
|
||||
|
||||
fun findListItem(webview: WebView, callBakItems : DidFindContents) {
|
||||
webview.evaluateJavascript(getContentsList()) { result ->
|
||||
callBakItems.invoke(result)
|
||||
}
|
||||
}
|
||||
|
||||
fun doOnloaded(webview: WebView, findContents : DidFindContents, findTitle : DidFindContents, findNextButton : DidFindContents,
|
||||
findPrevButton : 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
package com.mime.dualscreenview.webcontents
|
||||
|
||||
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 com.mime.dualscreenview.common.Blog
|
||||
import com.mime.dualscreenview.data.HistoryManager
|
||||
import com.mime.dualscreenview.data.model.LastInfo
|
||||
import com.mime.dualscreenview.webcontents.contentsinfo.Booktoki
|
||||
import com.mime.dualscreenview.webcontents.contentsinfo.DidFindContents
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.json.JSONObject
|
||||
|
||||
|
||||
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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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 ->
|
||||
Blog.LOGE("last.pageUrl >>> ${last.pageUrl}")
|
||||
currentContentsProvider = WebContentsManger.getBaseWebContentsBy(last.contentsName)
|
||||
// HistoryManager.getBooPageInfo(last.pageUrl,{ page ->
|
||||
// if(page != null){
|
||||
// if(page.contents?.length ?: 0 > 0) {
|
||||
// mainControllInterface?.onLoadedContents(page.contents!!)
|
||||
// } else {
|
||||
// webview.loadUrl(last.pageUrl)
|
||||
// }
|
||||
// } else {
|
||||
if (last.pageUrl.startsWith("https://")) {
|
||||
webview.loadUrl(last.pageUrl)
|
||||
} else {
|
||||
try {
|
||||
var uri = Uri.parse(webview.url)
|
||||
uri.path?.let {
|
||||
webview.loadUrl(uri.toString().replace(it,last.pageUrl))
|
||||
}
|
||||
} catch (e : Exception) {
|
||||
webview.loadUrl(Booktoki.getLastedDoamin().plus("/").plus(last.pageUrl))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// }
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
var alertDialogs : ArrayList<AlertDialog> = arrayListOf()
|
||||
// override fun onReceivedError(
|
||||
// view: WebView?,
|
||||
// request: WebResourceRequest?,
|
||||
// error: WebResourceError?
|
||||
// ) {
|
||||
// super.onReceivedError(view, request, error)
|
||||
// if (error != null && error.errorCode < 0) {
|
||||
//
|
||||
// webview.postDelayed({
|
||||
// val builder = AlertDialog.Builder(webview.context)
|
||||
//
|
||||
//
|
||||
// builder.setTitle("로딩 에러").setMessage("${currentContentsProvider?.getWebcontentsName()} ${currentContentsProvider?.lastNumber?.inc()} 여기로 다시 시도?!!")
|
||||
// builder.setPositiveButton(
|
||||
// "오키 ${currentContentsProvider?.lastNumber?.inc()} 레고!"
|
||||
// ) { dialog, id ->
|
||||
// dialog.dismiss()
|
||||
// currentContentsProvider?.lastNumber = currentContentsProvider?.lastNumber!!.inc()
|
||||
// loadContents(currentContentsProvider!!)
|
||||
// }
|
||||
//
|
||||
// builder.setNegativeButton(
|
||||
// "포기하자"
|
||||
// ) { dialog, id ->
|
||||
// dialog.dismiss()
|
||||
// }
|
||||
// builder.setNeutralButton(
|
||||
// "같은 주소로 다시 도전"
|
||||
// ) { dialog, id ->
|
||||
// loadContents(currentContentsProvider!!)
|
||||
// dialog.dismiss()
|
||||
// }
|
||||
// alertDialogs.add(builder.create())
|
||||
//
|
||||
// alertDialogs.last()?.show()
|
||||
//
|
||||
// },500)
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
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)
|
||||
view?.let {
|
||||
|
||||
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 ?: "")
|
||||
}
|
||||
}
|
||||
currentContentsProvider?.doOnloaded(it , { result ->
|
||||
result?.let { mainControllInterface.onLoadedContents(it) }
|
||||
} , {
|
||||
it?.let { mainControllInterface.onFindTitle(it.replace("\"","")) }
|
||||
}, {btn ->
|
||||
mainControllInterface?.showNextBtn (btn != null){
|
||||
webview?.evaluateJavascript("if(document.getElementById('${currentContentsProvider!!.getNextButtonJs()}') != null) document.getElementById('${currentContentsProvider!!.getNextButtonJs()}').click()") {
|
||||
}
|
||||
}
|
||||
},{btn ->
|
||||
mainControllInterface?.showPrevBtn(btn != null) {
|
||||
webview?.evaluateJavascript("if(document.getElementById('${currentContentsProvider!!.getPrevButtonJs()}') != null) document.getElementById('${currentContentsProvider!!.getPrevButtonJs()}').click()") {
|
||||
}
|
||||
}
|
||||
}, { complete ->
|
||||
if(complete) {
|
||||
mainControllInterface?.completePageLoad(LastInfo().apply {
|
||||
this.pageUrl = url ?: currentContentsProvider?.getLastedDoamin() ?: ""
|
||||
this.contentsName = currentContentsProvider?.getWebcontentsName() ?: ""
|
||||
this.pageIndex = 0
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
//package com.mime.dualscreenview.webcontents
|
||||
//
|
||||
//typealias ActionByBool = (Boolean) -> Unit
|
||||
//typealias DidFindContents = (String?) -> Unit
|
||||
//typealias GotoSomeWhere = () -> Unit
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.mime.dualscreenview.webcontents
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.mime.dualscreenview.webcontents
|
||||
|
||||
import com.mime.dualscreenview.webcontents.contentsinfo.Agit
|
||||
import com.mime.dualscreenview.webcontents.contentsinfo.Booktoki
|
||||
|
||||
object WebContentsManger {
|
||||
val allContentsList : ArrayList<BaseWebContents> = arrayListOf(Booktoki)
|
||||
|
||||
fun getBaseWebContentsBy(name : String) : BaseWebContents {
|
||||
var correctContents : BaseWebContents = Booktoki
|
||||
for (contents in allContentsList) {
|
||||
if(name.equals(contents.getWebcontentsName())) {
|
||||
correctContents = contents
|
||||
break
|
||||
}
|
||||
}
|
||||
return correctContents
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package com.mime.dualscreenview.webcontents.contentsinfo
|
||||
|
||||
import com.mime.dualscreenview.webcontents.BaseWebContents
|
||||
|
||||
object Agit : BaseWebContents() {
|
||||
|
||||
override var lastNumber : Int = 664
|
||||
|
||||
override fun getWebcontentsName(): String {
|
||||
return "Agit"
|
||||
}
|
||||
|
||||
override fun getLastedDoamin(): String {
|
||||
return String.format("https://agit%d.xyz/", lastNumber)
|
||||
}
|
||||
|
||||
override fun getContentsList(): String {
|
||||
return " var datasets = [];\n" +
|
||||
" var pageNum = 0;\n" +
|
||||
" var totalCount = 0;\n" +
|
||||
" var currentIdx = 0;\n" +
|
||||
" function getContentList() {\n" +
|
||||
" \n" +
|
||||
" if(document.getElementById('count_list') != undefined && totalCount <= 0) {\n" +
|
||||
" totalCount = Number(document.getElementById('count_list').textContent);\n" +
|
||||
" console.log(\"totalCount \" + totalCount);\n" +
|
||||
" currentIdx = totalCount;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" var bookTitle = document.getElementsByClassName('pt-2')[1].textContent;\n" +
|
||||
" var bookPageUrl = new URL(location.href).pathname;\n" +
|
||||
" var pages = document.getElementById('id_page_novel_c').childNodes;\n" +
|
||||
" var list = document.getElementById('id_list_novel_c').childNodes;\n" +
|
||||
" console.log(\"list.length >> \" + list.length);\n" +
|
||||
" for (i = 0; i < list.length; i++) {\n" +
|
||||
" var onclickValue = list[i].attributes['onclick'].value;\n" +
|
||||
" var pageUrl = onclickValue.split('location.href=')[1].replace(';', '');\n" +
|
||||
" var chapterTitle = list[i].childNodes[1].children[0].textContent;\n" +
|
||||
" var chapterID = list[i].childNodes[1].getAttribute('data-wr-id-c');\n" +
|
||||
" \n" +
|
||||
" var data = {\n" +
|
||||
" 'chapterID': Number(chapterID),\n" +
|
||||
" 'idx': Number(currentIdx),\n" +
|
||||
" 'pathUrl': pageUrl,\n" +
|
||||
" 'bookPageUrl': bookPageUrl,\n" +
|
||||
" 'chapterTitle': chapterTitle,\n" +
|
||||
" 'bookTitle': bookTitle,\n" +
|
||||
" };\n" +
|
||||
" datasets.push(data);\n" +
|
||||
" currentIdx = currentIdx - 1\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" \n" +
|
||||
" \n" +
|
||||
" var currentTime = 500;\n" +
|
||||
" try { currentTime = new Date().valueOf() % 1000;\n" +
|
||||
" \n" +
|
||||
" } catch (e) {\n" +
|
||||
" \n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" console.log(\"pages.length >> \" + pages.length);\n" +
|
||||
" console.log(\"datasets.length >> \" + datasets.length);\n" +
|
||||
" console.log(\"totalCount >> \" + totalCount);\n" +
|
||||
" console.log(\"pages.length >> \" + pages.length);\n" +
|
||||
" \n" +
|
||||
" if ((pages.length > pageNum) ||\n" +
|
||||
" (totalCount > datasets.length)) {\n" +
|
||||
" pageNum += 1;\n" +
|
||||
" get_data_novel_list_c(pageNum);\n" +
|
||||
" setTimeout(function() {\n" +
|
||||
" getContentList();\n" +
|
||||
" }, 2000 + currentTime);\n" +
|
||||
" } else if ((pages.length == pageNum) ||\n" +
|
||||
" (totalCount > 10 &&\n" +
|
||||
" totalCount == datasets.length)) {\n" +
|
||||
" datasets.sort((a, b) => b.idx < a.idx);\n" +
|
||||
" var i = 0;\n" +
|
||||
" datasets.forEach(function(item) {\n" +
|
||||
" item['chapterNum'] = i;\n" +
|
||||
" i = i + 1;\n" +
|
||||
" } );\n" +
|
||||
" \n" +
|
||||
" PAgit.onBookInfo(JSON.stringify({\n" +
|
||||
" 'bookTitle': bookTitle,\n" +
|
||||
" 'bookPageUrl': new URL(location.href)\n" +
|
||||
" .pathname,\n" +
|
||||
" 'pages': datasets ,\n" +
|
||||
" }));\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" function wait(sec) {\n" +
|
||||
" let start = Date.now(),\n" +
|
||||
" now = start;\n" +
|
||||
" while (now - start < sec * 1000) {\n" +
|
||||
" now = Date.now();\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" getContentList();"
|
||||
}
|
||||
|
||||
override fun acccceptResourceKeyword(): String {
|
||||
return "toki"
|
||||
}
|
||||
|
||||
override fun getNextButtonJs(): String {
|
||||
return "goNextBtn"
|
||||
}
|
||||
|
||||
override fun getPrevButtonJs(): String {
|
||||
return "goPrevBtn"
|
||||
}
|
||||
|
||||
override fun getTitleJs(): String {
|
||||
return "document.getElementsByClassName(\"toon-title\").length > 0 ? document.getElementsByClassName(\"toon-title\")[0].title : null"
|
||||
}
|
||||
|
||||
override fun getFindContentsJs(): String {
|
||||
return "document.getElementById('id_wr_content') != null ? document.getElementById('id_wr_content').innerText : null"
|
||||
}
|
||||
|
||||
override fun checkCorrectContents(contents: String): String {
|
||||
return if (contents != null && !contents.isNullOrEmpty()) {
|
||||
contents
|
||||
} else {
|
||||
"fail load"
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoadedJs(): String {
|
||||
return "if(document.getElementsByClassName(\"hd_pops\") != null && document.getElementsByClassName(\"hd_pops\").length > 0) document.getElementsByClassName(\"hd_pops\")[0].remove();" +
|
||||
"if(document.getElementsByClassName(\"hd_pops\") != null && document.getElementsByClassName(\"hd_pops\").length > 0) document.getElementsByClassName(\"hd_pops\")[0].remove();" +
|
||||
"if(document.getElementById(\"main-banner-view\") != null) document.getElementById(\"main-banner-view\").remove();" +
|
||||
"if(document.getElementsByClassName(\"board-tail-banner\") != null && document.getElementsByClassName(\"board-tail-banner\").length > 0)document.getElementsByClassName(\"board-tail-banner\")[0].remove();" +
|
||||
"if(document.getElementById(\"id_mbv\") != null)document.getElementById(\"id_mbv\").remove();"
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package com.mime.dualscreenview.webcontents.contentsinfo
|
||||
|
||||
import com.mime.dualscreenview.webcontents.BaseWebContents
|
||||
|
||||
object Booktoki : BaseWebContents() {
|
||||
|
||||
override var lastNumber : Int = 350
|
||||
|
||||
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 ""
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.mime.dualscreenview.webcontents.contentsinfo
|
||||
|
||||
|
||||
|
||||
typealias ActionByBool = (Boolean) -> Unit
|
||||
typealias DidFindContents = (String?) -> Unit
|
||||
typealias GotoSomeWhere = () -> Unit
|
||||
|
||||
interface ContentsInfoInterface {
|
||||
fun getWebcontentsName() : String
|
||||
fun getNextButtonJs() : String
|
||||
fun getPrevButtonJs() : String
|
||||
fun getTitleJs() : String
|
||||
fun getFindContentsJs() : String
|
||||
fun checkCorrectContents(contents: String) : String
|
||||
fun getLastedDoamin() : String
|
||||
fun onLoadedJs() : String
|
||||
fun acccceptResourceKeyword() : String
|
||||
fun getContentsList() : String
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
|
||||
function getList() {
|
||||
var children = document.getElementsByClassName('list-body')[0].children
|
||||
var maxCount = children.length
|
||||
const contentsArray = []
|
||||
for (i= 0; i < maxCount; i++) {
|
||||
children[i].getElementsByClassName('wr-num')
|
||||
contentsArray.push(
|
||||
{
|
||||
'title' : children[i].text ,
|
||||
'link' : children[i].value
|
||||
}
|
||||
)
|
||||
}
|
||||
contentsArray.reverse()
|
||||
return {'list' :contentsArray}
|
||||
}
|
||||
getList()
|
||||
@@ -1,30 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M17.921,1.505a1.5,1.5 0,0 1,-0.44 1.06L9.809,10.237a2.5,2.5 0,0 0,0 3.536l7.662,7.662a1.5,1.5 0,0 1,-2.121 2.121L7.688,15.9a5.506,5.506 0,0 1,0 -7.779L15.36,0.444a1.5,1.5 0,0 1,2.561 1.061Z"/>
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M6.079,22.5a1.5,1.5 0,0 1,0.44 -1.06l7.672,-7.672a2.5,2.5 0,0 0,0 -3.536L6.529,2.565A1.5,1.5 0,0 1,8.65 0.444l7.662,7.661a5.506,5.506 0,0 1,0 7.779L8.64,23.556A1.5,1.5 0,0 1,6.079 22.5Z"/>
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M2.849,23.55a2.954,2.954 0,0 0,3.266 -0.644L12,17.053l5.885,5.853a2.956,2.956 0,0 0,2.1 0.881,3.05 3.05,0 0,0 1.17,-0.237A2.953,2.953 0,0 0,23 20.779V5a5.006,5.006 0,0 0,-5 -5H6A5.006,5.006 0,0 0,1 5V20.779A2.953,2.953 0,0 0,2.849 23.55Z"/>
|
||||
</vector>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@android:id/background">
|
||||
<shape
|
||||
android:innerRadiusRatio="2.71"
|
||||
android:thicknessRatio="7.6"
|
||||
android:shape="ring"
|
||||
android:useLevel="false"
|
||||
android:type="sweep">
|
||||
<solid android:color="#9E9E9E" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item android:id="@android:id/progress">
|
||||
<rotate
|
||||
android:fromDegrees="270"
|
||||
android:toDegrees="270">
|
||||
<shape
|
||||
android:innerRadiusRatio="2.71"
|
||||
android:thicknessRatio="7.6"
|
||||
android:shape="ring"
|
||||
android:angle="0"
|
||||
android:type="sweep">
|
||||
</shape>
|
||||
</rotate>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
Before Width: | Height: | Size: 13 KiB |
@@ -1,15 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M256,319.84c-35.35,0 -64,28.65 -64,64v128h128v-128C320,348.49 291.35,319.84 256,319.84z"/>
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M362.67,383.84v128H448c35.35,0 64,-28.65 64,-64V253.26c0,-11.08 -4.3,-21.73 -12.01,-29.7l-181.29,-195.99c-31.99,-34.61 -85.98,-36.74 -120.59,-4.75c-1.64,1.52 -3.23,3.1 -4.75,4.75L12.4,223.5C4.45,231.5 -0,242.31 0,253.58v194.26c0,35.35 28.65,64 64,64h85.33v-128c0.4,-58.17 47.37,-105.68 104.07,-107.04C312.01,275.38 362.22,323.7 362.67,383.84z"/>
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M256,319.84c-35.35,0 -64,28.65 -64,64v128h128v-128C320,348.49 291.35,319.84 256,319.84z"/>
|
||||
</vector>
|
||||
@@ -1,170 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
@@ -1,15 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M22.713,4.077A2.993,2.993 0,0 0,20.41 3H4.242L4.2,2.649A3,3 0,0 0,1.222 0H1A1,1 0,0 0,1 2h0.222a1,1 0,0 1,0.993 0.883l1.376,11.7A5,5 0,0 0,8.557 19H19a1,1 0,0 0,0 -2H8.557a3,3 0,0 1,-2.82 -2h11.92a5,5 0,0 0,4.921 -4.113l0.785,-4.354A2.994,2.994 0,0 0,22.713 4.077Z"/>
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M7,22m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M17,22m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M34.28,384c17.65,30.63 56.78,41.15 87.4,23.5c0.02,-0.01 0.04,-0.02 0.06,-0.04l9.49,-5.48c17.92,15.33 38.52,27.22 60.76,35.07V448c0,35.35 28.65,64 64,64s64,-28.65 64,-64v-10.94c22.24,-7.86 42.84,-19.77 60.76,-35.12l9.54,5.5c30.63,17.67 69.79,7.17 87.47,-23.47c17.67,-30.63 7.17,-69.79 -23.47,-87.47l0,0l-9.47,-5.46c4.26,-23.2 4.26,-46.99 0,-70.19l9.47,-5.46c30.63,-17.67 41.14,-56.83 23.47,-87.47c-17.67,-30.63 -56.83,-41.14 -87.47,-23.47l-9.49,5.48C362.86,94.64 342.25,82.77 320,74.94V64c0,-35.35 -28.65,-64 -64,-64s-64,28.65 -64,64v10.94c-22.24,7.86 -42.84,19.77 -60.76,35.12l-9.54,-5.53C91.07,86.86 51.91,97.37 34.24,128s-7.17,69.79 23.47,87.47l0,0l9.47,5.46c-4.26,23.2 -4.26,46.99 0,70.19l-9.47,5.46C27.16,314.3 16.69,353.38 34.28,384zM256,170.67c47.13,0 85.33,38.21 85.33,85.33S303.13,341.33 256,341.33S170.67,303.13 170.67,256S208.87,170.67 256,170.67z"/>
|
||||
</vector>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="320dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_height="420dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<TextView
|
||||
android:id="@+id/style_dialog_title"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_width="0dp"
|
||||
android:gravity="center"
|
||||
android:layout_height="@dimen/main_top_height"/>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
app:layout_constraintTop_toBottomOf="@id/style_dialog_title"
|
||||
android:id="@+id/stylez_recyclerview"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,181 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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>
|
||||
<!--//style="@style/Widget.AppCompat.ProgressBar.Horizontal"-->
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="150dp"
|
||||
android:layout_margin="2.5dp"
|
||||
android:id="@+id/bg_sample"
|
||||
android:layout_height="140dp">
|
||||
<TextView
|
||||
android:gravity="center"
|
||||
android:text=""
|
||||
android:textAlignment="center"
|
||||
android:id="@+id/textview_sample"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<TextView
|
||||
android:id="@+id/setting_title"
|
||||
android:textAlignment="center"
|
||||
android:gravity="center"
|
||||
android:text="Setting"
|
||||
android:fontFamily="@font/jsdongkang_regular"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/setting_item_height"/>
|
||||
<CheckBox
|
||||
android:id="@+id/custom_style"
|
||||
app:layout_constraintTop_toTopOf="@+id/setting_title"
|
||||
app:layout_constraintBottom_toBottomOf="@id/setting_title"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="5dp"
|
||||
android:layout_height="match_parent">
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btn_decrement"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="-"
|
||||
android:padding="0dp"
|
||||
android:textSize="20dp"
|
||||
android:fontFamily="@font/jsdongkang_regular"
|
||||
android:background="@color/button_color"
|
||||
android:backgroundTint="@color/button_color_tint"
|
||||
app:layout_constraintEnd_toStartOf="@+id/text_value"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/text_value"
|
||||
android:layout_width="0dp"
|
||||
android:gravity="center"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="14dp"
|
||||
android:fontFamily="@font/jsdongkang_regular"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_increment"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/btn_decrement" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btn_increment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/button_color"
|
||||
android:text="+"
|
||||
android:padding="0dp"
|
||||
android:textSize="20dp"
|
||||
android:fontFamily="@font/jsdongkang_regular"
|
||||
android:backgroundTint="@color/button_color_tint"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/text_value" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="5dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_margin="5dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<com.mime.dualscreenview.view.PagedTextView
|
||||
android:layout_margin="5dp"
|
||||
android:id="@+id/hidden_view"
|
||||
android:visibility="visible"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="false"
|
||||
android:lineSpacingExtra="0dp"
|
||||
style="@style/sss"
|
||||
android:layout_height="match_parent"/>
|
||||
<View
|
||||
android:id="@+id/demp"
|
||||
android:visibility="gone"
|
||||
android:layout_margin="5dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_margin="5dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:layout_margin="5dp"
|
||||
android:gravity="start"
|
||||
android:includeFontPadding="false"
|
||||
android:id="@+id/first_view"
|
||||
android:lineSpacingExtra="0dp"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
style="@style/sss"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:layout_margin="5dp"
|
||||
android:gravity="start"
|
||||
android:includeFontPadding="false"
|
||||
android:lineSpacingExtra="0dp"
|
||||
android:visibility="gone"
|
||||
android:id="@+id/sencond_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
style="@style/sss"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/current_chapter"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
<TextView
|
||||
android:id="@+id/current_page"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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:layout_height="match_parent"
|
||||
tools:context=".activity.Main">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_desc"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,63 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout>
|
||||
<data>
|
||||
|
||||
</data>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/vertical_guide"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_percent="0.5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:layout_margin="5dp"
|
||||
android:includeFontPadding="false"
|
||||
android:lineSpacingExtra="0dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:id="@+id/preview"
|
||||
android:text="@string/preview_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"/>
|
||||
<ScrollView
|
||||
android:id="@+id/config_setting"
|
||||
android:background="#99444444"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/vertical_guide"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<include layout="@layout/item_setting_title"/>
|
||||
<com.mime.dualscreenview.view.StepsEditor
|
||||
android:id="@+id/text_size"
|
||||
style="@style/StepsEditorStyle" />
|
||||
<com.mime.dualscreenview.view.StepsEditor
|
||||
android:id="@+id/letter_space"
|
||||
style="@style/StepsEditorStyle" />
|
||||
<com.mime.dualscreenview.view.StepsEditor
|
||||
android:id="@+id/line_space"
|
||||
style="@style/StepsEditorStyle" />
|
||||
<com.mime.dualscreenview.view.StepsEditor
|
||||
android:id="@+id/page_padding"
|
||||
style="@style/StepsEditorStyle" />
|
||||
<com.mime.dualscreenview.view.ScopeEditor
|
||||
android:id="@+id/page_typesface"
|
||||
style="@style/StepsEditorStyle" />
|
||||
<com.mime.dualscreenview.view.ScopeEditor
|
||||
android:id="@+id/page_style"
|
||||
style="@style/StepsEditorStyle" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 982 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -1,85 +0,0 @@
|
||||
setTimeout(function(){ function invokeSaveAsDialog(file, fileName) {
|
||||
|
||||
if (!file) {
|
||||
|
||||
throw 'Blob object is required.';
|
||||
|
||||
}
|
||||
|
||||
if (!file.type) {
|
||||
|
||||
try {
|
||||
|
||||
file.type = 'video/webm';
|
||||
|
||||
} catch (e) {}
|
||||
|
||||
}
|
||||
|
||||
var fileExtension = (file.type || 'video/webm').split('/')[1];
|
||||
|
||||
if (fileName && fileName.indexOf('.') !== -1) {
|
||||
|
||||
var splitted = fileName.split('.');
|
||||
|
||||
fileName = splitted[0];
|
||||
|
||||
fileExtension = splitted[1];
|
||||
|
||||
}
|
||||
|
||||
var fileFullName = (fileName || (Math.round(Math.random() * 9999999999) + 888888888)) + '.' + fileExtension;
|
||||
|
||||
if (typeof navigator.msSaveOrOpenBlob !== 'undefined') {
|
||||
|
||||
return navigator.msSaveOrOpenBlob(file, fileFullName);
|
||||
|
||||
} else if (typeof navigator.msSaveBlob !== 'undefined') {
|
||||
|
||||
return navigator.msSaveBlob(file, fileFullName);
|
||||
|
||||
}
|
||||
|
||||
var hyperlink = document.createElement('a');
|
||||
|
||||
hyperlink.href = URL.createObjectURL(file);
|
||||
|
||||
hyperlink.download = fileFullName;
|
||||
|
||||
hyperlink.style = 'display:none;opacity:0;color:transparent;';
|
||||
|
||||
(document.body || document.documentElement).appendChild(hyperlink);
|
||||
|
||||
if (typeof hyperlink.click === 'function') {
|
||||
|
||||
hyperlink.click();
|
||||
|
||||
} else {
|
||||
|
||||
hyperlink.target = '_blank';
|
||||
|
||||
hyperlink.dispatchEvent(new MouseEvent('click', {
|
||||
|
||||
view: window,
|
||||
|
||||
bubbles: true,
|
||||
|
||||
cancelable: true
|
||||
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
(window.URL || window.webkitURL).revokeObjectURL(hyperlink.href);
|
||||
|
||||
}
|
||||
|
||||
var textFile = new Blob([document.getElementById("novel_content").innerText], {
|
||||
|
||||
type: 'text/plain'
|
||||
|
||||
});
|
||||
|
||||
invokeSaveAsDialog(textFile, document.getElementsByClassName('toon-title')[0].title +'.txt')
|
||||
|
||||
document.getElementById('goNextBtn').click() }, 2000)
|
||||
@@ -1,18 +0,0 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.DualScreenView" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/black</item>
|
||||
<item name="colorPrimaryVariant">@color/black</item>
|
||||
<item name="colorOnPrimary">@color/black</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorSecondaryVariant">@color/teal_200</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="purple_200">#FFBB86FC</color>
|
||||
<color name="purple_500">#FF6200EE</color>
|
||||
<color name="purple_700">#FF3700B3</color>
|
||||
<color name="teal_200">#FF03DAC5</color>
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="button_color">#994CAF50</color>
|
||||
<color name="button_color_tint">#99007ACC</color>
|
||||
</resources>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="main_top_height">40dp</dimen>
|
||||
<dimen name="textview_padding">15dp</dimen>
|
||||
<dimen name="setting_item_height">45dp</dimen>
|
||||
</resources>
|
||||
@@ -1,72 +0,0 @@
|
||||
<resources>
|
||||
<string name="app_name">Bum\'s App</string>
|
||||
<string name="display_the_second_screen">화면 옮 기 기</string>
|
||||
<string name="main_desc">it\'s 두번째화면</string>
|
||||
<string name="preview_text"><![CDATA[여섯글자마다 방점을찍어놔가사관찰하다 반쯤놓치거나해석잘안되면 몇번돌리든가이건이를테면 덤비는리듬과손묶인채붙는 일종의노름판\n신도구제불능 내가물오른밤감방에날가둬 내가패를까도가난한니네가 판돈잃지않게나하고니네가 의견일치한게아마처음일걸 그마저운일걸\n존나좋음이퀄 내중저음일걸이배열어쩌면 너에대한배려너에겐어쩌면 언어적배리어그럼넌글렀어 지망생여기에잠들다글로써 훗날니묘비에\n\nFor sale my rhymes never usedFor sale my rhymes never used판매자바로너 니가씨발오너For sale my rhymes never used\n\n노예처럼일해서왕처럼지배성탄처럼지내설탕뿌려위에성공을말했기에난그길위에선딱그어이젠자봐주의깊게\n멈칫할시간도없는듯써내려활자로활짝갠곳에돈비내려초라한핀조명과낮은무대위목표를조준하기에충분했지\n시인의신이될준비는치밀해흘러군침이계속이기기위해처음시작했던이유따윈잊어\n맨발맨손으로역사들을빚어미안해난비션갖고와내기적자음모음이어리듬위에띄어금은보화이쁜걸로손에끼워\n\nUh she suckin\' my soul likeDe La to the SoulI shout out to the RhondaBut before I\'m sober\n변태는 변태인데 underground 모범생맨날 난 오덕 돼 활자에 꼬여내 팔자도 고쳐낼 하나의 초월체를만들려 고쳐댄 rhyme들만 몇 truck 돼\n그러다 깨어나 여기에빼어난 묘기에 없네 기본기내 눈엔 수명이 대본처럼 읽히네뭐처럼 비치네 뭐처럼 비치네\nFuck all of ya list manIf it ain\'t Forbes list mayneYour wristwatch cheaper thanMy profile picture damn\nPicture the future and믿어 like it\'s happendBig ass house foreign cars have several\n미녀 fine ass apple hip 내 옆에 같이 태우고Top of the top으로 가 죽어야 들어 잠은넌 안 죽었다는 척갖은 폼 잡으면 뭐하냐\n좆밥들 또 반년만 가면 쏙다 들어가는 거 다 보여내 눈엔 너가 금방 죽어다음 무덤 안 들어갈 주검한 우물 파는 넌 밟고서땅을 쳐봐 내 발자국을\n]]></string>
|
||||
|
||||
<string-array name="sample_textz">
|
||||
<item>여섯글자마다 방점을찍어놔
|
||||
가사관찰하다 반쯤놓치거나
|
||||
해석잘안되면 몇번돌리든가
|
||||
이건이를테면 덤비는리듬과
|
||||
손묶인채붙는 일종의노름판</item>
|
||||
<item>신도구제불능 내가물오른밤
|
||||
감방에날가둬 내가패를까도
|
||||
가난한니네가 판돈잃지않게
|
||||
나하고니네가 의견일치한게
|
||||
아마처음일걸 그마저운일걸</item>
|
||||
<item>존나좋음이퀄 내중저음일걸
|
||||
이배열어쩌면 너에대한배려
|
||||
너에겐어쩌면 언어적배리어
|
||||
그럼넌글렀어 지망생여기에
|
||||
잠들다글로써 훗날니묘비에</item>
|
||||
<item>For sale my rhymes never used
|
||||
For sale my rhymes never used
|
||||
판매자바로너 니가씨발오너
|
||||
For sale my rhymes never used</item>
|
||||
<item>노예처럼일해서왕처럼지배
|
||||
성탄처럼지내설탕뿌려위에
|
||||
성공을말했기에난그길위에
|
||||
선딱그어이젠자봐주의깊게</item>
|
||||
<item>멈칫할시간도없는듯써내려
|
||||
활자로활짝갠곳에돈비내려
|
||||
초라한핀조명과낮은무대위
|
||||
목표를조준하기에충분했지</item>
|
||||
<item>시인의신이될준비는치밀해
|
||||
흘러군침이계속이기기위해
|
||||
처음시작했던이유따윈잊어</item>
|
||||
<item>맨발맨손으로역사들을빚어
|
||||
미안해난비션갖고와내기적
|
||||
자음모음이어리듬위에띄어
|
||||
금은보화이쁜걸로손에끼워</item>
|
||||
<item>Uh she suckin\' my soul like
|
||||
De La to the Soul
|
||||
I shout out to the Rhonda
|
||||
But before I\'m sober</item>
|
||||
<item>변태는 변태인데 underground 모범생
|
||||
맨날 난 오덕 돼 활자에 꼬여
|
||||
내 팔자도 고쳐낼 하나의 초월체를
|
||||
만들려 고쳐댄 rhyme들만 몇 truck 돼</item>
|
||||
<item>그러다 깨어나 여기에
|
||||
빼어난 묘기에 없네 기본기
|
||||
내 눈엔 수명이 대본처럼 읽히네
|
||||
뭐처럼 비치네 뭐처럼 비치네</item>
|
||||
<item>Fuck all of ya list man
|
||||
If it ain\'t Forbes list mayne
|
||||
Your wristwatch cheaper than
|
||||
My profile picture damn</item>
|
||||
<item>Picture the future and
|
||||
믿어 like it\'s happend
|
||||
Big ass house foreign cars have several</item>
|
||||
<item>미녀 fine ass apple hip 내 옆에 같이 태우고
|
||||
Top of the top으로 가 죽어야 들어 잠은
|
||||
넌 안 죽었다는 척
|
||||
갖은 폼 잡으면 뭐하냐</item>
|
||||
<item>좆밥들 또 반년만 가면 쏙
|
||||
다 들어가는 거 다 보여
|
||||
내 눈엔 너가 금방 죽어
|
||||
다음 무덤 안 들어갈 주검
|
||||
한 우물 파는 넌 밟고서
|
||||
땅을 쳐봐 내 발자국을</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="sss">
|
||||
<item name="android:statusBarColor" tools:targetApi="l">@color/black</item>
|
||||
<item name="android:fontFamily">@font/kcc_sonkeechung</item>
|
||||
<item name="android:textSize">14dp</item>
|
||||
<item name="android:textAlignment">textStart</item>
|
||||
</style>
|
||||
<style name="StepsEditorStyle">
|
||||
<item name="android:statusBarColor" tools:targetApi="l">@color/black</item>
|
||||
<item name="android:layout_width">match_parent</item>>
|
||||
<item name="android:layout_height">@dimen/setting_item_height</item>>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,18 +0,0 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.DualScreenView" parent="Theme.MaterialComponents.NoActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<item name="colorPrimary">@color/black</item>
|
||||
<item name="colorPrimaryVariant">@color/black</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorSecondaryVariant">@color/teal_700</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor">?attr/colorOnSecondary</item>
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample backup rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/guide/topics/data/autobackup
|
||||
for details.
|
||||
Note: This file is ignored for devices older that API 31
|
||||
See https://developer.android.com/about/versions/12/backup-restore
|
||||
-->
|
||||
<full-backup-content>
|
||||
<!--
|
||||
<include domain="sharedpref" path="."/>
|
||||
<exclude domain="sharedpref" path="device.xml"/>
|
||||
-->
|
||||
</full-backup-content>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample data extraction rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||
for details.
|
||||
-->
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
-->
|
||||
</cloud-backup>
|
||||
<!--
|
||||
<device-transfer>
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
</device-transfer>
|
||||
-->
|
||||
</data-extraction-rules>
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.mime.dualscreenview
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id 'com.android.application' version '8.5.2' apply false
|
||||
id 'com.android.library' version '8.5.2' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '2.0.0' apply false
|
||||
id 'io.realm.kotlin' version '2.0.0' apply false
|
||||
}
|
||||
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
#android.useNewApkCreator=false
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
android.nonFinalResIds=false
|
||||
@@ -1,249 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
@@ -1,92 +0,0 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -1,16 +0,0 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
rootProject.name = "Bum's App"
|
||||
include ':app'
|
||||