Identities: WIP

This commit overwrites the version 1 database schema. Yeah as long as
Comet is not out of alpha, I'm not dealing with this horrendous
migration process.
This commit is contained in:
dece 2022-01-26 01:26:29 +01:00
parent 020f48149b
commit 1f2be8cdee
13 changed files with 236 additions and 15 deletions

View file

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "44cb07b76e6b8abfaa988e1d3696a347",
"identityHash": "70da3095877de4a82021855471523b90",
"entities": [
{
"tableName": "HistoryEntry",
@ -35,12 +35,76 @@
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "Identity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `key` TEXT NOT NULL, `name` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "IdentityUsage",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `uri` TEXT NOT NULL, `identityId` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "uri",
"columnName": "uri",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "identityId",
"columnName": "identityId",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '44cb07b76e6b8abfaa988e1d3696a347')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '70da3095877de4a82021855471523b90')"
]
}
}

View file

@ -1,13 +1,22 @@
package dev.lowrespalmtree.comet
import android.content.Context
import androidx.room.AutoMigration
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(entities = [History.HistoryEntry::class], version = 1)
@Database(
entities = [
History.HistoryEntry::class,
Identities.Identity::class,
Identities.IdentityUsage::class,
],
version = 1
)
abstract class AppDatabase : RoomDatabase() {
abstract fun historyEntryDao(): History.HistoryEntryDao
abstract fun identityDao(): Identities.IdentityDao
}
object Database {
@ -16,6 +25,6 @@ object Database {
fun init(context: Context) {
if (::INSTANCE.isInitialized)
return
INSTANCE = Room.databaseBuilder(context, AppDatabase::class.java, "comet").build()
INSTANCE = Room.databaseBuilder(context, AppDatabase::class.java, "comet.db").build()
}
}

View file

@ -5,9 +5,9 @@ import androidx.room.*
object History {
@Entity
data class HistoryEntry(
@PrimaryKey @ColumnInfo(name = "uri") val uri: String,
@ColumnInfo(name = "title") var title: String?,
@ColumnInfo(name = "lastVisit") var lastVisit: Long,
@PrimaryKey val uri: String,
var title: String?,
var lastVisit: Long,
)
@Dao

View file

@ -6,9 +6,10 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
@ -21,8 +22,8 @@ import kotlinx.coroutines.launch
@ExperimentalCoroutinesApi
class HistoryFragment : Fragment(), HistoryItemAdapterListener {
private val vm: HistoryViewModel by viewModels()
private lateinit var binding: FragmentHistoryListBinding
private lateinit var historyViewModel: HistoryViewModel
private lateinit var adapter: HistoryItemAdapter
override fun onCreateView(
@ -35,14 +36,13 @@ class HistoryFragment : Fragment(), HistoryItemAdapterListener {
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
historyViewModel = ViewModelProvider(this)[HistoryViewModel::class.java]
adapter = HistoryItemAdapter(this)
binding.list.layoutManager = LinearLayoutManager(requireContext())
binding.list.adapter = adapter
historyViewModel.items.observe(viewLifecycleOwner, { adapter.setItems(it) })
vm.items.observe(viewLifecycleOwner, { adapter.setItems(it) })
historyViewModel.refreshHistory()
vm.refreshHistory()
}
override fun onItemClick(url: String) {
@ -51,7 +51,9 @@ class HistoryFragment : Fragment(), HistoryItemAdapterListener {
}
@ExperimentalCoroutinesApi
class HistoryViewModel : ViewModel() {
class HistoryViewModel(
@Suppress("unused") private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val items: MutableLiveData<List<HistoryEntry>>
by lazy { MutableLiveData<List<HistoryEntry>>() }

View file

@ -0,0 +1,38 @@
package dev.lowrespalmtree.comet
import androidx.room.*
object Identities {
@Entity
data class Identity(
/** ID. */
@PrimaryKey(autoGenerate = true) val id: Int,
/** Key to retrieve certificate from the keystore. */
val key: String,
/** Label for this identity. */
val name: String?,
)
@Entity
data class IdentityUsage(
/** ID. */
@PrimaryKey(autoGenerate = true) val id: Int,
/** URL path where an identity can be used. */
val uri: String,
/** ID of the Identity to use. */
val identityId: Int
)
@Dao
interface IdentityDao {
@Insert
suspend fun insert(vararg entries: Identity)
@Query("SELECT * FROM IdentityUsage WHERE :identityId = identityId")
fun getUsagesFor(identityId: Int): List<IdentityUsage>
}
suspend fun insert(key: String, name: String? = null) {
Database.INSTANCE.identityDao().insert(Identity(0, key, name))
}
}

View file

@ -0,0 +1,21 @@
package dev.lowrespalmtree.comet
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import dev.lowrespalmtree.comet.databinding.FragmentIdentitiesBinding
class IdentitiesFragment : Fragment() {
private lateinit var binding: FragmentIdentitiesBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentIdentitiesBinding.inflate(layoutInflater)
return binding.root
}
}

View file

@ -0,0 +1,23 @@
package dev.lowrespalmtree.comet
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import dev.lowrespalmtree.comet.databinding.FragmentIdentityBinding
class IdentityAdapter : RecyclerView.Adapter<HistoryItemAdapter.ViewHolder>() {
private var identities = listOf<Unit>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HistoryItemAdapter.ViewHolder {
TODO("Not yet implemented")
}
override fun onBindViewHolder(holder: HistoryItemAdapter.ViewHolder, position: Int) {
TODO("Not yet implemented")
}
override fun getItemCount(): Int {
TODO("Not yet implemented")
}
inner class ViewHolder(val binding: FragmentIdentityBinding) : RecyclerView.ViewHolder(binding.root)
}

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list"
android:name="dev.lowrespalmtree.comet.HistoryFragment"
@ -8,6 +7,5 @@
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context=".HistoryFragment"
tools:listitem="@layout/fragment_history_item" />

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:name="dev.lowrespalmtree.comet.IdentitiesFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:context=".IdentitiesFragment"
tools:listitem="@layout/fragment_identity">
</androidx.recyclerview.widget.RecyclerView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/list" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:layout_margin="4dp"
app:cardCornerRadius="4dp"
app:cardElevation="4dp"
android:foreground="?android:selectableItemBackground">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

View file

@ -9,6 +9,9 @@
android:id="@+id/historyFragment"
android:icon="@android:drawable/ic_menu_recent_history"
android:title="@string/history" />
<item
android:id="@+id/identitiesFragment"
android:title="@string/identities" />
<item
android:id="@+id/settingsFragment"
android:icon="@android:drawable/ic_menu_preferences"

View file

@ -15,6 +15,7 @@
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<fragment
android:id="@+id/historyFragment"
android:name="dev.lowrespalmtree.comet.HistoryFragment"
@ -26,6 +27,12 @@
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<fragment
android:id="@+id/identitiesFragment"
android:name="dev.lowrespalmtree.comet.IdentitiesFragment"
android:label="IdentitiesFragment" />
<fragment
android:id="@+id/settingsFragment"
android:name="dev.lowrespalmtree.comet.SettingsFragment"

View file

@ -28,6 +28,9 @@
</string>
<string name="attachment_summary_off">Only download attachments when manually requested</string>
<string name="home">Home</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="identities">Identities</string>
</resources>