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, "formatVersion": 1,
"database": { "database": {
"version": 1, "version": 1,
"identityHash": "44cb07b76e6b8abfaa988e1d3696a347", "identityHash": "70da3095877de4a82021855471523b90",
"entities": [ "entities": [
{ {
"tableName": "HistoryEntry", "tableName": "HistoryEntry",
@ -35,12 +35,76 @@
}, },
"indices": [], "indices": [],
"foreignKeys": [] "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": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "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 package dev.lowrespalmtree.comet
import android.content.Context import android.content.Context
import androidx.room.AutoMigration
import androidx.room.Database import androidx.room.Database
import androidx.room.Room import androidx.room.Room
import androidx.room.RoomDatabase 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 class AppDatabase : RoomDatabase() {
abstract fun historyEntryDao(): History.HistoryEntryDao abstract fun historyEntryDao(): History.HistoryEntryDao
abstract fun identityDao(): Identities.IdentityDao
} }
object Database { object Database {
@ -16,6 +25,6 @@ object Database {
fun init(context: Context) { fun init(context: Context) {
if (::INSTANCE.isInitialized) if (::INSTANCE.isInitialized)
return 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 { object History {
@Entity @Entity
data class HistoryEntry( data class HistoryEntry(
@PrimaryKey @ColumnInfo(name = "uri") val uri: String, @PrimaryKey val uri: String,
@ColumnInfo(name = "title") var title: String?, var title: String?,
@ColumnInfo(name = "lastVisit") var lastVisit: Long, var lastVisit: Long,
) )
@Dao @Dao

View file

@ -6,9 +6,10 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -21,8 +22,8 @@ import kotlinx.coroutines.launch
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
class HistoryFragment : Fragment(), HistoryItemAdapterListener { class HistoryFragment : Fragment(), HistoryItemAdapterListener {
private val vm: HistoryViewModel by viewModels()
private lateinit var binding: FragmentHistoryListBinding private lateinit var binding: FragmentHistoryListBinding
private lateinit var historyViewModel: HistoryViewModel
private lateinit var adapter: HistoryItemAdapter private lateinit var adapter: HistoryItemAdapter
override fun onCreateView( override fun onCreateView(
@ -35,14 +36,13 @@ class HistoryFragment : Fragment(), HistoryItemAdapterListener {
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
historyViewModel = ViewModelProvider(this)[HistoryViewModel::class.java]
adapter = HistoryItemAdapter(this) adapter = HistoryItemAdapter(this)
binding.list.layoutManager = LinearLayoutManager(requireContext()) binding.list.layoutManager = LinearLayoutManager(requireContext())
binding.list.adapter = adapter 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) { override fun onItemClick(url: String) {
@ -51,7 +51,9 @@ class HistoryFragment : Fragment(), HistoryItemAdapterListener {
} }
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
class HistoryViewModel : ViewModel() { class HistoryViewModel(
@Suppress("unused") private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val items: MutableLiveData<List<HistoryEntry>> val items: MutableLiveData<List<HistoryEntry>>
by lazy { 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"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" <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" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list" android:id="@+id/list"
android:name="dev.lowrespalmtree.comet.HistoryFragment" android:name="dev.lowrespalmtree.comet.HistoryFragment"
@ -8,6 +7,5 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context=".HistoryFragment" tools:context=".HistoryFragment"
tools:listitem="@layout/fragment_history_item" /> 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:id="@+id/historyFragment"
android:icon="@android:drawable/ic_menu_recent_history" android:icon="@android:drawable/ic_menu_recent_history"
android:title="@string/history" /> android:title="@string/history" />
<item
android:id="@+id/identitiesFragment"
android:title="@string/identities" />
<item <item
android:id="@+id/settingsFragment" android:id="@+id/settingsFragment"
android:icon="@android:drawable/ic_menu_preferences" android:icon="@android:drawable/ic_menu_preferences"

View file

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

View file

@ -28,6 +28,9 @@
</string> </string>
<string name="attachment_summary_off">Only download attachments when manually requested</string> <string name="attachment_summary_off">Only download attachments when manually requested</string>
<string name="home">Home</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> </resources>