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:
parent
020f48149b
commit
1f2be8cdee
|
@ -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')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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>>() }
|
||||||
|
|
||||||
|
|
38
app/src/main/java/dev/lowrespalmtree/comet/Identities.kt
Normal file
38
app/src/main/java/dev/lowrespalmtree/comet/Identities.kt
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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" />
|
32
app/src/main/res/layout/fragment_identities.xml
Normal file
32
app/src/main/res/layout/fragment_identities.xml
Normal 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>
|
21
app/src/main/res/layout/fragment_identity.xml
Normal file
21
app/src/main/res/layout/fragment_identity.xml
Normal 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>
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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>
|
Reference in a new issue