mirror of https://git.sr.ht/~oppen/ariane
history rewrite, plus tls client cert wip
This commit is contained in:
parent
244459b3c3
commit
3f6b78ed08
|
@ -1 +1 @@
|
||||||
Två
|
a.kt
|
|
@ -7,7 +7,7 @@
|
||||||
<option name="testRunner" value="PLATFORM" />
|
<option name="testRunner" value="PLATFORM" />
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="gradleJvm" value="1.8" />
|
<option name="gradleJvm" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
|
|
|
@ -32,7 +32,10 @@ class GeminiDatasourceTests {
|
||||||
val capsule = capsules.random()
|
val capsule = capsules.random()
|
||||||
println("Using $capsule for Gemini tests")
|
println("Using $capsule for Gemini tests")
|
||||||
capsuleIndex = capsules.indexOf(capsule)
|
capsuleIndex = capsules.indexOf(capsule)
|
||||||
gemini = Datasource.factory(InstrumentationRegistry.getInstrumentation().targetContext)
|
gemini = Datasource.factory(
|
||||||
|
InstrumentationRegistry.getInstrumentation().targetContext,
|
||||||
|
db.history()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
package oppen.ariane.io.bookmarks
|
|
||||||
|
|
||||||
import androidx.room.Database
|
|
||||||
import androidx.room.RoomDatabase
|
|
||||||
|
|
||||||
@Database(entities = [BookmarkEntity::class], version = 2)
|
|
||||||
abstract class BookmarksDB: RoomDatabase() {
|
|
||||||
abstract fun bookmarksDao(): BookmarksDao
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package oppen.ariane.io.bookmarks
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
|
|
||||||
interface BookmarksDatasource {
|
|
||||||
|
|
||||||
fun get(onBookmarks: (List<Bookmark>) -> Unit)
|
|
||||||
fun add(bookmark: Bookmark, onAdded: () -> Unit)
|
|
||||||
fun delete(bookmark: Bookmark, onDelete: () -> Unit)
|
|
||||||
|
|
||||||
fun moveUp(bookmark: Bookmark, onMoved: () -> Unit)
|
|
||||||
fun moveDown(bookmark: Bookmark, onMoved: () -> Unit)
|
|
||||||
fun update(bookmark: Bookmark, label: String?, uri: String?, onUpdate: () -> Unit)
|
|
||||||
|
|
||||||
companion object{
|
|
||||||
fun getDefault(applicationContext: Context): BookmarksDatasource{
|
|
||||||
return RoomBookmarks(applicationContext)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
package oppen.ariane.io.bookmarks
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.room.Room
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.net.URI
|
|
||||||
|
|
||||||
class RoomBookmarks(applicationContext: Context): BookmarksDatasource {
|
|
||||||
|
|
||||||
private val db: BookmarksDB = Room.databaseBuilder(applicationContext, BookmarksDB::class.java, "tva_bookmarks").build()
|
|
||||||
|
|
||||||
override fun get(onBookmarks: (List<Bookmark>) -> Unit) {
|
|
||||||
GlobalScope.launch(Dispatchers.IO){
|
|
||||||
val dbBookmarks = db.bookmarksDao().getAll()
|
|
||||||
val bookmarks = mutableListOf<Bookmark>()
|
|
||||||
|
|
||||||
dbBookmarks.forEach { bookmarkEntity ->
|
|
||||||
bookmarks.add(
|
|
||||||
Bookmark(
|
|
||||||
uid = bookmarkEntity.uid,
|
|
||||||
label = bookmarkEntity.label ?: "Unknown",
|
|
||||||
uri = URI.create(bookmarkEntity.uri),
|
|
||||||
index = bookmarkEntity.uiIndex ?: 0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onBookmarks(bookmarks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun add(bookmark: Bookmark, onAdded: () -> Unit) {
|
|
||||||
GlobalScope.launch(Dispatchers.IO){
|
|
||||||
val bookmarkEntity = BookmarkEntity(
|
|
||||||
label = bookmark.label,
|
|
||||||
uri = bookmark.uri.toString(),
|
|
||||||
uiIndex = bookmark.index,
|
|
||||||
folder = "~/")
|
|
||||||
|
|
||||||
db.bookmarksDao().insertAll(bookmarkEntity)
|
|
||||||
onAdded()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun moveUp(bookmark: Bookmark, onMoved: () -> Unit) {
|
|
||||||
GlobalScope.launch(Dispatchers.IO){
|
|
||||||
|
|
||||||
//todo - this method is broken:
|
|
||||||
val prev = db.bookmarksDao().getBookmark(bookmark.index -1)
|
|
||||||
val target = db.bookmarksDao().getBookmark(bookmark.index)
|
|
||||||
|
|
||||||
db.bookmarksDao().updateUIIndex(prev.uid, bookmark.index)
|
|
||||||
db.bookmarksDao().updateUIIndex(target.uid, bookmark.index - 1)
|
|
||||||
onMoved()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun moveDown(bookmark: Bookmark, onMoved: () -> Unit) {
|
|
||||||
GlobalScope.launch(Dispatchers.IO){
|
|
||||||
val next = db.bookmarksDao().getBookmark(bookmark.index + 1)
|
|
||||||
val target = db.bookmarksDao().getBookmark(bookmark.index)
|
|
||||||
|
|
||||||
db.bookmarksDao().updateUIIndex(next.uid, bookmark.index)
|
|
||||||
db.bookmarksDao().updateUIIndex(target.uid, bookmark.index + 1)
|
|
||||||
onMoved()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun update(bookmark: Bookmark, label: String?, uri: String?, onUpdate: () -> Unit) {
|
|
||||||
GlobalScope.launch(Dispatchers.IO){
|
|
||||||
db.bookmarksDao().updateContent(bookmark.uid, label ?: "", uri ?: "")
|
|
||||||
onUpdate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun delete(bookmark: Bookmark, onDelete: () -> Unit) {
|
|
||||||
GlobalScope.launch(Dispatchers.IO){
|
|
||||||
val entity = db.bookmarksDao().getBookmark(bookmark.index)
|
|
||||||
db.bookmarksDao().delete(entity)
|
|
||||||
onDelete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package oppen.ariane.io.database
|
||||||
|
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import oppen.ariane.io.database.bookmarks.BookmarkEntity
|
||||||
|
import oppen.ariane.io.database.bookmarks.BookmarksDao
|
||||||
|
import oppen.ariane.io.database.history.HistoryDao
|
||||||
|
import oppen.ariane.io.database.history.HistoryEntity
|
||||||
|
|
||||||
|
@Database(entities = [BookmarkEntity::class, HistoryEntity::class], version = 3)
|
||||||
|
abstract class ArianeAbstractDatabase: RoomDatabase() {
|
||||||
|
abstract fun bookmarks(): BookmarksDao
|
||||||
|
abstract fun history(): HistoryDao
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package oppen.ariane.io.database
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Room
|
||||||
|
import oppen.ariane.io.database.bookmarks.ArianeBookmarks
|
||||||
|
import oppen.ariane.io.database.history.ArianeHistory
|
||||||
|
|
||||||
|
class ArianeDatabase(context: Context) {
|
||||||
|
|
||||||
|
private val db: ArianeAbstractDatabase = Room.databaseBuilder(context, ArianeAbstractDatabase::class.java, "ariane_database_v1").build()
|
||||||
|
|
||||||
|
fun bookmarks(): ArianeBookmarks = ArianeBookmarks(db)
|
||||||
|
fun history(): ArianeHistory = ArianeHistory(db)
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package oppen.ariane.io.database.bookmarks
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import oppen.ariane.io.database.ArianeAbstractDatabase
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
|
class ArianeBookmarks(private val db: ArianeAbstractDatabase): BookmarksDatasource {
|
||||||
|
|
||||||
|
override fun get(onBookmarks: (List<BookmarkEntry>) -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO){
|
||||||
|
val dbBookmarks = db.bookmarks().getAll()
|
||||||
|
val bookmarks = mutableListOf<BookmarkEntry>()
|
||||||
|
|
||||||
|
dbBookmarks.forEach { bookmarkEntity ->
|
||||||
|
bookmarks.add(
|
||||||
|
BookmarkEntry(
|
||||||
|
uid = bookmarkEntity.uid,
|
||||||
|
label = bookmarkEntity.label ?: "Unknown",
|
||||||
|
uri = URI.create(bookmarkEntity.uri),
|
||||||
|
index = bookmarkEntity.uiIndex ?: 0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onBookmarks(bookmarks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun add(bookmarkEntry: BookmarkEntry, onAdded: () -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO){
|
||||||
|
val bookmarkEntity = BookmarkEntity(
|
||||||
|
label = bookmarkEntry.label,
|
||||||
|
uri = bookmarkEntry.uri.toString(),
|
||||||
|
uiIndex = bookmarkEntry.index,
|
||||||
|
folder = "~/")
|
||||||
|
|
||||||
|
db.bookmarks().insertAll(bookmarkEntity)
|
||||||
|
onAdded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun moveUp(bookmarkEntry: BookmarkEntry, onMoved: () -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO){
|
||||||
|
|
||||||
|
//todo - this method is broken:
|
||||||
|
val prev = db.bookmarks().getBookmark(bookmarkEntry.index -1)
|
||||||
|
val target = db.bookmarks().getBookmark(bookmarkEntry.index)
|
||||||
|
|
||||||
|
db.bookmarks().updateUIIndex(prev.uid, bookmarkEntry.index)
|
||||||
|
db.bookmarks().updateUIIndex(target.uid, bookmarkEntry.index - 1)
|
||||||
|
onMoved()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun moveDown(bookmarkEntry: BookmarkEntry, onMoved: () -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO){
|
||||||
|
val next = db.bookmarks().getBookmark(bookmarkEntry.index + 1)
|
||||||
|
val target = db.bookmarks().getBookmark(bookmarkEntry.index)
|
||||||
|
|
||||||
|
db.bookmarks().updateUIIndex(next.uid, bookmarkEntry.index)
|
||||||
|
db.bookmarks().updateUIIndex(target.uid, bookmarkEntry.index + 1)
|
||||||
|
onMoved()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(bookmarkEntry: BookmarkEntry, label: String?, uri: String?, onUpdate: () -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO){
|
||||||
|
db.bookmarks().updateContent(bookmarkEntry.uid, label ?: "", uri ?: "")
|
||||||
|
onUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun delete(bookmarkEntry: BookmarkEntry, onDelete: () -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO){
|
||||||
|
val entity = db.bookmarks().getBookmark(bookmarkEntry.index)
|
||||||
|
db.bookmarks().delete(entity)
|
||||||
|
onDelete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package oppen.ariane.io.bookmarks
|
package oppen.ariane.io.database.bookmarks
|
||||||
|
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
|
@ -1,8 +1,8 @@
|
||||||
package oppen.ariane.io.bookmarks
|
package oppen.ariane.io.database.bookmarks
|
||||||
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
class Bookmark(
|
class BookmarkEntry(
|
||||||
val uid: Int,
|
val uid: Int,
|
||||||
val label: String,
|
val label: String,
|
||||||
val uri: URI,
|
val uri: URI,
|
|
@ -1,4 +1,4 @@
|
||||||
package oppen.ariane.io.bookmarks
|
package oppen.ariane.io.database.bookmarks
|
||||||
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package oppen.ariane.io.database.bookmarks
|
||||||
|
|
||||||
|
interface BookmarksDatasource {
|
||||||
|
|
||||||
|
fun get(onBookmarks: (List<BookmarkEntry>) -> Unit)
|
||||||
|
fun add(bookmarkEntry: BookmarkEntry, onAdded: () -> Unit)
|
||||||
|
fun delete(bookmarkEntry: BookmarkEntry, onDelete: () -> Unit)
|
||||||
|
|
||||||
|
fun moveUp(bookmarkEntry: BookmarkEntry, onMoved: () -> Unit)
|
||||||
|
fun moveDown(bookmarkEntry: BookmarkEntry, onMoved: () -> Unit)
|
||||||
|
fun update(bookmarkEntry: BookmarkEntry, label: String?, uri: String?, onUpdate: () -> Unit)
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package oppen.ariane.io.database.history
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import oppen.ariane.io.database.ArianeAbstractDatabase
|
||||||
|
|
||||||
|
class ArianeHistory(private val db: ArianeAbstractDatabase): HistoryDatasource {
|
||||||
|
|
||||||
|
override fun get(onHistory: (List<HistoryEntry>) -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO){
|
||||||
|
val dbBookmarks = db.history().getAll()
|
||||||
|
val history = mutableListOf<HistoryEntry>()
|
||||||
|
|
||||||
|
dbBookmarks.forEach { entity ->
|
||||||
|
history.add(HistoryEntry(entity.uid, entity.timestamp ?: 0L, Uri.parse(entity.uri)))
|
||||||
|
}
|
||||||
|
onHistory(history)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun add(entry: HistoryEntry, onAdded: () -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO){
|
||||||
|
val lastAdded = db.history().getLastAdded()
|
||||||
|
val entity = HistoryEntity(entry.uri.toString(), System.currentTimeMillis())
|
||||||
|
|
||||||
|
when (lastAdded) {
|
||||||
|
null -> db.history().insert(entity)
|
||||||
|
else -> {
|
||||||
|
when {
|
||||||
|
lastAdded.uri.toString() != entry.uri.toString() -> db.history().insert(entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun add(uri: Uri, onAdded: () -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO){
|
||||||
|
val lastAdded = db.history().getLastAdded()
|
||||||
|
val entity = HistoryEntity(uri.toString(), System.currentTimeMillis())
|
||||||
|
|
||||||
|
when (lastAdded) {
|
||||||
|
null -> db.history().insert(entity)
|
||||||
|
else -> {
|
||||||
|
when {
|
||||||
|
lastAdded.uri.toString() != uri.toString() -> db.history().insert(entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clear(onClear: () -> Unit) {
|
||||||
|
//todo
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun delete(entry: HistoryEntry, onDelete: () -> Unit) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO){
|
||||||
|
val entity = db.history().getEntry(entry.uid)
|
||||||
|
db.history().delete(entity)
|
||||||
|
onDelete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package oppen.ariane.io.database.history
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Query
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface HistoryDao {
|
||||||
|
@Query("SELECT * FROM history ORDER BY timestamp DESC")
|
||||||
|
suspend fun getAll(): List<HistoryEntity>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM history WHERE uid = :uid LIMIT 1")
|
||||||
|
fun getEntry(uid: Int): HistoryEntity
|
||||||
|
|
||||||
|
@Query("SELECT * FROM history ORDER BY timestamp DESC LIMIT 1")
|
||||||
|
fun getLastAdded(): HistoryEntity?
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
fun insert(vararg history: HistoryEntity)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
fun delete(history: HistoryEntity)
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package oppen.ariane.io.database.history
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
|
||||||
|
interface HistoryDatasource {
|
||||||
|
|
||||||
|
fun get(onHistory: (List<HistoryEntry>) -> Unit)
|
||||||
|
fun add(entry: HistoryEntry, onAdded: () -> Unit)
|
||||||
|
fun add(uri: Uri, onAdded: () -> Unit)
|
||||||
|
fun clear(onClear: () -> Unit)
|
||||||
|
fun delete(entry: HistoryEntry, onDelete: () -> Unit)
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package oppen.ariane.io.database.history
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(tableName = "history")
|
||||||
|
class HistoryEntity(
|
||||||
|
@ColumnInfo(name = "uri") val uri: String?,
|
||||||
|
@ColumnInfo(name = "timestamp") val timestamp: Long?
|
||||||
|
){
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
var uid: Int = 0
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package oppen.ariane.io.database.history
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
|
||||||
|
class HistoryEntry(
|
||||||
|
val uid: Int,
|
||||||
|
val timestamp: Long,
|
||||||
|
val uri: Uri
|
||||||
|
)
|
|
@ -2,6 +2,7 @@ package oppen.ariane.io.gemini
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import oppen.ariane.io.GemState
|
import oppen.ariane.io.GemState
|
||||||
|
import oppen.ariane.io.database.history.ArianeHistory
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
interface Datasource {
|
interface Datasource {
|
||||||
|
@ -11,8 +12,8 @@ interface Datasource {
|
||||||
fun goBack(onUpdate: (state: GemState) -> Unit)
|
fun goBack(onUpdate: (state: GemState) -> Unit)
|
||||||
|
|
||||||
companion object{
|
companion object{
|
||||||
fun factory(context: Context): Datasource {
|
fun factory(context: Context, history: ArianeHistory): Datasource {
|
||||||
return GeminiDatasource(context)
|
return GeminiDatasource(context, history)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,6 +6,8 @@ import androidx.preference.PreferenceManager
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import oppen.ariane.io.GemState
|
import oppen.ariane.io.GemState
|
||||||
|
import oppen.ariane.io.database.history.ArianeHistory
|
||||||
|
import oppen.ariane.io.database.history.HistoryEntry
|
||||||
import oppen.ariane.io.keymanager.ArianeKeyManager
|
import oppen.ariane.io.keymanager.ArianeKeyManager
|
||||||
import oppen.isGemini
|
import oppen.isGemini
|
||||||
import oppen.toURI
|
import oppen.toURI
|
||||||
|
@ -18,7 +20,7 @@ import javax.net.ssl.*
|
||||||
|
|
||||||
const val GEMINI_SCHEME = "gemini"
|
const val GEMINI_SCHEME = "gemini"
|
||||||
|
|
||||||
class GeminiDatasource(private val context: Context): Datasource {
|
class GeminiDatasource(private val context: Context, val history: ArianeHistory): Datasource {
|
||||||
|
|
||||||
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
private val addressBuilder = AddressBuilder()
|
private val addressBuilder = AddressBuilder()
|
||||||
|
@ -88,7 +90,7 @@ class GeminiDatasource(private val context: Context): Datasource {
|
||||||
else -> SSLContext.getInstance(protocol)
|
else -> SSLContext.getInstance(protocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
sslContext.init(arianeKeyManager.getFactory()?.keyManagers, DummyTrustManager.get(), null)
|
sslContext.init(arianeKeyManager.getFactory(context)?.keyManagers, DummyTrustManager.get(), null)
|
||||||
val factory: SSLSocketFactory = sslContext.socketFactory
|
val factory: SSLSocketFactory = sslContext.socketFactory
|
||||||
|
|
||||||
//todo to here ----------------------------------------------------------------------------
|
//todo to here ----------------------------------------------------------------------------
|
||||||
|
@ -140,6 +142,11 @@ class GeminiDatasource(private val context: Context): Datasource {
|
||||||
|
|
||||||
println("Ariane: response header: $headerLine")
|
println("Ariane: response header: $headerLine")
|
||||||
|
|
||||||
|
if(headerLine == null){
|
||||||
|
onUpdate(GemState.ResponseError(GeminiResponse.Header(-2, "Server did not respond with a Gemini header")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val header = GeminiResponse.parseHeader(headerLine)
|
val header = GeminiResponse.parseHeader(headerLine)
|
||||||
|
|
||||||
when {
|
when {
|
||||||
|
@ -197,6 +204,8 @@ class GeminiDatasource(private val context: Context): Datasource {
|
||||||
runtimeHistory.add(uri)
|
runtimeHistory.add(uri)
|
||||||
println("Ariane added $uri to runtime history (size ${runtimeHistory.size})")
|
println("Ariane added $uri to runtime history (size ${runtimeHistory.size})")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
history.add(uri.toUri()){}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getString(socket: SSLSocket?, uri: URI, header: GeminiResponse.Header, onUpdate: (state: GemState) -> Unit){
|
private fun getString(socket: SSLSocket?, uri: URI, header: GeminiResponse.Header, onUpdate: (state: GemState) -> Unit){
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package oppen.ariane.io.keymanager
|
package oppen.ariane.io.keymanager
|
||||||
|
|
||||||
import android.R
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import oppen.ariane.R
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.KeyStore
|
import java.security.KeyStore
|
||||||
|
@ -17,7 +17,7 @@ class ArianeKeyManager {
|
||||||
val hasLoadedKey = false
|
val hasLoadedKey = false
|
||||||
return when {
|
return when {
|
||||||
hasLoadedKey -> {
|
hasLoadedKey -> {
|
||||||
val keyStore: KeyStore = KeyStore.getInstance("BKS")
|
val keyStore: KeyStore = KeyStore.getInstance("BKS")//or "pkcs12"v?
|
||||||
val inputStream: InputStream = ByteArrayInputStream("dummy".toByteArray())
|
val inputStream: InputStream = ByteArrayInputStream("dummy".toByteArray())
|
||||||
keyStore.load(inputStream, "yourKeyStorePassword".toCharArray())
|
keyStore.load(inputStream, "yourKeyStorePassword".toCharArray())
|
||||||
inputStream.close()
|
inputStream.close()
|
||||||
|
@ -30,4 +30,14 @@ class ArianeKeyManager {
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getFactoryDemo(context: Context): KeyManagerFactory? {
|
||||||
|
val keyStore: KeyStore = KeyStore.getInstance("pkcs12")//or "pkcs12"v?
|
||||||
|
keyStore.load(context.resources.openRawResource(R.raw.cert), "PASSWORD".toCharArray())
|
||||||
|
|
||||||
|
val keyManagerFactory: KeyManagerFactory = KeyManagerFactory.getInstance("X509")
|
||||||
|
keyManagerFactory.init(keyStore, "PASSWORD".toCharArray())
|
||||||
|
|
||||||
|
return keyManagerFactory
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,6 @@ package oppen.ariane.ui
|
||||||
|
|
||||||
import android.app.DownloadManager
|
import android.app.DownloadManager
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.media.MediaPlayer
|
import android.media.MediaPlayer
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
@ -19,11 +18,11 @@ import oppen.ariane.Ariane
|
||||||
import oppen.ariane.R
|
import oppen.ariane.R
|
||||||
import oppen.ariane.databinding.ActivityGemBinding
|
import oppen.ariane.databinding.ActivityGemBinding
|
||||||
import oppen.ariane.io.GemState
|
import oppen.ariane.io.GemState
|
||||||
import oppen.ariane.io.bookmarks.BookmarksDatasource
|
import oppen.ariane.io.database.ArianeDatabase
|
||||||
|
import oppen.ariane.io.database.bookmarks.BookmarksDatasource
|
||||||
import oppen.ariane.io.gemini.Datasource
|
import oppen.ariane.io.gemini.Datasource
|
||||||
import oppen.ariane.io.gemini.GeminiResponse
|
import oppen.ariane.io.gemini.GeminiResponse
|
||||||
import oppen.ariane.io.gemini.RuntimeCache
|
import oppen.ariane.io.gemini.RuntimeCache
|
||||||
import oppen.ariane.io.history.uris.HistoryInterface
|
|
||||||
import oppen.ariane.ui.audio_player.AudioPlayer
|
import oppen.ariane.ui.audio_player.AudioPlayer
|
||||||
import oppen.ariane.ui.bookmarks.BookmarkDialog
|
import oppen.ariane.ui.bookmarks.BookmarkDialog
|
||||||
import oppen.ariane.ui.bookmarks.BookmarksDialog
|
import oppen.ariane.ui.bookmarks.BookmarksDialog
|
||||||
|
@ -36,7 +35,6 @@ import oppen.ariane.ui.modals_menus.input.InputDialog
|
||||||
import oppen.ariane.ui.modals_menus.overflow.OverflowPopup
|
import oppen.ariane.ui.modals_menus.overflow.OverflowPopup
|
||||||
import oppen.ariane.ui.settings.SettingsActivity
|
import oppen.ariane.ui.settings.SettingsActivity
|
||||||
import oppen.hideKeyboard
|
import oppen.hideKeyboard
|
||||||
import oppen.toURI
|
|
||||||
import oppen.visibleRetainingSpace
|
import oppen.visibleRetainingSpace
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
|
@ -50,14 +48,12 @@ const val CREATE_BINARY_FILE_REQ = 630
|
||||||
class GemActivity : AppCompatActivity() {
|
class GemActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private var inSearch = false
|
private var inSearch = false
|
||||||
|
|
||||||
private val mediaPlayer = MediaPlayer()
|
private val mediaPlayer = MediaPlayer()
|
||||||
|
|
||||||
private lateinit var bookmarkDatasource: BookmarksDatasource
|
private lateinit var bookmarkDatasource: BookmarksDatasource
|
||||||
|
|
||||||
private val model by viewModels<GemViewModel>()
|
private val model by viewModels<GemViewModel>()
|
||||||
private lateinit var binding: ActivityGemBinding
|
private lateinit var binding: ActivityGemBinding
|
||||||
private lateinit var history: HistoryInterface
|
|
||||||
private val adapter = GemtextAdapter { adapter, uri, longTap, position: Int, view ->
|
private val adapter = GemtextAdapter { adapter, uri, longTap, position: Int, view ->
|
||||||
if(longTap){
|
if(longTap){
|
||||||
LinkPopup.show(view, uri){ menuId ->
|
LinkPopup.show(view, uri){ menuId ->
|
||||||
|
@ -89,6 +85,7 @@ class GemActivity : AppCompatActivity() {
|
||||||
binding.addressEdit.hint = getString(R.string.main_input_hint)
|
binding.addressEdit.hint = getString(R.string.main_input_hint)
|
||||||
inSearch = false
|
inSearch = false
|
||||||
}
|
}
|
||||||
|
|
||||||
model.request(uri)
|
model.request(uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +93,8 @@ class GemActivity : AppCompatActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
bookmarkDatasource = BookmarksDatasource.getDefault(applicationContext)
|
val db = ArianeDatabase(applicationContext)
|
||||||
|
bookmarkDatasource = db.bookmarks()
|
||||||
|
|
||||||
binding = DataBindingUtil.setContentView(this, R.layout.activity_gem)
|
binding = DataBindingUtil.setContentView(this, R.layout.activity_gem)
|
||||||
binding.viewmodel = model
|
binding.viewmodel = model
|
||||||
|
@ -105,52 +103,11 @@ class GemActivity : AppCompatActivity() {
|
||||||
binding.gemtextRecycler.layoutManager = LinearLayoutManager(this)
|
binding.gemtextRecycler.layoutManager = LinearLayoutManager(this)
|
||||||
binding.gemtextRecycler.adapter = adapter
|
binding.gemtextRecycler.adapter = adapter
|
||||||
|
|
||||||
history = HistoryInterface.default(this)
|
|
||||||
|
|
||||||
model.initialise(
|
model.initialise(
|
||||||
home = PreferenceManager.getDefaultSharedPreferences(this).getString("home_capsule", Ariane.DEFAULT_HOME_CAPSULE) ?: Ariane.DEFAULT_HOME_CAPSULE,
|
home = PreferenceManager.getDefaultSharedPreferences(this).getString("home_capsule", Ariane.DEFAULT_HOME_CAPSULE) ?: Ariane.DEFAULT_HOME_CAPSULE,
|
||||||
gemini = Datasource.factory(this),
|
gemini = Datasource.factory(this, db.history()),
|
||||||
bookmarks = BookmarksDatasource.getDefault(applicationContext)
|
db = db,
|
||||||
){ state ->
|
onState = this::handleState)
|
||||||
|
|
||||||
binding.pullToRefresh.isRefreshing = false
|
|
||||||
|
|
||||||
when(state){
|
|
||||||
is GemState.AppQuery -> runOnUiThread { showAlert("App backdoor/query not implemented yet") }
|
|
||||||
is GemState.ResponseInput -> runOnUiThread {
|
|
||||||
loadingView(false)
|
|
||||||
InputDialog.show(this, state) { queryAddress ->
|
|
||||||
model.request(queryAddress)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is GemState.Requesting -> loadingView(true)
|
|
||||||
is GemState.NotGeminiRequest -> externalProtocol(state)
|
|
||||||
is GemState.ResponseError -> showAlert("${GeminiResponse.getCodeString(state.header.code)}: ${state.header.meta}")
|
|
||||||
is GemState.ResponseGemtext -> renderGemtext(state)
|
|
||||||
is GemState.ResponseText -> renderText(state)
|
|
||||||
is GemState.ResponseImage -> renderImage(state)
|
|
||||||
is GemState.ResponseAudio -> renderAudio(state)
|
|
||||||
is GemState.ResponseBinary -> renderBinary(state)
|
|
||||||
is GemState.Blank -> {
|
|
||||||
binding.addressEdit.setText("")
|
|
||||||
adapter.render(arrayListOf())
|
|
||||||
}
|
|
||||||
is GemState.ResponseUnknownMime -> {
|
|
||||||
runOnUiThread {
|
|
||||||
loadingView(false)
|
|
||||||
AlertDialog.Builder(this, R.style.AppDialogTheme)
|
|
||||||
.setTitle(R.string.unknown_mime_dialog_title)
|
|
||||||
.setMessage("Address: ${state.uri}\nMeta: ${state.header.meta}")
|
|
||||||
.setPositiveButton("Download") { _, _ ->
|
|
||||||
loadingView(true)
|
|
||||||
model.requestBinaryDownload(state.uri)
|
|
||||||
}
|
|
||||||
.setNegativeButton("Cancel") { _, _ -> }
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.addressEdit.setOnEditorActionListener { _, actionId, _ ->
|
binding.addressEdit.setOnEditorActionListener { _, actionId, _ ->
|
||||||
when (actionId) {
|
when (actionId) {
|
||||||
|
@ -210,7 +167,7 @@ class GemActivity : AppCompatActivity() {
|
||||||
startActivity(Intent.createChooser(this, null))
|
startActivity(Intent.createChooser(this, null))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.overflow_menu_history -> HistoryDialog.show(this) { historyAddress ->
|
R.id.overflow_menu_history -> HistoryDialog.show(this, db.history()) { historyAddress ->
|
||||||
model.request(historyAddress)
|
model.request(historyAddress)
|
||||||
}
|
}
|
||||||
R.id.overflow_menu_about -> AboutDialog.show(this)
|
R.id.overflow_menu_about -> AboutDialog.show(this)
|
||||||
|
@ -235,6 +192,46 @@ class GemActivity : AppCompatActivity() {
|
||||||
checkIntentExtras(intent)
|
checkIntentExtras(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleState(state: GemState) {
|
||||||
|
binding.pullToRefresh.isRefreshing = false
|
||||||
|
|
||||||
|
when (state) {
|
||||||
|
is GemState.AppQuery -> runOnUiThread { showAlert("App backdoor/query not implemented yet") }
|
||||||
|
is GemState.ResponseInput -> runOnUiThread {
|
||||||
|
loadingView(false)
|
||||||
|
InputDialog.show(this, state) { queryAddress ->
|
||||||
|
model.request(queryAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is GemState.Requesting -> loadingView(true)
|
||||||
|
is GemState.NotGeminiRequest -> externalProtocol(state)
|
||||||
|
is GemState.ResponseError -> showAlert("${GeminiResponse.getCodeString(state.header.code)}: ${state.header.meta}")
|
||||||
|
is GemState.ResponseGemtext -> renderGemtext(state)
|
||||||
|
is GemState.ResponseText -> renderText(state)
|
||||||
|
is GemState.ResponseImage -> renderImage(state)
|
||||||
|
is GemState.ResponseAudio -> renderAudio(state)
|
||||||
|
is GemState.ResponseBinary -> renderBinary(state)
|
||||||
|
is GemState.Blank -> {
|
||||||
|
binding.addressEdit.setText("")
|
||||||
|
adapter.render(arrayListOf())
|
||||||
|
}
|
||||||
|
is GemState.ResponseUnknownMime -> {
|
||||||
|
runOnUiThread {
|
||||||
|
loadingView(false)
|
||||||
|
AlertDialog.Builder(this, R.style.AppDialogTheme)
|
||||||
|
.setTitle(R.string.unknown_mime_dialog_title)
|
||||||
|
.setMessage("Address: ${state.uri}\nMeta: ${state.header.meta}")
|
||||||
|
.setPositiveButton("Download") { _, _ ->
|
||||||
|
loadingView(true)
|
||||||
|
model.requestBinaryDownload(state.uri)
|
||||||
|
}
|
||||||
|
.setNegativeButton("Cancel") { _, _ -> }
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent?) {
|
override fun onNewIntent(intent: Intent?) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
|
|
||||||
|
@ -305,8 +302,6 @@ class GemActivity : AppCompatActivity() {
|
||||||
binding.gemtextRecycler.post {
|
binding.gemtextRecycler.post {
|
||||||
binding.gemtextRecycler.scrollToPosition(0)
|
binding.gemtextRecycler.scrollToPosition(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
history.add(state.uri.toString())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderText(state: GemState.ResponseText) = runOnUiThread {
|
private fun renderText(state: GemState.ResponseText) = runOnUiThread {
|
||||||
|
@ -401,10 +396,14 @@ class GemActivity : AppCompatActivity() {
|
||||||
if(visible) binding.appBar.setExpanded(true)
|
if(visible) binding.appBar.setExpanded(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if(model.canGoBack()){
|
if(model.canGoBack()){
|
||||||
model.goBack()
|
model.goBack{ state ->
|
||||||
|
/*
|
||||||
|
Passing the callback here so we can eventually add a mechanism to restore scroll position
|
||||||
|
*/
|
||||||
|
handleState(state)
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
println("Ariane history is empty - exiting")
|
println("Ariane history is empty - exiting")
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
|
|
|
@ -2,21 +2,21 @@ package oppen.ariane.ui
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import oppen.ariane.Ariane
|
|
||||||
import oppen.ariane.io.gemini.Datasource
|
import oppen.ariane.io.gemini.Datasource
|
||||||
import oppen.ariane.io.GemState
|
import oppen.ariane.io.GemState
|
||||||
import oppen.ariane.io.bookmarks.BookmarksDatasource
|
import oppen.ariane.io.database.ArianeDatabase
|
||||||
|
import oppen.ariane.io.database.bookmarks.BookmarksDatasource
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
class GemViewModel: ViewModel() {
|
class GemViewModel: ViewModel() {
|
||||||
|
|
||||||
private lateinit var gemini: Datasource
|
private lateinit var gemini: Datasource
|
||||||
private lateinit var bookmarks: BookmarksDatasource
|
private lateinit var db: ArianeDatabase
|
||||||
private var onState: (state: GemState) -> Unit = {}
|
private var onState: (state: GemState) -> Unit = {}
|
||||||
|
|
||||||
fun initialise(home: String, gemini: Datasource, bookmarks: BookmarksDatasource, onState: (state: GemState) -> Unit){
|
fun initialise(home: String, gemini: Datasource, db: ArianeDatabase, onState: (state: GemState) -> Unit){
|
||||||
this.gemini = gemini
|
this.gemini = gemini
|
||||||
this.bookmarks = bookmarks
|
this.db = db
|
||||||
this.onState = onState
|
this.onState = onState
|
||||||
|
|
||||||
request(home)
|
request(home)
|
||||||
|
@ -49,5 +49,5 @@ class GemViewModel: ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun canGoBack(): Boolean = gemini.canGoBack()
|
fun canGoBack(): Boolean = gemini.canGoBack()
|
||||||
fun goBack() = gemini.goBack(onState)
|
fun goBack(onGoBack: (state: GemState) -> Unit) = gemini.goBack(onGoBack)
|
||||||
}
|
}
|
|
@ -7,8 +7,8 @@ import android.view.View
|
||||||
import androidx.appcompat.app.AppCompatDialog
|
import androidx.appcompat.app.AppCompatDialog
|
||||||
import kotlinx.android.synthetic.main.fragment_bookmark_dialog.view.*
|
import kotlinx.android.synthetic.main.fragment_bookmark_dialog.view.*
|
||||||
import oppen.ariane.R
|
import oppen.ariane.R
|
||||||
import oppen.ariane.io.bookmarks.Bookmark
|
import oppen.ariane.io.database.bookmarks.BookmarkEntry
|
||||||
import oppen.ariane.io.bookmarks.BookmarksDatasource
|
import oppen.ariane.io.database.bookmarks.BookmarksDatasource
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ class BookmarkDialog(
|
||||||
|
|
||||||
bookmarkDatasource.add(
|
bookmarkDatasource.add(
|
||||||
|
|
||||||
Bookmark(
|
BookmarkEntry(
|
||||||
uid = -1,
|
uid = -1,
|
||||||
label = view.bookmark_name.text.toString(),
|
label = view.bookmark_name.text.toString(),
|
||||||
uri = URI.create(view.bookmark_uri.text.toString()),
|
uri = URI.create(view.bookmark_uri.text.toString()),
|
||||||
|
|
|
@ -6,18 +6,18 @@ import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlinx.android.synthetic.main.bookmark.view.*
|
import kotlinx.android.synthetic.main.bookmark.view.*
|
||||||
import oppen.ariane.R
|
import oppen.ariane.R
|
||||||
import oppen.ariane.io.bookmarks.Bookmark
|
import oppen.ariane.io.database.bookmarks.BookmarkEntry
|
||||||
import oppen.visible
|
import oppen.visible
|
||||||
|
|
||||||
class BookmarksAdapter(val onBookmark: (bookmark: Bookmark) -> Unit, val onOverflow: (view: View, bookmark: Bookmark, isFirst: Boolean, isLast: Boolean) -> Unit): RecyclerView.Adapter<BookmarksAdapter.ViewHolder>() {
|
class BookmarksAdapter(val onBookmark: (bookmarkEntry: BookmarkEntry) -> Unit, val onOverflow: (view: View, bookmarkEntry: BookmarkEntry, isFirst: Boolean, isLast: Boolean) -> Unit): RecyclerView.Adapter<BookmarksAdapter.ViewHolder>() {
|
||||||
|
|
||||||
val bookmarks = mutableListOf<Bookmark>()
|
val bookmarks = mutableListOf<BookmarkEntry>()
|
||||||
|
|
||||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
|
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
|
||||||
|
|
||||||
fun update(bookmarks: List<Bookmark>){
|
fun update(bookmarkEntries: List<BookmarkEntry>){
|
||||||
this.bookmarks.clear()
|
this.bookmarks.clear()
|
||||||
this.bookmarks.addAll(bookmarks)
|
this.bookmarks.addAll(bookmarkEntries)
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,19 +51,19 @@ class BookmarksAdapter(val onBookmark: (bookmark: Bookmark) -> Unit, val onOverf
|
||||||
|
|
||||||
override fun getItemCount(): Int = bookmarks.size
|
override fun getItemCount(): Int = bookmarks.size
|
||||||
|
|
||||||
fun hide(bookmark: Bookmark) {
|
fun hide(bookmarkEntry: BookmarkEntry) {
|
||||||
bookmark.visible = false
|
bookmarkEntry.visible = false
|
||||||
notifyItemChanged(bookmarks.indexOf(bookmark))
|
notifyItemChanged(bookmarks.indexOf(bookmarkEntry))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun show(bookmark: Bookmark) {
|
fun show(bookmarkEntry: BookmarkEntry) {
|
||||||
bookmark.visible = true
|
bookmarkEntry.visible = true
|
||||||
notifyItemChanged(bookmarks.indexOf(bookmark))
|
notifyItemChanged(bookmarks.indexOf(bookmarkEntry))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remove(bookmark: Bookmark){
|
fun remove(bookmarkEntry: BookmarkEntry){
|
||||||
val index = bookmarks.indexOf(bookmark)
|
val index = bookmarks.indexOf(bookmarkEntry)
|
||||||
bookmarks.remove(bookmark)
|
bookmarks.remove(bookmarkEntry)
|
||||||
notifyItemRemoved(index)
|
notifyItemRemoved(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,15 +11,15 @@ import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.android.synthetic.main.dialog_bookmarks.view.*
|
import kotlinx.android.synthetic.main.dialog_bookmarks.view.*
|
||||||
import oppen.ariane.R
|
import oppen.ariane.R
|
||||||
import oppen.ariane.io.bookmarks.Bookmark
|
import oppen.ariane.io.database.bookmarks.BookmarkEntry
|
||||||
import oppen.ariane.io.bookmarks.BookmarksDatasource
|
import oppen.ariane.io.database.bookmarks.BookmarksDatasource
|
||||||
import oppen.visible
|
import oppen.visible
|
||||||
|
|
||||||
|
|
||||||
class BookmarksDialog(
|
class BookmarksDialog(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val bookmarkDatasource: BookmarksDatasource,
|
private val bookmarkDatasource: BookmarksDatasource,
|
||||||
onBookmark: (bookmark: Bookmark) -> Unit): AppCompatDialog(context, R.style.FSDialog) {
|
onBookmark: (bookmarkEntry: BookmarkEntry) -> Unit): AppCompatDialog(context, R.style.FSDialog) {
|
||||||
|
|
||||||
var bookmarksAdapter: BookmarksAdapter
|
var bookmarksAdapter: BookmarksAdapter
|
||||||
|
|
||||||
|
@ -82,9 +82,9 @@ class BookmarksDialog(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun edit(bookmark: Bookmark){
|
private fun edit(bookmarkEntry: BookmarkEntry){
|
||||||
BookmarkDialog(context, BookmarkDialog.mode_edit, null, bookmark.uri.toString(), bookmark.label){ label, uri ->
|
BookmarkDialog(context, BookmarkDialog.mode_edit, null, bookmarkEntry.uri.toString(), bookmarkEntry.label){ label, uri ->
|
||||||
bookmarkDatasource.update(bookmark, label, uri){
|
bookmarkDatasource.update(bookmarkEntry, label, uri){
|
||||||
bookmarkDatasource.get {bookmarks ->
|
bookmarkDatasource.get {bookmarks ->
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
bookmarksAdapter.update(bookmarks)
|
bookmarksAdapter.update(bookmarks)
|
||||||
|
@ -99,15 +99,15 @@ class BookmarksDialog(
|
||||||
* Bookmark isn't actually deleted from the DB until the Snackbar disappears. Which is nice.
|
* Bookmark isn't actually deleted from the DB until the Snackbar disappears. Which is nice.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private fun delete(bookmark: Bookmark){
|
private fun delete(bookmarkEntry: BookmarkEntry){
|
||||||
//OnDelete
|
//OnDelete
|
||||||
bookmarksAdapter.hide(bookmark)
|
bookmarksAdapter.hide(bookmarkEntry)
|
||||||
Snackbar.make(view, "Deleted ${bookmark.label}", Snackbar.LENGTH_SHORT).addCallback(object: Snackbar.Callback() {
|
Snackbar.make(view, "Deleted ${bookmarkEntry.label}", Snackbar.LENGTH_SHORT).addCallback(object: Snackbar.Callback() {
|
||||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) = when (event) {
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) = when (event) {
|
||||||
BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_ACTION -> bookmarksAdapter.show(bookmark)
|
BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_ACTION -> bookmarksAdapter.show(bookmarkEntry)
|
||||||
else -> bookmarkDatasource.delete(bookmark){
|
else -> bookmarkDatasource.delete(bookmarkEntry){
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
bookmarksAdapter.remove(bookmark)
|
bookmarksAdapter.remove(bookmarkEntry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,8 +116,8 @@ class BookmarksDialog(
|
||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun moveUp(bookmark: Bookmark){
|
private fun moveUp(bookmarkEntry: BookmarkEntry){
|
||||||
bookmarkDatasource.moveUp(bookmark){
|
bookmarkDatasource.moveUp(bookmarkEntry){
|
||||||
bookmarkDatasource.get { bookmarks ->
|
bookmarkDatasource.get { bookmarks ->
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
bookmarksAdapter.update(bookmarks)
|
bookmarksAdapter.update(bookmarks)
|
||||||
|
@ -126,8 +126,8 @@ class BookmarksDialog(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun moveDown(bookmark: Bookmark){
|
private fun moveDown(bookmarkEntry: BookmarkEntry){
|
||||||
bookmarkDatasource.moveDown(bookmark){
|
bookmarkDatasource.moveDown(bookmarkEntry){
|
||||||
bookmarkDatasource.get { bookmarks ->
|
bookmarkDatasource.get { bookmarks ->
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
bookmarksAdapter.update(bookmarks)
|
bookmarksAdapter.update(bookmarks)
|
||||||
|
|
|
@ -7,8 +7,9 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlinx.android.synthetic.main.row_history.view.*
|
import kotlinx.android.synthetic.main.row_history.view.*
|
||||||
import oppen.delay
|
import oppen.delay
|
||||||
import oppen.ariane.R
|
import oppen.ariane.R
|
||||||
|
import oppen.ariane.io.database.history.HistoryEntry
|
||||||
|
|
||||||
class HistoryAdapter(val history: List<String>, val onClick:(address: String) -> Unit): RecyclerView.Adapter<HistoryAdapter.ViewHolder>() {
|
class HistoryAdapter(val history: List<HistoryEntry>, val onClick:(entry: HistoryEntry) -> Unit): RecyclerView.Adapter<HistoryAdapter.ViewHolder>() {
|
||||||
|
|
||||||
class ViewHolder(view: View): RecyclerView.ViewHolder(view)
|
class ViewHolder(view: View): RecyclerView.ViewHolder(view)
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ class HistoryAdapter(val history: List<String>, val onClick:(address: String) ->
|
||||||
override fun getItemCount(): Int = history.size
|
override fun getItemCount(): Int = history.size
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
holder.itemView.history_address.text = history[position]
|
holder.itemView.history_address.text = history[position].uri.toString()
|
||||||
holder.itemView.history_row.setOnClickListener {
|
holder.itemView.history_row.setOnClickListener {
|
||||||
delay(500){
|
delay(500){
|
||||||
onClick(history[holder.adapterPosition])
|
onClick(history[holder.adapterPosition])
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package oppen.ariane.ui.modals_menus.history
|
package oppen.ariane.ui.modals_menus.history
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
@ -11,14 +13,11 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import kotlinx.android.synthetic.main.dialog_about.view.close_tab_dialog
|
import kotlinx.android.synthetic.main.dialog_about.view.close_tab_dialog
|
||||||
import kotlinx.android.synthetic.main.dialog_history.view.*
|
import kotlinx.android.synthetic.main.dialog_history.view.*
|
||||||
import oppen.ariane.R
|
import oppen.ariane.R
|
||||||
|
import oppen.ariane.io.database.history.ArianeHistory
|
||||||
import oppen.ariane.io.gemini.RuntimeCache
|
import oppen.ariane.io.gemini.RuntimeCache
|
||||||
import oppen.ariane.io.history.uris.HistoryInterface
|
|
||||||
|
|
||||||
object HistoryDialog {
|
object HistoryDialog {
|
||||||
fun show(context: Context, onHistoryItem: (address: String) -> Unit){
|
fun show(context: Context, history: ArianeHistory, onHistoryItem: (address: String) -> Unit){
|
||||||
val historyCache = HistoryInterface.default(context)
|
|
||||||
val history = historyCache.get()
|
|
||||||
|
|
||||||
val dialog = AppCompatDialog(context, R.style.AppTheme)
|
val dialog = AppCompatDialog(context, R.style.AppTheme)
|
||||||
|
|
||||||
val view = View.inflate(context, R.layout.dialog_history, null)
|
val view = View.inflate(context, R.layout.dialog_history, null)
|
||||||
|
@ -34,9 +33,10 @@ object HistoryDialog {
|
||||||
inflater.inflate(R.menu.history_overflow_menu, popup.menu)
|
inflater.inflate(R.menu.history_overflow_menu, popup.menu)
|
||||||
popup.setOnMenuItemClickListener { menuItem ->
|
popup.setOnMenuItemClickListener { menuItem ->
|
||||||
if(menuItem.itemId == R.id.history_overflow_clear_history){
|
if(menuItem.itemId == R.id.history_overflow_clear_history){
|
||||||
historyCache.clear()
|
history.clear {
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
Toast.makeText(context, "History cleared", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "History cleared", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}else if(menuItem.itemId == R.id.history_overflow_clear_runtime_cache){
|
}else if(menuItem.itemId == R.id.history_overflow_clear_runtime_cache){
|
||||||
RuntimeCache.clear()
|
RuntimeCache.clear()
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
@ -49,12 +49,16 @@ object HistoryDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
view.history_recycler.layoutManager = LinearLayoutManager(context)
|
view.history_recycler.layoutManager = LinearLayoutManager(context)
|
||||||
view.history_recycler.adapter = HistoryAdapter(history.asReversed()){ address ->
|
|
||||||
onHistoryItem(address)
|
history.get { history ->
|
||||||
dialog.dismiss()
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
view.history_recycler.adapter = HistoryAdapter(history) { entry ->
|
||||||
|
onHistoryItem(entry.uri.toString())
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.show()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Binary file not shown.
Loading…
Reference in New Issue