Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 35 additions & 14 deletions src/database/identities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,8 @@ impl Database {
"CREATE TABLE IF NOT EXISTS identity_order (
pos INTEGER NOT NULL,
identity_id BLOB NOT NULL,
PRIMARY KEY(pos)
)",
PRIMARY KEY(pos),
FOREIGN KEY (identity_id) REFERENCES identity(id) ON DELETE CASCADE)",
)?;
Ok(())
}
Expand Down Expand Up @@ -317,33 +317,54 @@ impl Database {
Ok(())
}

/// Loads the custom identity order from the DB, returning a list of Identifiers in the stored order.
/// If there's no data, returns an empty Vec.
/// Loads the user’s custom identity order (the entire list).
/// If an identity in the order doesn't exist in the identity table, it is removed.
pub fn load_identity_order(&self) -> rusqlite::Result<Vec<Identifier>> {
// Make sure table exists (in case it doesn't)
// Make sure table exists
self.ensure_identity_order_table_exists()?;

let conn = self.conn.lock().unwrap();

// Read all rows sorted by pos
let mut stmt = conn.prepare(
"SELECT identity_id FROM identity_order
ORDER BY pos ASC",
)?;
let mut stmt = conn.prepare("SELECT identity_id FROM identity_order ORDER BY pos ASC")?;

let mut rows = stmt.query([])?;
let mut result = Vec::new();
let mut final_list = Vec::new();
let mut to_remove = Vec::new();

while let Some(row) = rows.next()? {
let id_bytes: Vec<u8> = row.get(0)?;
// Convert from raw bytes to an Identifier
if let Ok(identifier) = Identifier::from_vec(id_bytes) {
result.push(identifier);
let identifier = match Identifier::from_vec(id_bytes.clone()) {
Ok(id) => id,
Err(_) => {
// If parsing as an Identifier fails, queue for removal
to_remove.push(id_bytes);
continue;
}
};

// Check if the identity is still in 'identity' table
let mut check_stmt =
conn.prepare("SELECT EXISTS(SELECT 1 FROM identity WHERE id = ?)")?;
let exists: i64 = check_stmt.query_row(params![identifier.to_vec()], |r| r.get(0))?;
if exists == 1 {
// Keep it
final_list.push(identifier);
} else {
// If for some reason it fails to parse, skip it or handle error
// Queue for removal because it doesn't exist in the identity table
to_remove.push(identifier.to_vec());
}
}

Ok(result)
// Remove any “dangling” references
for id in to_remove {
conn.execute(
"DELETE FROM identity_order WHERE identity_id = ?",
params![id],
)?;
}

Ok(final_list)
}
}
32 changes: 27 additions & 5 deletions src/ui/identities/identities_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use eframe::egui::{self, Context};
use eframe::emath::Align;
use egui::{Color32, Frame, Margin, RichText, Ui};
use egui_extras::{Column, TableBuilder};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex};

Expand Down Expand Up @@ -101,12 +101,34 @@ impl IdentitiesScreen {
screen
}

/// Reorder the underlying IndexMap to match a list of IDs
/// Reorders `self.identities` to match the order of the provided list of IDs.
/// Any IDs not present in the provided list are left in their current position.
fn reorder_map_to(&self, new_order: Vec<Identifier>) {
let mut lock = self.identities.lock().unwrap();
for (desired_idx, id) in new_order.iter().enumerate() {
if let Some(current_idx) = lock.get_index_of(id) {
if current_idx != desired_idx && current_idx < lock.len() {
if lock.is_empty() || new_order.is_empty() {
return;
}

// 1) Collect the set of IDs currently in `self.identities`
let existing_ids: HashSet<Identifier> = lock.keys().cloned().collect();

// 2) Build a filtered list that only includes IDs which exist in the map
// (and also limit the length so we don’t swap out of range)
let valid_ids: Vec<Identifier> = new_order
.into_iter()
.filter(|id| existing_ids.contains(id))
.take(lock.len()) // never try to reorder more items than we actually have
.collect();

// 3) Do the swaps only for items still present in our map,
// skipping any that no longer exist or where desired_idx is out of range
for (desired_idx, id) in valid_ids.into_iter().enumerate() {
// Double‐check the desired index is in range
if desired_idx >= lock.len() {
break;
}
if let Some(current_idx) = lock.get_index_of(&id) {
if current_idx != desired_idx {
lock.swap_indices(current_idx, desired_idx);
}
}
Expand Down