From 61199d91db79b02967c3d52c7703417683788036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96ppen?= Date: Sat, 15 Aug 2020 21:20:15 +0100 Subject: [PATCH] working history and back action --- .idea/vcs.xml | 6 ++ .../java/oppen/tva/io/GeminiDatasource.kt | 27 ++++++- .../java/oppen/tva/io/history/BasicCache.kt | 72 +++++++++++++++++++ .../oppen/tva/io/history/CacheInterface.kt | 2 +- .../oppen/tva/io/history/SimplePrefsCache.kt | 68 ------------------ app/src/main/java/oppen/tva/io/history/Tab.kt | 15 ++++ app/src/main/java/oppen/tva/ui/TvaActivity.kt | 9 +++ .../main/java/oppen/tva/ui/TvaViewModel.kt | 22 ++++++ .../oppen/tva/ui/gemtext/GemtextAdapter.kt | 4 +- app/src/main/res/layout/activity_tva.xml | 10 +-- 10 files changed, 157 insertions(+), 78 deletions(-) create mode 100644 .idea/vcs.xml create mode 100644 app/src/main/java/oppen/tva/io/history/BasicCache.kt delete mode 100644 app/src/main/java/oppen/tva/io/history/SimplePrefsCache.kt diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/io/GeminiDatasource.kt b/app/src/main/java/oppen/tva/io/GeminiDatasource.kt index 0e68d39..39e4845 100644 --- a/app/src/main/java/oppen/tva/io/GeminiDatasource.kt +++ b/app/src/main/java/oppen/tva/io/GeminiDatasource.kt @@ -11,6 +11,7 @@ const val GEMINI_SCHEME = "gemini" class GeminiDatasource: Datasource{ + private var last: URI? = null override fun request(uri: URI, onUpdate: (state: TvaState) -> Unit) { //Any inputted uri starting with a colon is an app-specific command, eg. :prefs :settings @@ -29,7 +30,30 @@ class GeminiDatasource: Datasource{ } } - else -> onUpdate(TvaState.NotGeminiRequest(uri)) + else -> { + val address = uri.toString() + when { + address.startsWith("//") -> { + //just missing protocol + request(URI.create("gemini:$address"), onUpdate) + return + } + address.startsWith("/") -> { + //internal navigation + val internalNav = "gemini://${last?.host}$address" + request(URI.create(internalNav), onUpdate) + return + } + !address.contains("://") -> { + //looks like a relative link + val lastAddress = last.toString() + val relAddress = "${lastAddress.substring(0, lastAddress.lastIndexOf("/") + 1)}$address" + request(URI.create(relAddress), onUpdate) + return + } + else -> onUpdate(TvaState.NotGeminiRequest(uri)) + } + } } } @@ -39,6 +63,7 @@ class GeminiDatasource: Datasource{ * */ private fun geminiRequest(uri: URI, onUpdate: (state: TvaState) -> Unit){ + last = uri val port = if(uri.port == -1) 1965 else uri.port val sslContext = SSLContext.getInstance("TLSv1.2") diff --git a/app/src/main/java/oppen/tva/io/history/BasicCache.kt b/app/src/main/java/oppen/tva/io/history/BasicCache.kt new file mode 100644 index 0000000..ac730cc --- /dev/null +++ b/app/src/main/java/oppen/tva/io/history/BasicCache.kt @@ -0,0 +1,72 @@ +package oppen.tva.io.history + +import android.content.Context +import java.net.URI +import kotlin.text.StringBuilder + +/** + * + * This is slow, unsafe, awful, and synchronous but I don't want get bogged down implementing Room just yet + * + */ +class BasicCache(context: Context): CacheInterface { + + private val DELIM = "||" + private val prefsKey = "oppen.tva.io.history.BasicCache.PREFS_KEY" + private val prefsCacheKey = "oppen.tva.io.history.BasicCache.PREFS_CACHE_KEY" + private val prefsActiveIndexKey = "oppen.tva.io.history.BasicCache.PREFS_ACTIVE_INDEX_KEY" + private val prefs = context.getSharedPreferences(prefsKey, Context.MODE_PRIVATE) + + override fun update(tabs: List, activeIndex: Int) { + val sb = StringBuilder() + tabs.forEach { tab -> + sb.append("${tab.index}$DELIM") + tab.history.forEach { uri -> + sb.append("$uri$DELIM") + } + sb.append("\n") + } + + val edit = prefs.edit() + val raw = sb.toString() + + println("------------------------------------") + println(raw) + println("------------------------------------") + + edit.putString(prefsCacheKey, sb.toString()) + edit.putInt(prefsActiveIndexKey, activeIndex) + edit.apply() + } + + override fun getTabs(onTabs: (tabs: MutableList, activeIndex: Int) -> Unit) { + val raw = prefs.getString(prefsCacheKey, null) + + println("====================================") + println(raw) + println("====================================") + + if (raw == null) { + onTabs(arrayListOf(), 0) + } else { + val activeIndex = prefs.getInt(prefsActiveIndexKey, 0) + val tabs = mutableListOf() + raw.lines().forEach { line -> + if (line.trim().isNotEmpty()) { + val segs = line.split(DELIM) + val tabIndex = segs.first() + val tab = Tab(tabIndex.toInt()) + for (index in 1 until segs.size) { + val address = segs[index] + if (address.isNotBlank()) { + tab.history.add(URI.create(address)) + } + } + tabs.add(tab) + } + } + + onTabs(tabs, activeIndex) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/io/history/CacheInterface.kt b/app/src/main/java/oppen/tva/io/history/CacheInterface.kt index 2d357ae..0323e21 100644 --- a/app/src/main/java/oppen/tva/io/history/CacheInterface.kt +++ b/app/src/main/java/oppen/tva/io/history/CacheInterface.kt @@ -8,7 +8,7 @@ interface CacheInterface { companion object{ fun default(context: Context): CacheInterface{ - return SimplePrefsCache(context) + return BasicCache(context) } } } \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/io/history/SimplePrefsCache.kt b/app/src/main/java/oppen/tva/io/history/SimplePrefsCache.kt deleted file mode 100644 index 06c5579..0000000 --- a/app/src/main/java/oppen/tva/io/history/SimplePrefsCache.kt +++ /dev/null @@ -1,68 +0,0 @@ -package oppen.tva.io.history - -import android.content.Context -import org.json.JSONArray -import org.json.JSONObject - -/** - * - * This is a simple SharedPreferences based store for now because I don't want to get bogged down setting up Room at this point - * - */ -class SimplePrefsCache(context: Context): CacheInterface { - - private val prefsKey = "oppen.tva.io.history.SimplePrefsCache.PREFS_KEY" - private val prefsCacheKey = "oppen.tva.io.history.SimplePrefsCache.PREFS_CACHE_KEY" - private val prefsActiveIndexKey = "oppen.tva.io.history.SimplePrefsCache.PREFS_ACTIVE_INDEX_KEY" - private val prefs = context.getSharedPreferences(prefsKey, Context.MODE_PRIVATE) - - override fun getTabs(onTabs: (tabs: MutableList, activeIndex: Int) -> Unit) { - val activeIndex = prefs.getInt(prefsActiveIndexKey, 0) - when (val rawJson = prefs.getString(prefsCacheKey, null)) { - null -> onTabs(arrayListOf(), activeIndex) - else -> { - val tabs = mutableListOf() - val tabsJsonArray = JSONArray(rawJson) - val tabCount = tabsJsonArray.length() - for(index in 0 until tabCount){ - val jsonTabObject = tabsJsonArray.getJSONObject(index) - val tabIndex = jsonTabObject.getInt("index") - val tab = Tab(tabIndex) - val jsonTabHistory = jsonTabObject.getJSONArray("history") - val historySize = jsonTabHistory.length() - for(historyIndex in 0 until historySize){ - tab.add(jsonTabHistory.getString(historyIndex)) - } - tabs.add(tab) - } - - onTabs(tabs, activeIndex) - } - } - } - - override fun update(tabs: List, activeIndex: Int) { - val edit = prefs.edit() - edit.putInt(prefsActiveIndexKey, activeIndex) - edit.putString(prefsCacheKey, tabsToJson(tabs)) - edit.apply() - } - - private fun tabsToJson(tabs: List): String { - val jsonArray = JSONArray() - tabs.forEach { tab -> - val jsonTab = JSONObject() - jsonTab.put("index", tab.index) - - val jsonHistoryArray = JSONArray() - tab.history.forEach { uri -> - jsonHistoryArray.put(uri.toString()) - } - jsonTab.put("history", jsonHistoryArray) - jsonArray.put(jsonTab) - } - val rawJsonArray = jsonArray.toString(5) - println("Raw tabs json to store:\n$rawJsonArray") - return rawJsonArray - } -} \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/io/history/Tab.kt b/app/src/main/java/oppen/tva/io/history/Tab.kt index 224facb..d5778a3 100644 --- a/app/src/main/java/oppen/tva/io/history/Tab.kt +++ b/app/src/main/java/oppen/tva/io/history/Tab.kt @@ -13,6 +13,21 @@ class Tab(val index: Int) { history.add(URI.create(address)) } + fun getPrevious(): URI? { + return when { + history.size > 1 -> { + history[history.size-2] + } + else -> { + null + } + } + } + + fun popHistory(){ + history.dropLast(1) + } + companion object{ fun new(index: Int, address: String): Tab { val tab = Tab(index) diff --git a/app/src/main/java/oppen/tva/ui/TvaActivity.kt b/app/src/main/java/oppen/tva/ui/TvaActivity.kt index baa3bbe..483be20 100644 --- a/app/src/main/java/oppen/tva/ui/TvaActivity.kt +++ b/app/src/main/java/oppen/tva/ui/TvaActivity.kt @@ -54,4 +54,13 @@ class TvaActivity : AppCompatActivity() { binding.addressEdit.setText(state.uri.toString()) adapter.render(state.lines) } + + @ExperimentalStdlibApi + override fun onBackPressed() { + if(model.canGoBack()){ + model.goBack() + }else{ + super.onBackPressed() + } + } } \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/ui/TvaViewModel.kt b/app/src/main/java/oppen/tva/ui/TvaViewModel.kt index 8a3e0e3..e2ffc91 100644 --- a/app/src/main/java/oppen/tva/ui/TvaViewModel.kt +++ b/app/src/main/java/oppen/tva/ui/TvaViewModel.kt @@ -59,4 +59,26 @@ class TvaViewModel: ViewModel() { onState(state) } + + fun canGoBack(): Boolean { + println("canGoBack()...") + tabs[activeTab].history.forEachIndexed{ index, uri -> + println("canGoBack history $index: $uri") + } + return tabs[activeTab].history.size > 1 + } + + @ExperimentalStdlibApi + fun goBack(){ + val previous = tabs[activeTab].getPrevious() + + if(previous == null){ + println("Previous history URI is null") + return + } + + tabs[activeTab].history.removeLast() + cache.update(tabs, activeTab) + request(previous) + } } \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/ui/gemtext/GemtextAdapter.kt b/app/src/main/java/oppen/tva/ui/gemtext/GemtextAdapter.kt index fc64a94..ec23e0f 100644 --- a/app/src/main/java/oppen/tva/ui/gemtext/GemtextAdapter.kt +++ b/app/src/main/java/oppen/tva/ui/gemtext/GemtextAdapter.kt @@ -81,7 +81,9 @@ class GemtextAdapter(val onLink: (link: URI) -> Unit): RecyclerView.Adapter - - - - - - - @@ -90,6 +83,9 @@ android:id="@+id/gemtext_recycler" android:layout_width="match_parent" android:layout_height="wrap_content" + android:clipToPadding="false" + android:paddingTop="@dimen/default_margin" + android:paddingBottom="@dimen/default_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior"/>