This commit is contained in:
lunaticbum 2024-08-01 18:04:10 +09:00
parent 4c620872af
commit aa4fec37cf
14 changed files with 1182 additions and 117 deletions

View File

@ -52,7 +52,7 @@ dependencies {
implementation 'com.google.android.material:material:1.8.0' implementation 'com.google.android.material:material:1.8.0'
implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.google.code.gson:gson:2.10.1'
implementation files('libs/DualScreen.jar') // implementation files('libs/DualScreen.jar')
implementation 'io.realm.kotlin:library-base:1.6.0' implementation 'io.realm.kotlin:library-base:1.6.0'

View File

@ -1,13 +1,9 @@
package com.mime.dualscreenview.activity package com.mime.dualscreenview.activity
import android.app.ActivityOptions
import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Color import android.graphics.Bitmap
import android.hardware.display.DisplayManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@ -18,13 +14,14 @@ import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
import android.view.View import android.view.View
import android.view.View.* import android.view.View.*
import android.webkit.WebSettings
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.EditText import android.widget.EditText
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ProgressBar import android.widget.ProgressBar
import android.widget.TextView import android.widget.TextView
import android.widget.Toast
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.AppCompatButton import androidx.appcompat.widget.AppCompatButton
@ -49,16 +46,14 @@ import com.mime.dualscreenview.view.TouchArea
import com.mime.dualscreenview.webcontents.BaseWebContentsViewer import com.mime.dualscreenview.webcontents.BaseWebContentsViewer
import com.mime.dualscreenview.webcontents.MainControllInterface import com.mime.dualscreenview.webcontents.MainControllInterface
import com.mime.dualscreenview.webcontents.contentsinfo.Agit import com.mime.dualscreenview.webcontents.contentsinfo.Agit
import com.mime.dualscreenview.webcontents.contentsinfo.Booktoki
import com.mime.dualscreenview.webcontents.contentsinfo.GotoSomeWhere import com.mime.dualscreenview.webcontents.contentsinfo.GotoSomeWhere
import io.realm.kotlin.Realm
import io.realm.kotlin.UpdatePolicy import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.copyFromRealm import io.realm.kotlin.ext.copyFromRealm
import io.realm.kotlin.ext.query import io.realm.kotlin.ext.query
import io.realm.kotlin.query.find
import java.lang.System.currentTimeMillis import java.lang.System.currentTimeMillis
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import kotlin.random.Random
class Intro : Base() , MainControllInterface, PagedTextViewInterface { class Intro : Base() , MainControllInterface, PagedTextViewInterface {
@ -72,6 +67,7 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
var lastInfo : LastInfo? = null var lastInfo : LastInfo? = null
lateinit var paged_layer : PagedTextLayout lateinit var paged_layer : PagedTextLayout
lateinit var textview_title : TextView lateinit var textview_title : TextView
var currentBooinfo : BookPageInfo? = null
val handle = object : Handler() { val handle = object : Handler() {
override fun handleMessage(msg: Message) { override fun handleMessage(msg: Message) {
// super.handleMessage(msg) // super.handleMessage(msg)
@ -79,7 +75,6 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
(msg.obj as? ReaderConfig)?.let { (msg.obj as? ReaderConfig)?.let {
} }
} }
} }
} }
@ -89,12 +84,19 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
Blog.LOGD(log= "onConfigurationChanged ${this::class.java.name} >> newConfig ${newConfig}") Blog.LOGD(log= "onConfigurationChanged ${this::class.java.name} >> newConfig ${newConfig}")
mBaseWebContentsViewer.webview.reload() mBaseWebContentsViewer.webview.reload()
} }
var contentsSaver : WebView? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Blog.LOGD(log= "onCreate ${this::class.java.name} >> savedInstanceState ${savedInstanceState}") Blog.LOGD(log= "onCreate ${this::class.java.name} >> savedInstanceState ${savedInstanceState}")
setContentView(R.layout.intro) setContentView(R.layout.intro)
findViewById<WebView>(R.id.menu_web)?.let {
mBaseWebContentsViewer = BaseWebContentsViewer(findViewById<WebView>(R.id.menu_web),this) it.setOnLongClickListener {
onTouch(TouchArea.Center)
return@setOnLongClickListener false
}
mBaseWebContentsViewer = BaseWebContentsViewer(it,this)
}
paged_layer =findViewById<PagedTextLayout>(R.id.paged_layer) paged_layer =findViewById<PagedTextLayout>(R.id.paged_layer)
textview_title =findViewById<TextView>(R.id.textview_title) textview_title =findViewById<TextView>(R.id.textview_title)
@ -108,6 +110,19 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
} }
} }
} }
findViewById<WebView>(R.id.hidden_web)?.let { v->
contentsSaver = v
contentsSaver?.webViewClient = saveClient
contentsSaver?.settings?.textZoom = 100
contentsSaver?.settings?.javaScriptEnabled = true
contentsSaver?.settings?.javaScriptCanOpenWindowsAutomatically = false
contentsSaver?.settings?.loadWithOverviewMode = true
contentsSaver?.settings?.setPluginState(WebSettings.PluginState.ON)
contentsSaver?.settings?.domStorageEnabled = true
contentsSaver?.clearCache(true);
contentsSaver?.clearHistory();
contentsSaver?.clearSslPreferences();
}
findViewById<View>(R.id.btn_rotate).setOnClickListener { v-> findViewById<View>(R.id.btn_rotate).setOnClickListener { v->
switcvhOrient() switcvhOrient()
@ -178,8 +193,10 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
realm.close() realm.close()
infos?.let { infos?.let {
Blog.LOGE("onBookInfos" , "onBookInfos it >> ${it}") Blog.LOGE("onBookInfos" , "onBookInfos it >> ${it}")
runOnUiThread {
showList(it) showList(it)
} }
}
@ -276,15 +293,115 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
} }
fun showList(infos: BookPageInfos) { fun showList(infos: BookPageInfos) {
DefaultList.showDefaultList(this@Intro,"현제는 ${currentTitle} - ${currentChapter} -> 다른화를 골라",infos.getTitleArray().reversed(),currentChapter, { position -> if (infos != null) {
DefaultList.showDefaultList(
this@Intro,
"현제는 ${currentTitle} - ${(infos.pages.size ?: 0) - currentChapter} -> 다른화를 골라",
infos.getTitleArray(),
currentChapter,
{ position ->
return@showDefaultList infos.pages?.get(position)?.chapterTitle ?: "" return@showDefaultList infos.pages?.get(position)?.chapterTitle ?: ""
},{position -> },
infos.pages?.reversed()?.get(position)?.let{moveTo(it)} { position ->
infos.pages?.get(position)?.let { moveTo(it) }
}, { state ->
if (state < 0 ) {
saveItem(infos)
}
}) })
} }
}
var isLoading = false
var saveClient = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
isLoading = true
Blog.LOGE("saveClient >>> ${isLoading} ${url}")
}
override fun onPageFinished(webView: WebView?, url: String?) {
super.onPageFinished(webView, url)
isLoading = false
var ramdomTimeSec = 1000L + Random(System.currentTimeMillis()).nextLong().rem(1999)
Blog.LOGE("ramdomTime >>> ${ramdomTimeSec}")
webView?.postDelayed( {
Blog.LOGE("saveClient >>> ${isLoading} ${url}")
var findContents = Agit.getFindContentsJs()
Blog.LOGE("saveClient find >>> ${findContents}")
Random(System.currentTimeMillis()).nextLong().rem(999)
webView?.evaluateJavascript(findContents){ result: String? ->
Blog.LOGE("saveClient result >>> ${result}")
result?.let { string: String ->
Blog.LOGE("saveClient contents >>> ${string}")
if (string.length > 10) {
Blog.LOGE("saveClient it.length >>> ${string.length}")
var contents = string.replace("\\\"", "\"")
contents =
(contents.replace("\\n", System.getProperty("line.separator")))
Blog.LOGE("saveClient contents >>> ${contents}")
Uri.parse(url)?.let {
it.path?.let {
HistoryManager.getBooPageInfo(it) {
HistoryManager.openRealm().apply {
this.writeBlocking {
it?.contents = contents
if (it != null) {
copyToRealm(it, UpdatePolicy.ALL)
}
}
}.close()
}
}
}
}
var ramdomTime = 10000L + Random(System.currentTimeMillis()).nextLong().rem(3999)
Blog.LOGE("ramdomTime >>> ${ramdomTime}")
contentsSaver?.postDelayed( { saveItem(null) }, ramdomTime)
}
}},ramdomTimeSec)
}
}
var saveTarget : ArrayList<BookPageInfo> = arrayListOf()
private fun saveItem(infos: BookPageInfos?) {
Blog.LOGE("saveItem >>> infos?.pages ${infos?.pages?.size ?: 0}")
var savedCount = Random(System.currentTimeMillis()).nextLong().rem(19) + 6L
infos?.pages?.reversed()?.forEach {
if (it.contents?.length ?: 0 > 10) {
} else {
if (saveTarget.size < savedCount.toInt()) {
saveTarget.add(it)
}
}
}
Blog.LOGE("saveItem >>> saveTarget ${saveTarget.count()}")
if (isLoading == false) {
try {
saveTarget?.removeFirst()?.let {
Blog.LOGE("saveItem >>> ${it.pathUrl}")
runOnUiThread {
mBaseWebContentsViewer.webview.url?.let { currentUrl ->
currentUrl.replace(Uri.parse(currentUrl).path ?: "", it.pathUrl ?: "")
?.let { targetUrl ->
Blog.LOGE("targetUrl >>> ${targetUrl}")
contentsSaver?.loadUrl(targetUrl)
}
}
}
}
} catch ( e : Exception) {
e.printStackTrace()
}
}
}
private fun moveTo(item: BookPageInfo?) { private fun moveTo(item: BookPageInfo?) {
item?.pathUrl?.let { newPath -> item?.pathUrl?.let { newPath ->
if (item.contents?.length ?: 0 > 10) {
paged_layer.text = item!!.contents!!
paged_layer.visibility = VISIBLE
}
mBaseWebContentsViewer?.webview?.url?.let { currentUrl -> mBaseWebContentsViewer?.webview?.url?.let { currentUrl ->
Uri.parse(currentUrl)?.path?.let { Uri.parse(currentUrl)?.path?.let {
currentUrl.replace(it, newPath)?.let { currentUrl.replace(it, newPath)?.let {
@ -324,15 +441,20 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
} }
} }
fun actionNextEvent() { fun actionNextEvent(fast : Boolean = false) {
if (paged_layer != null && paged_layer!!.visibility == View.VISIBLE && paged_layer!!.size() > 0 && (paged_layer!!.current() < paged_layer!!.size() - 1) ) { if (paged_layer != null && paged_layer!!.visibility == View.VISIBLE && paged_layer!!.size() > 0 && (paged_layer!!.current() < paged_layer!!.size() - 1) ) {
paged_layer!!.doNext() paged_layer!!.doNext(fast)
updateLastInfo(paged_layer!!) updateLastInfo(paged_layer!!)
}else { }else {
Uri.parse(mBaseWebContentsViewer.webview.url)?.let { Uri.parse(mBaseWebContentsViewer.webview.url)?.let {
it.path?.let { it.path?.let {
HistoryManager.getNextPage(it) { HistoryManager.getNextPage(it) {
Blog.LOGE("HistoryManager.getNextPage(${it})") Blog.LOGE("HistoryManager.getNextPage(${it})")
if (it?.contents?.length ?: 0 > 10) {
currentBooinfo = it
paged_layer.text = it!!.contents!!
paged_layer.visibility = VISIBLE
}
if(it?.pathUrl?.length ?: 0 > 0) { if(it?.pathUrl?.length ?: 0 > 0) {
HistoryManager.save(historyItem = HistoryItem().putHistory(it,mBaseWebContentsViewer.webview.url!!)) HistoryManager.save(historyItem = HistoryItem().putHistory(it,mBaseWebContentsViewer.webview.url!!))
Blog.LOGE("HistoryManager.getNextPage(${it?.pathUrl})") Blog.LOGE("HistoryManager.getNextPage(${it?.pathUrl})")
@ -345,6 +467,11 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
mBaseWebContentsViewer.webview.loadUrl(Agit.getLastedDoamin() + it?.pathUrl!!) mBaseWebContentsViewer.webview.loadUrl(Agit.getLastedDoamin() + it?.pathUrl!!)
paged_layer?.visibility = GONE paged_layer?.visibility = GONE
} }
it?.pathUrl?.let {
HistoryManager.getBooInfo(it) {
saveItem(it)
}
}
} }
} }
} }
@ -366,14 +493,20 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
} }
fun actionPrevEvent() { fun actionPrevEvent(fast : Boolean = false) {
if (paged_layer != null && paged_layer!!.visibility == View.VISIBLE && paged_layer!!.size() > 0 && paged_layer!!.current() > 0 ) { if (paged_layer != null && paged_layer!!.visibility == View.VISIBLE && paged_layer!!.size() > 0 && paged_layer!!.current() > 0 ) {
paged_layer!!.doPrev() paged_layer!!.doPrev(fast)
updateLastInfo(paged_layer!!) updateLastInfo(paged_layer!!)
} else { } else {
Uri.parse(mBaseWebContentsViewer.webview.url)?.let { Uri.parse(mBaseWebContentsViewer.webview.url)?.let {
it.path?.let { it.path?.let {
HistoryManager.getPrevPage(it) { HistoryManager.getPrevPage(it) {
if (it?.contents?.length ?: 0 > 10) {
currentBooinfo = it
paged_layer.text = it!!.contents!!
paged_layer.visibility = VISIBLE
}
if(it?.pathUrl?.length ?: 0 > 0) { if(it?.pathUrl?.length ?: 0 > 0) {
HistoryManager.save(historyItem = HistoryItem().putHistory(it,mBaseWebContentsViewer.webview.url!!)) HistoryManager.save(historyItem = HistoryItem().putHistory(it,mBaseWebContentsViewer.webview.url!!))
if (lastInfo?.pageUrl?.length ?: 0 > 0 && lastInfo?.pageUrl!!.startsWith("http")) { if (lastInfo?.pageUrl?.length ?: 0 > 0 && lastInfo?.pageUrl!!.startsWith("http")) {
@ -393,10 +526,10 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
super.onBackPressed() super.onBackPressed()
var layer = findViewById<PagedTextLayout>(R.id.paged_layer) var layer = findViewById<PagedTextLayout>(R.id.paged_layer)
if (!didBackPress) { // if (!didBackPress) {
firstBackPress() // firstBackPress()
return // return
} // }
if (layer != null && layer.visibility == View.VISIBLE) { if (layer != null && layer.visibility == View.VISIBLE) {
didBackPress = false didBackPress = false
@ -413,10 +546,11 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
if (!didBackPress) { if (!didBackPress) {
firstBackPress() firstBackPress()
return return
} } else {
finish() finish()
didBackPress = false didBackPress = false
} }
}
override fun showAlert(alert: String) { override fun showAlert(alert: String) {
@ -428,6 +562,7 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
paged_layer.apply { paged_layer.apply {
if (aContents != null) { if (aContents != null) {
var contents = aContents.replace("\\\"","\"") var contents = aContents.replace("\\\"","\"")
text = (contents.replace("\\n", System.getProperty("line.separator")))
visibility = VISIBLE visibility = VISIBLE
mPagedTextViewInterface = this@Intro mPagedTextViewInterface = this@Intro
var realm = HistoryManager.openRealm() var realm = HistoryManager.openRealm()
@ -455,8 +590,8 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
text = (contents.replace("\\n", System.getProperty("line.separator"))) // text = (contents.replace("\\n", System.getProperty("line.separator")))
if(lastInfo != null && lastInfo!!.pageUrl.equals(mBaseWebContentsViewer.webview.url)) { if(lastInfo != null && mBaseWebContentsViewer.webview.url?.endsWith(lastInfo!!.pageUrl) ?: false) {
this@Intro.findViewById<ProgressBar>(R.id.progress)?.visibility = VISIBLE this@Intro.findViewById<ProgressBar>(R.id.progress)?.visibility = VISIBLE
paged_layer?.postDelayed({ paged_layer?.postDelayed({
next(lastInfo!!.pageIndex) next(lastInfo!!.pageIndex)
@ -466,9 +601,18 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
},1000) },1000)
} }
forceUpdateUI() forceUpdateUI()
HistoryManager.getBooPageInfo(mBaseWebContentsViewer.webview.url!!){ mBaseWebContentsViewer.webview.url?.let {
Uri.parse(it)?.let {
it.path?.let {
HistoryManager.getBooPageInfo(it){
currentBooinfo = it
HistoryManager.openRealm().apply { HistoryManager.openRealm().apply {
this.writeBlocking { this.writeBlocking {
it?.chapterTitle?.let {
onFindTitle(it)
}
currentChapter = it?.chapterNum ?: 0
currentPage = it?.chapterNum ?: 0
it?.contents = contents it?.contents = contents
if (it != null) { if (it != null) {
copyToRealm(it, UpdatePolicy.ALL) copyToRealm(it, UpdatePolicy.ALL)
@ -479,6 +623,9 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
} }
} }
} }
}
}
}
Log.i(TAG,"onLoadedContents >> " + aContents) Log.i(TAG,"onLoadedContents >> " + aContents)
} }
@ -596,7 +743,7 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
} }
override fun onTouch(touchArea: TouchArea) { override fun onTouch(touchArea: TouchArea) {
Blog.LOGD(log="onTouch") Blog.LOGD(log="onTouch ${touchArea}")
when (touchArea) { when (touchArea) {
TouchArea.Center-> { TouchArea.Center-> {
findViewById<View>(R.id.btn_right).visibility = VISIBLE findViewById<View>(R.id.btn_right).visibility = VISIBLE
@ -616,6 +763,12 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
TouchArea.Left-> { TouchArea.Left-> {
actionPrevEvent() actionPrevEvent()
} }
TouchArea.DoubleRight -> {
actionNextEvent(true)
}
TouchArea.DoubleLeft -> {
actionPrevEvent(true)
}
else -> { else -> {
} }
@ -626,19 +779,38 @@ class Intro : Base() , MainControllInterface, PagedTextViewInterface {
override fun onLongClick() { override fun onLongClick() {
Blog.LOGD(log="onLongClick") Blog.LOGD(log="onLongClick")
}
override fun onSwipeLeft(count : Int) {
Blog.LOGD(log="onSwipeLeft ${count}")
actionNextEvent(count > 1)
}
override fun onSwipeRight(count : Int) {
Blog.LOGD(log="onSwipeRight ${count}")
actionPrevEvent(count > 1)
}
override fun onSwipeUp(touchCount: Int) {
}
override fun onSwipeDown(touchCount: Int) {
if (touchCount == 2) {
if (paged_layer?.visibility == VISIBLE) { if (paged_layer?.visibility == VISIBLE) {
paged_layer?.visibility = GONE paged_layer?.visibility = GONE
} findViewById<View>(R.id.btn_right).visibility = VISIBLE
} findViewById<View>(R.id.btn_left).visibility = VISIBLE
override fun onSwipeLeft() { findViewById<View>(R.id.btn_setting).visibility = VISIBLE
Blog.LOGD(log="onSwipeLeft")
actionNextEvent()
textview_title.visibility = VISIBLE
findViewById<View>(R.id.btn_home).visibility = VISIBLE
findViewById<View>(R.id.btn_list).visibility = VISIBLE
findViewById<View>(R.id.btn_history).visibility = VISIBLE
findViewById<View>(R.id.btn_rotate).visibility = VISIBLE
}
} }
override fun onSwipeRight() {
Blog.LOGD(log="onSwipeRight")
actionPrevEvent()
} }

View File

@ -65,8 +65,8 @@ class BookPageInfos : RealmObject {
var arrayList = ArrayList<String>() var arrayList = ArrayList<String>()
pages?.forEach { pages?.forEach {
Blog.LOGE("chapterTitle >> ${it.chapterTitle} ") // Blog.LOGE("chapterTitle >> ${it.getTitleItem()} ")
arrayList.add(it.chapterTitle ?: "") } arrayList.add(it.getTitleItem())}
return arrayList return arrayList
} }
@ -85,5 +85,22 @@ class BookPageInfo : RealmObject {
@PrimaryKey @PrimaryKey
var pathUrl : String? = "" var pathUrl : String? = ""
fun getTitleItem() : String {
var result = StringBuilder()
result.append(if (contents?.length ?: 0 > 10) {
"S:[0] "
} else {
"[X] "
})
result.append(chapterTitle?: "")
result.append(if (lastPage ?: 0 >0) {
" [0] "
} else {
" [X] "
})
return result.toString()
}
} }

View File

@ -7,20 +7,31 @@ import android.widget.ArrayAdapter
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
object DefaultList { object DefaultList {
fun showDefaultList(context: Context,title : String, items : Collection<String>, firstPosition : Int, choosedTitle : (Int)->String, chooedPositive : (Int)->Unit) { fun showDefaultList(context: Context,title : String, items : Collection<String>, firstPosition : Int, choosedTitle : (Int)->String, chooedPositive : (Int)->Unit, saveCalback : (Int)->Unit ) {
val builderSingle: AlertDialog.Builder = AlertDialog.Builder(context) val builderSingle: AlertDialog.Builder = AlertDialog.Builder(context)
builderSingle.setTitle(title) builderSingle.setTitle(title)
val arrayAdapter = val arrayAdapter =
ArrayAdapter<String>(context, R.layout.select_dialog_singlechoice) ArrayAdapter<String>(context, R.layout.select_dialog_singlechoice)
arrayAdapter.addAll(items) arrayAdapter.addAll(items)
builderSingle.setNeutralButton("전체 저장") { dialog, which ->
saveCalback.invoke(-1)
dialog.dismiss()
}
builderSingle.setNegativeButton("닫기", builderSingle.setNegativeButton("닫기",
DialogInterface.OnClickListener { dialog, which -> dialog.dismiss() }) DialogInterface.OnClickListener { dialog, which ->
dialog.dismiss() })
builderSingle.setAdapter(arrayAdapter, builderSingle.setAdapter(arrayAdapter,
DialogInterface.OnClickListener { dialog, position -> DialogInterface.OnClickListener { dialog, position ->
val strName = arrayAdapter.getItem(position) val strName = arrayAdapter.getItem(position)
val builderInner: AlertDialog.Builder = AlertDialog.Builder(context) val builderInner: AlertDialog.Builder = AlertDialog.Builder(context)
builderInner.setMessage(strName) builderInner.setMessage(strName)
builderInner.setTitle(choosedTitle.invoke(position)) builderInner.setTitle(choosedTitle.invoke(position))
builderInner.setNegativeButton("닫기") { dialog, which ->
}
// builderInner.setNeutralButton("자동 저장") { dialog, which ->
// saveCalback.invoke(position)
// }
builderInner.setPositiveButton("이동"){ dialog, which -> builderInner.setPositiveButton("이동"){ dialog, which ->
chooedPositive.invoke(position) chooedPositive.invoke(position)
dialog.dismiss() dialog.dismiss()

View File

@ -1,13 +1,716 @@
package com.mime.dualscreenview.view package com.mime.dualscreenview.view
import android.content.Context import android.content.Context
import android.os.SystemClock
import android.util.Log
import android.view.GestureDetector import android.view.GestureDetector
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View 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 { enum class TouchArea {
Left,Center,Right 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 { abstract class OnSwipeTouchListener(val context: Context?) : View.OnTouchListener {
@ -21,6 +724,7 @@ abstract class OnSwipeTouchListener(val context: Context?) : View.OnTouchListene
abstract fun onSwipeDown() abstract fun onSwipeDown()
abstract fun onSwipeUp() abstract fun onSwipeUp()
abstract fun onSingleTap(area : TouchArea) abstract fun onSingleTap(area : TouchArea)
abstract fun onDoubleTap(area : TouchArea)
override fun onTouch(v: View?, event: MotionEvent?): Boolean { override fun onTouch(v: View?, event: MotionEvent?): Boolean {
if (event == null) { if (event == null) {
@ -36,8 +740,26 @@ abstract class OnSwipeTouchListener(val context: Context?) : View.OnTouchListene
return true 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) {
override fun onSingleTapUp(e: MotionEvent): Boolean { } 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 width: Int = context?.resources?.displayMetrics?.widthPixels ?: 0
val height: Int = context?.resources?.displayMetrics?.heightPixels ?: 0 val height: Int = context?.resources?.displayMetrics?.heightPixels ?: 0
var touchArea : TouchArea = TouchArea.Center var touchArea : TouchArea = TouchArea.Center
@ -53,16 +775,22 @@ abstract class OnSwipeTouchListener(val context: Context?) : View.OnTouchListene
} }
} }
onSingleTap(touchArea) onSingleTap(touchArea)
return super.onSingleTapUp(e) return super.onSingleTapConfirmed(e)
} }
// override fun onSingleTapUp(e: MotionEvent): Boolean {
//
// return super.onSingleTapUp(e)
// }
override fun onFling( override fun onFling(
e1: MotionEvent, e1: MotionEvent,
e2: MotionEvent, e2: MotionEvent,
velocityX: Float, velocityX: Float,
velocityY: Float velocityY: Float
): Boolean { ): Boolean {
Blog.LOGE("e1.pointerCount >> ${e1.pointerCount}")
Blog.LOGE("e2.pointerCount >> ${e2.pointerCount}")
val distanceX = e2.x - (e1?.x ?: 0f) val distanceX = e2.x - (e1?.x ?: 0f)
val distanceY = e2.y - (e1?.y ?: 0f) val distanceY = e2.y - (e1?.y ?: 0f)
if (Math.abs(distanceX) > Math.abs(distanceY) if (Math.abs(distanceX) > Math.abs(distanceY)

View File

@ -53,46 +53,120 @@ class PagedTextLayout : ConstraintLayout , PagedTextGenerateInterface {
mPagedTextViewInterface?.onTimeoverTouch() mPagedTextViewInterface?.onTimeoverTouch()
} }
var currentPageTextView : TextView? = null
fun initView(context: Context) { fun initView(context: Context) {
inflate(context, R.layout.layout_textviewer, this) inflate(context, R.layout.layout_textviewer, this)
mainTextView = findViewById(R.id.first_view) mainTextView = findViewById(R.id.first_view)
sencondTextView = findViewById(R.id.sencond_view) sencondTextView = findViewById(R.id.sencond_view)
demp = findViewById(R.id.demp) demp = findViewById(R.id.demp)
currentPageTextView = findViewById(R.id.current_page)
hiddenTextView = findViewById(R.id.hidden_view) hiddenTextView = findViewById(R.id.hidden_view)
hiddenTextView?.mPagedTextGenerateInterface = this hiddenTextView?.mPagedTextGenerateInterface = this
currentPageTextView?.text = ""
hanler.removeCallbacks(touchTimeover) hanler.removeCallbacks(touchTimeover)
setOnLongClickListener { v -> setOnLongClickListener { v ->
mPagedTextViewInterface?.onLongClick() mPagedTextViewInterface?.onLongClick()
return@setOnLongClickListener false return@setOnLongClickListener false
} }
setOnTouchListener(object : OnSwipeTouchListener(context) { setOnTouchListener(SimpleFingerGestures(omfgl = object : SimpleFingerGestures.OnFingerGestureListener{
override fun onSwipeUp() { 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() mPagedTextViewInterface?.onLongClick()
return false
} }
override fun onSwipeDown() { override fun onDoubleTap(fingers: Int): Boolean {
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) hanler.removeCallbacks(touchTimeover)
mPagedTextViewInterface?.onTouch(touchArea) mPagedTextViewInterface?.onTouch(TouchArea.Center)
hanler?.postDelayed(touchTimeover, 3000L) hanler?.postDelayed(touchTimeover, 3000L)
} else { return false
mPagedTextViewInterface?.onTouch(touchArea)
} }
} }))
// {
}) // 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) { fun layoutChange(needDualPage: Boolean) {
@ -168,6 +242,10 @@ class PagedTextLayout : ConstraintLayout , PagedTextGenerateInterface {
fun setPageBy(num : Int) { fun setPageBy(num : Int) {
currentPage = num currentPage = num
var realPage = if(isDualPage()) currentPage * 2 else currentPage 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" mainTextView?.text = pageList?.get(realPage) ?: "NONE"
if(isDualPage()) { if(isDualPage()) {
realPage = realPage.inc() realPage = realPage.inc()
@ -178,13 +256,26 @@ class PagedTextLayout : ConstraintLayout , PagedTextGenerateInterface {
} }
fun size(): Int = if(isDualPage()) Math.round((hiddenTextView?.size() ?:0) * 0.5f) else hiddenTextView?.size() ?: 0 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 current(): Int = currentPage
fun doNext() { fun doNext(fast : Boolean = false) {
if (fast) {
setPageBy(if((currentPage + getFastPageCount()) >= 0) {
currentPage + getFastPageCount()
} else {size()})
} else {
setPageBy(currentPage.inc()) setPageBy(currentPage.inc())
} }
}
fun doPrev() { fun doPrev(fast : Boolean = false) {
setPageBy(currentPage.dec()) if (fast) {
setPageBy(if((currentPage - getFastPageCount()) >= 0) {
currentPage - getFastPageCount()
} else {0})
} else {
setPageBy(if(currentPage > 0 )currentPage.dec() else 0)
}
} }
fun forceUpdateUI() { fun forceUpdateUI() {

View File

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

View File

@ -6,6 +6,7 @@ import android.net.http.SslError
import android.util.Log import android.util.Log
import android.webkit.* import android.webkit.*
import com.mime.dualscreenview.common.Blog import com.mime.dualscreenview.common.Blog
import com.mime.dualscreenview.data.HistoryManager
import com.mime.dualscreenview.data.model.LastInfo import com.mime.dualscreenview.data.model.LastInfo
import com.mime.dualscreenview.webcontents.contentsinfo.DidFindContents import com.mime.dualscreenview.webcontents.contentsinfo.DidFindContents
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
@ -72,9 +73,19 @@ open class BaseWebContentsViewer {
} }
fun loadLastInfo(lastInfo: LastInfo) { fun loadLastInfo(lastInfo: LastInfo) {
lastInfo?.let { lastInfo?.let { last ->
currentContentsProvider = WebContentsManger.getBaseWebContentsBy(it.contentsName) currentContentsProvider = WebContentsManger.getBaseWebContentsBy(last.contentsName)
webview.loadUrl(it.pageUrl) // HistoryManager.getBooPageInfo(last.pageUrl,{ page ->
// if(page != null){
// if(page.contents?.length ?: 0 > 0) {
// mainControllInterface?.onLoadedContents(page.contents!!)
// } else {
// webview.loadUrl(last.pageUrl)
// }
// } else {
webview.loadUrl(last.pageUrl)
// }
// })
} }
} }

View File

@ -117,7 +117,7 @@ object Agit : BaseWebContents() {
} }
override fun getFindContentsJs(): String { override fun getFindContentsJs(): String {
return "document.getElementById(\"id_wr_content\") != null ? document.getElementById(\"id_wr_content\").innerText : null" return "document.getElementById('id_wr_content') != null ? document.getElementById('id_wr_content').innerText : null"
} }
override fun checkCorrectContents(contents: String): String { override fun checkCorrectContents(contents: String): String {

View File

@ -7,6 +7,15 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".activity.Intro"> 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 <WebView
android:id="@+id/menu_web" android:id="@+id/menu_web"
@ -158,5 +167,6 @@
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<!--//style="@style/Widget.AppCompat.ProgressBar.Horizontal"--> <!--//style="@style/Widget.AppCompat.ProgressBar.Horizontal"-->

View File

@ -7,7 +7,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout <LinearLayout
android:layout_margin="8dp" android:layout_margin="15dp"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:orientation="horizontal" android:orientation="horizontal"
@ -43,7 +43,7 @@
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:layout_margin="5dp" android:layout_margin="5dp"
android:padding="2dp" android:padding="2dp"
android:gravity="center" android:gravity="start"
android:includeFontPadding="false" android:includeFontPadding="false"
android:id="@+id/first_view" android:id="@+id/first_view"
android:lineSpacingExtra="0dp" android:lineSpacingExtra="0dp"
@ -55,6 +55,7 @@
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:layout_margin="5dp" android:layout_margin="5dp"
android:padding="2dp" android:padding="2dp"
android:gravity="start"
android:includeFontPadding="false" android:includeFontPadding="false"
android:lineSpacingExtra="0dp" android:lineSpacingExtra="0dp"
android:visibility="visible" android:visibility="visible"
@ -63,7 +64,11 @@
android:layout_weight="1" android:layout_weight="1"
style="@style/sss" style="@style/sss"
android:layout_height="match_parent"/> android:layout_height="match_parent"/>
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/current_page"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout> </RelativeLayout>

41
gradlew vendored
View File

@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@ -80,13 +80,11 @@ do
esac esac
done done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # This is normally unused
# shellcheck disable=SC2034
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@ -133,22 +131,29 @@ location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 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 Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) 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 ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
case $MAX_FD in #( case $MAX_FD in #(
'' | soft) :;; #( '' | 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" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then
done done
fi fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
# shell script including quotes and variable substitutions, so put them in DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded. # 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 -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \
@ -205,6 +214,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \ 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. # Use "xargs" to parse quoted args.
# #
# With -n1 it outputs one arg per line, with the quotes and backslashes removed. # With -n1 it outputs one arg per line, with the quotes and backslashes removed.

15
gradlew.bat vendored
View File

@ -14,7 +14,7 @@
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if %ERRORLEVEL% equ 0 goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 set EXIT_CODE=%ERRORLEVEL%
exit /b 1 if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal

View File

@ -12,5 +12,5 @@ dependencyResolutionManagement {
mavenCentral() mavenCentral()
} }
} }
rootProject.name = "DualScreenView" rootProject.name = "Bum's App"
include ':app' include ':app'