fix: smart playlist UX polish — layout, defaults, free-form input, case-insensitive matching
Details view: - Skip evaluation on new playlists (was returning all 25k tracks) - Go straight to editor on auto-edit instead of awaiting loadTracks Editor: - Default sort to Random instead of None, remove None option - Hide sort direction button when sort is Random - Fixed-width field (160px) and operator (140px) columns, value fills remaining space - Preview fills remaining vertical space (flex layout) instead of fixed 200px max-height - Preview scrolls independently while rules/options stay pinned Combobox: - Accept free-form text on blur and Enter — no longer requires selection from dropdown - Enables typing values like 'indie' that may not be exact DB entries Backend: - Case-insensitive text matching: COLLATE NOCASE on is/is_not/is_any_of operators - Applies to both regular fields and genre subqueries - LIKE operators were already case-insensitive (SQLite default)
This commit is contained in:
1 parent
477b7ff6a2
commit
6972953649
5 files changed
+69
-33
No files matched your search
@@ -194,13 +194,13 @@ func buildGenreSubquery(rule Rule) (string, []any, error) {
|
||||
|
||||
switch rule.Operator {
|
||||
case "is":
|
||||
return subquery + "g.name = ?)", []any{rule.Value}, nil
|
||||
return subquery + "g.name = ? COLLATE NOCASE)", []any{rule.Value}, nil
|
||||
|
||||
case "is_not":
|
||||
return `af.id NOT IN (
|
||||
SELECT rg_sub.recording_id FROM recording_genres rg_sub
|
||||
JOIN genres g ON rg_sub.genre_id = g.id
|
||||
WHERE g.name = ?)`, []any{rule.Value}, nil
|
||||
WHERE g.name = ? COLLATE NOCASE)`, []any{rule.Value}, nil
|
||||
|
||||
case "is_any_of":
|
||||
var values []string
|
||||
@@ -225,7 +225,7 @@ func buildGenreSubquery(rule Rule) (string, []any, error) {
|
||||
condArgs := make([]any, len(values))
|
||||
|
||||
for i, v := range values {
|
||||
placeholders[i] = "?"
|
||||
placeholders[i] = "? COLLATE NOCASE"
|
||||
condArgs[i] = v
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ func buildCondition(
|
||||
return col + " = ?", []any{v}, nil
|
||||
}
|
||||
|
||||
return col + " = ?", []any{rule.Value}, nil
|
||||
return col + " = ? COLLATE NOCASE", []any{rule.Value}, nil
|
||||
|
||||
case "is_not":
|
||||
if isNumeric {
|
||||
@@ -267,7 +267,7 @@ func buildCondition(
|
||||
return col + " != ?", []any{v}, nil
|
||||
}
|
||||
|
||||
return col + " != ?", []any{rule.Value}, nil
|
||||
return col + " != ? COLLATE NOCASE", []any{rule.Value}, nil
|
||||
|
||||
case "contains":
|
||||
return col + " LIKE ?",
|
||||
@@ -308,7 +308,7 @@ func buildCondition(
|
||||
condArgs := make([]any, len(values))
|
||||
|
||||
for i, v := range values {
|
||||
placeholders[i] = "?"
|
||||
placeholders[i] = "? COLLATE NOCASE"
|
||||
condArgs[i] = v
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user