reordering works better now with proper db update, but only one direction
parent
2d6bff5fc6
commit
5294ee7c4d
|
@ -50,7 +50,7 @@ struct RibbonRequest: Queryable {
|
||||||
// This method is not required by Queryable, but it makes it easier
|
// This method is not required by Queryable, but it makes it easier
|
||||||
func fetchValue(_ db: Database) throws -> [Ribbon] {
|
func fetchValue(_ db: Database) throws -> [Ribbon] {
|
||||||
if (id == nil) {
|
if (id == nil) {
|
||||||
return try Ribbon.fetchAll(db)
|
return try Ribbon.order(Column("pos")).fetchAll(db)
|
||||||
} else {
|
} else {
|
||||||
return try Ribbon.filter(idColumn == id).fetchAll(db)
|
return try Ribbon.filter(idColumn == id).fetchAll(db)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ struct AppDatabase {
|
||||||
|
|
||||||
try db.create(table: "Ribbon") { t in
|
try db.create(table: "Ribbon") { t in
|
||||||
t.autoIncrementedPrimaryKey("id")
|
t.autoIncrementedPrimaryKey("id")
|
||||||
|
t.column("pos", .integer).notNull()
|
||||||
t.column("title", .text).notNull()
|
t.column("title", .text).notNull()
|
||||||
t.column("book", .text).notNull()
|
t.column("book", .text).notNull()
|
||||||
t.column("scrollOffset", .integer).notNull()
|
t.column("scrollOffset", .integer).notNull()
|
||||||
|
@ -69,7 +70,7 @@ struct AppDatabase {
|
||||||
t.column("scrollOffset", .integer).notNull()
|
t.column("scrollOffset", .integer).notNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
try db.create(table: "foo4") { t in
|
try db.create(table: "foo2") { t in
|
||||||
t.autoIncrementedPrimaryKey("id")
|
t.autoIncrementedPrimaryKey("id")
|
||||||
t.column("ribbonId", .integer).notNull()
|
t.column("ribbonId", .integer).notNull()
|
||||||
}
|
}
|
||||||
|
@ -112,6 +113,58 @@ func load<T: Decodable>(_ filename: String) -> T {
|
||||||
|
|
||||||
extension AppDatabase {
|
extension AppDatabase {
|
||||||
|
|
||||||
|
func updateRibbonPosition(_ ribbon: inout Ribbon, _ oldPos: Int, _ newPos: Int) async throws {
|
||||||
|
try await dbWriter.write { [ribbon] db in
|
||||||
|
|
||||||
|
// This is only for moving back rn
|
||||||
|
|
||||||
|
print("MEOW HERE")
|
||||||
|
print(oldPos)
|
||||||
|
print(newPos)
|
||||||
|
print(ribbon)
|
||||||
|
print(ribbon.id!)
|
||||||
|
print("MEOW HERE 2")
|
||||||
|
|
||||||
|
|
||||||
|
// try db.execute(sql: """
|
||||||
|
// BEGIN TRANSACTION;
|
||||||
|
// """)
|
||||||
|
do {
|
||||||
|
try db.execute(sql: """
|
||||||
|
UPDATE Ribbon
|
||||||
|
SET pos =
|
||||||
|
CASE
|
||||||
|
WHEN pos = ? THEN ?
|
||||||
|
ELSE
|
||||||
|
pos + 1
|
||||||
|
END
|
||||||
|
WHERE (pos >= ? AND pos <= ?)
|
||||||
|
""", arguments: [oldPos, newPos, newPos, oldPos])
|
||||||
|
|
||||||
|
// try db.execute(sql: """
|
||||||
|
// UPDATE Ribbon
|
||||||
|
// SET pos = ?
|
||||||
|
// WHERE (id = ?)
|
||||||
|
// """, arguments: [newPos, ribbon.id!])
|
||||||
|
|
||||||
|
var ret = try Ribbon.fetchAll(db, sql: "SELECT * FROM Ribbon ORDER BY pos ASC") // [Player]
|
||||||
|
// print(ret)
|
||||||
|
print("all")
|
||||||
|
print(ret)
|
||||||
|
} catch {
|
||||||
|
print("Error info: \(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// try ribbon.saved(db)
|
||||||
|
|
||||||
|
// try db.execute(sql: """
|
||||||
|
// COMMIT;
|
||||||
|
// """)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func saveRibbon(_ ribbon: inout Ribbon) async throws {
|
func saveRibbon(_ ribbon: inout Ribbon) async throws {
|
||||||
// if ribbon.name.isEmpty {
|
// if ribbon.name.isEmpty {
|
||||||
// throw ValidationError.missingName
|
// throw ValidationError.missingName
|
||||||
|
@ -121,7 +174,6 @@ extension AppDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func saveSelectedRibbon(_ selectedRibbon: inout SelectedRibbon) async throws {
|
func saveSelectedRibbon(_ selectedRibbon: inout SelectedRibbon) async throws {
|
||||||
// if ribbon.name.isEmpty {
|
// if ribbon.name.isEmpty {
|
||||||
// throw ValidationError.missingName
|
// throw ValidationError.missingName
|
||||||
|
@ -140,7 +192,6 @@ extension AppDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func importJson(_ filename: String, _ db: Database) throws {
|
func importJson(_ filename: String, _ db: Database) throws {
|
||||||
let importJson : JsonImport = load(filename)
|
let importJson : JsonImport = load(filename)
|
||||||
|
|
||||||
|
@ -159,39 +210,20 @@ extension AppDatabase {
|
||||||
|
|
||||||
/// Create random Lines if the database is empty.
|
/// Create random Lines if the database is empty.
|
||||||
func initDatabase() throws {
|
func initDatabase() throws {
|
||||||
|
|
||||||
|
|
||||||
try dbWriter.write { db in
|
try dbWriter.write { db in
|
||||||
|
|
||||||
if try Line.all().isEmpty(db) {
|
if try Line.all().isEmpty(db) {
|
||||||
|
|
||||||
try importJson("john_export.json", db)
|
try importJson("john_export.json", db)
|
||||||
try importJson("mark_export.json", db)
|
try importJson("mark_export.json", db)
|
||||||
_ = try Ribbon(id: 1, title: "John", book: "bible.john", scrollId: "1", scrollOffset: 0).inserted(db)
|
_ = try Ribbon(id: 1, pos: 1, title: "John", book: "bible.john", scrollId: "1", scrollOffset: 0).inserted(db)
|
||||||
_ = try Ribbon(id: 2, title: "Gospel of Mark", book: "bible.mark", scrollId: "1", scrollOffset: 300).inserted(db)
|
_ = try Ribbon(id: 2, pos: 2, title: "Gospel of Mark", book: "bible.mark", scrollId: "1", scrollOffset: 300).inserted(db)
|
||||||
|
_ = try Ribbon(id: 3, pos: 3, title: "John 2", book: "bible.john", scrollId: "1", scrollOffset: 0).inserted(db)
|
||||||
_ = try SelectedRibbon(id: 1, ribbonId: 1).inserted(db)
|
_ = try SelectedRibbon(id: 1, ribbonId: 1).inserted(db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// static let uiTestLines = [
|
|
||||||
// Line(id: nil, name: "Arthur", score: 5),
|
|
||||||
// Line(id: nil, name: "Barbara", score: 6),
|
|
||||||
// Line(id: nil, name: "Craig", score: 8),
|
|
||||||
// Line(id: nil, name: "David", score: 4),
|
|
||||||
// Line(id: nil, name: "Elena", score: 1),
|
|
||||||
// Line(id: nil, name: "Frederik", score: 2),
|
|
||||||
// Line(id: nil, name: "Gilbert", score: 7),
|
|
||||||
// Line(id: nil, name: "Henriette", score: 3)]
|
|
||||||
|
|
||||||
// func createLinesForUITests() throws {
|
|
||||||
// try dbWriter.write { db in
|
|
||||||
// try AppDatabase.uiTestLines.forEach { Line in
|
|
||||||
// _ = try Line.inserted(db) // insert but ignore inserted id
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Database Access: Reads
|
// MARK: - Database Access: Reads
|
||||||
|
|
|
@ -127,7 +127,7 @@ struct RibbonCrown : View {
|
||||||
@Binding var showOverlay : Bool
|
@Binding var showOverlay : Bool
|
||||||
@Binding var refresh : Bool
|
@Binding var refresh : Bool
|
||||||
|
|
||||||
var height = CGFloat(50)
|
var height = CGFloat(45)
|
||||||
var xOffset = CGFloat(25)
|
var xOffset = CGFloat(25)
|
||||||
var scale = 0.65
|
var scale = 0.65
|
||||||
|
|
||||||
|
@ -138,12 +138,16 @@ struct RibbonCrown : View {
|
||||||
|
|
||||||
@State var saveOffset = CGFloat()
|
@State var saveOffset = CGFloat()
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|
||||||
|
ZStack {
|
||||||
|
MyIcon().frame(width: CGFloat(100 * 1.66 * scale), height: CGFloat(100 * scale), alignment: .center) .foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
|
||||||
|
|
||||||
Text(ribbon.title)
|
Text(ribbon.title)
|
||||||
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
||||||
// // .background(Color(red: 0.3, green: 0.3, blue: 0.3))
|
|
||||||
// .foregroundColor(.white))
|
// .foregroundColor(.white))
|
||||||
// .foregroundColor(.black)
|
// .foregroundColor(.black)
|
||||||
.frame(minWidth: CGFloat(75), maxWidth: CGFloat(75), minHeight: height, maxHeight: height, alignment: .center)
|
.frame(minWidth: CGFloat(70), maxWidth: CGFloat(70), minHeight: height, maxHeight: height, alignment: .center)
|
||||||
|
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
||||||
// .background(.red)
|
// .background(.red)
|
||||||
// .background(.yellow)
|
// .background(.yellow)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
|
@ -151,14 +155,29 @@ struct RibbonCrown : View {
|
||||||
.padding([.top, .bottom], 10)
|
.padding([.top, .bottom], 10)
|
||||||
.font(Font.custom("AveriaSerifLibre-Regular", size: CGFloat(10)))
|
.font(Font.custom("AveriaSerifLibre-Regular", size: CGFloat(10)))
|
||||||
|
|
||||||
.overlay( MyIcon().frame(width: CGFloat(100 * 1.66 * scale), height: CGFloat(100 * scale), alignment: .center) .foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4))))
|
}
|
||||||
|
|
||||||
.offset(x: xOffset)
|
// Text(ribbon.title)
|
||||||
.onTapGesture {
|
// .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
||||||
Print("TAP")
|
// // // .background(Color(red: 0.3, green: 0.3, blue: 0.3))
|
||||||
// selectedLine = seg.id
|
// // .foregroundColor(.white))
|
||||||
// Print(selectedLine)
|
// // .foregroundColor(.black)
|
||||||
}
|
// .frame(minWidth: CGFloat(75), maxWidth: CGFloat(75), minHeight: height, maxHeight: height, alignment: .center)
|
||||||
|
// // .background(.red)
|
||||||
|
// // .background(.yellow)
|
||||||
|
// .multilineTextAlignment(.center)
|
||||||
|
// // .minimumScaleFactor(0.5)
|
||||||
|
// .padding([.top, .bottom], 10)
|
||||||
|
// .font(Font.custom("AveriaSerifLibre-Regular", size: CGFloat(10)))
|
||||||
|
|
||||||
|
// .overlay( MyIcon().frame(width: CGFloat(100 * 1.66 * scale), height: CGFloat(100 * scale), alignment: .center) .foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4))))
|
||||||
|
|
||||||
|
// .offset(x: xOffset)
|
||||||
|
// .onTapGesture {
|
||||||
|
// Print("TAP")
|
||||||
|
// // selectedLine = seg.id
|
||||||
|
// // Print(selectedLine)
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
// ForEach(sr) { selectedRibbon in
|
// ForEach(sr) { selectedRibbon in
|
||||||
|
@ -312,8 +331,9 @@ struct ContentView: View {
|
||||||
|
|
||||||
@State var refresh2: Bool = false
|
@State var refresh2: Bool = false
|
||||||
|
|
||||||
@State var data = ["Imitation of Christ", "Psalms", "Fundamentals of Dogmatic Theology"]
|
@State var draggedRibbon: Ribbon?
|
||||||
@State var reorder = true
|
|
||||||
|
@State var reorder = true
|
||||||
|
|
||||||
|
|
||||||
@Query(RibbonRequest()) private var ribbons: [Ribbon]
|
@Query(RibbonRequest()) private var ribbons: [Ribbon]
|
||||||
|
@ -341,104 +361,54 @@ struct ContentView: View {
|
||||||
|
|
||||||
var width = CGFloat(100 * 1.66 * scale)
|
var width = CGFloat(100 * 1.66 * scale)
|
||||||
|
|
||||||
|
// ForEach(ribbons) { ribbon in
|
||||||
|
// data.append(ribbon)
|
||||||
|
// }
|
||||||
|
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
ZStack (alignment: .top) {
|
ZStack (alignment: .top) {
|
||||||
VStack (alignment: .leading) {
|
VStack (alignment: .leading) {
|
||||||
VStack {
|
VStack {
|
||||||
|
// ReorderableForEach($data, allowReordering: $reorder) { item, isDragged in
|
||||||
ReorderableForEach($data, allowReordering: $reorder) { item, isDragged in
|
ForEach(ribbons) { ribbon in
|
||||||
Text(item)
|
RibbonCrown(ribbon: ribbon,
|
||||||
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
scrollId:$scrollId,
|
||||||
// // .background(Color(red: 0.3, green: 0.3, blue: 0.3))
|
scrollOffset:$scrollOffset,
|
||||||
// .foregroundColor(.white))
|
showOverlay: $showOverlay,
|
||||||
// .foregroundColor(.black)
|
refresh:$refresh
|
||||||
.frame(minWidth: CGFloat(75), maxWidth: width + 30, minHeight: height, maxHeight: height, alignment: .center)
|
)
|
||||||
// .background(.red)
|
.onDrag {
|
||||||
// .background(.yellow)
|
self.draggedRibbon = ribbon
|
||||||
.multilineTextAlignment(.center)
|
return NSItemProvider()
|
||||||
// .minimumScaleFactor(0.5)
|
}
|
||||||
.padding([.top, .bottom], 10)
|
.onDrop(of: [.text],
|
||||||
.font(Font.custom("AveriaSerifLibre-Regular", size: CGFloat(10)))
|
delegate: DropViewDelegate(destinationItem: ribbon, draggedItem: $draggedRibbon, appDatabase: appDatabase)
|
||||||
|
)
|
||||||
.overlay( MyIcon().frame(width: width, height: CGFloat(100 * scale), alignment: .center) .foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4))))
|
|
||||||
|
|
||||||
.offset(x: xOffset)
|
|
||||||
.onTapGesture {
|
|
||||||
Print("TAP")
|
|
||||||
// selectedLine = seg.id
|
|
||||||
// Print(selectedLine)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// .overlay(isDragged ? Color.white.opacity(0.6) : Color.clear)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Text("Imitation of Christ")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Text("Imitation of Christ")
|
|
||||||
// .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
// .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
||||||
// // // .background(Color(red: 0.3, green: 0.3, blue: 0.3))
|
|
||||||
// // .foregroundColor(.white))
|
|
||||||
// // .foregroundColor(.black)
|
|
||||||
// .frame(minWidth: CGFloat(75), maxWidth: CGFloat(150), minHeight: height, maxHeight: height, alignment: .center)
|
|
||||||
// // .background(.red)
|
|
||||||
// // .background(.yellow)
|
|
||||||
// .multilineTextAlignment(.center)
|
|
||||||
// // .minimumScaleFactor(0.5)
|
|
||||||
// .padding([.top, .bottom], 10)
|
|
||||||
// .font(Font.custom("AveriaSerifLibre-Regular", size: CGFloat(10)))
|
|
||||||
|
|
||||||
// .overlay( MyIcon().frame(width: CGFloat(100 * 1.66 * scale), height: CGFloat(100 * scale), alignment: .center) .foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4))))
|
|
||||||
|
|
||||||
// .offset(x: xOffset)
|
|
||||||
// .onTapGesture {
|
|
||||||
// Print("TAP")
|
|
||||||
// // selectedLine = seg.id
|
|
||||||
// // Print(selectedLine)
|
|
||||||
// }
|
|
||||||
// .onDrag {
|
|
||||||
// // self.draggedColor = color
|
|
||||||
// return NSItemProvider()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Text("Psalms")
|
|
||||||
// .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
|
|
||||||
// // .background(Color(red: 0.3, green: 0.3, blue: 0.3))
|
|
||||||
// // .foregroundColor(.white))
|
|
||||||
// // .foregroundColor(.black)
|
|
||||||
// .overlay( MyIcon().frame(width: CGFloat(100 * 1.66 * scale), height: CGFloat(100 * scale)) .foregroundColor(Color(UIColor(red: 0.56, green: 0.30, blue: 0.30, alpha: 0.4))))
|
|
||||||
// .frame(minWidth: CGFloat(75), maxWidth: CGFloat(75), minHeight: height, maxHeight: height, alignment: .center)
|
|
||||||
// // .background(.red)
|
|
||||||
// .multilineTextAlignment(.center)
|
|
||||||
|
|
||||||
// .offset(x: xOffset)
|
|
||||||
// .padding([.top, .bottom], 10)
|
|
||||||
// // .minimumScaleFactor(0.5)
|
|
||||||
// .font(Font.custom("AveriaSerifLibre-Regular", size: CGFloat(14)))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.frame(width: geometry.size.width, height: geometry.size.height - 100, alignment: .topLeading)
|
.frame(width: geometry.size.width, height: geometry.size.height - 100, alignment: .topLeading)
|
||||||
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
||||||
.zIndex(0)
|
.zIndex(0)
|
||||||
|
.animation(.default, value: ribbons)
|
||||||
|
|
||||||
// Spacer()
|
// Spacer()
|
||||||
|
|
||||||
ForEach(ribbons) { ribbon in
|
// ForEach(ribbons) { ribbon in
|
||||||
RibbonCrown(ribbon: ribbon,
|
// RibbonCrown(ribbon: ribbon,
|
||||||
scrollId:$scrollId,
|
// scrollId:$scrollId,
|
||||||
scrollOffset:$scrollOffset,
|
// scrollOffset:$scrollOffset,
|
||||||
showOverlay: $showOverlay,
|
// showOverlay: $showOverlay,
|
||||||
refresh:$refresh
|
// refresh:$refresh
|
||||||
)
|
// )
|
||||||
// .buttonStyle(BlueButtonStyle())
|
// // .buttonStyle(BlueButtonStyle())
|
||||||
// .frame(alignment: .topLeading)
|
// // .frame(alignment: .topLeading)
|
||||||
|
|
||||||
// .background(Color(red: 0.4, green: 0.4, blue: 0.1))
|
// // .background(Color(red: 0.4, green: 0.4, blue: 0.1))
|
||||||
.animation(nil)
|
// .animation(nil)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
|
||||||
.frame(alignment: .topLeading)
|
.frame(alignment: .topLeading)
|
||||||
|
@ -861,6 +831,7 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func handleVisibilityChanged2(_ id: String, change: VisibilityChange, tracker: VisibilityTracker<String>) {
|
func handleVisibilityChanged2(_ id: String, change: VisibilityChange, tracker: VisibilityTracker<String>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,6 +891,50 @@ private let itemFormatter: DateFormatter = {
|
||||||
return formatter
|
return formatter
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
struct DropViewDelegate: DropDelegate {
|
||||||
|
|
||||||
|
let destinationItem: Ribbon
|
||||||
|
// @Binding var colors: [Color]
|
||||||
|
@Binding var draggedItem: Ribbon?
|
||||||
|
let appDatabase: AppDatabase
|
||||||
|
|
||||||
|
func dropUpdated(info: DropInfo) -> DropProposal? {
|
||||||
|
return DropProposal(operation: .move)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dropEntered(info: DropInfo) {
|
||||||
|
|
||||||
|
Task {
|
||||||
|
|
||||||
|
var newRibbon = draggedItem!
|
||||||
|
var newDest = destinationItem
|
||||||
|
|
||||||
|
var oldPos = draggedItem!.pos
|
||||||
|
var newPos = destinationItem.pos
|
||||||
|
|
||||||
|
print("dragged item")
|
||||||
|
print(draggedItem)
|
||||||
|
print("dest item")
|
||||||
|
print(destinationItem)
|
||||||
|
|
||||||
|
|
||||||
|
if (draggedItem!.id! == destinationItem.id!) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newRibbon.pos = destinationItem.pos
|
||||||
|
|
||||||
|
_ = try await appDatabase.updateRibbonPosition(&newRibbon, oldPos, newPos )
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func performDrop(info: DropInfo) -> Bool {
|
||||||
|
draggedItem = nil
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ContentView_Previews: PreviewProvider {
|
struct ContentView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ContentView()
|
ContentView()
|
||||||
|
|
|
@ -17,6 +17,7 @@ struct Ribbon: Identifiable, Equatable {
|
||||||
/// Int64 is the recommended type for auto-incremented database ids.
|
/// Int64 is the recommended type for auto-incremented database ids.
|
||||||
/// Use nil for players that are not inserted yet in the database.
|
/// Use nil for players that are not inserted yet in the database.
|
||||||
var id: Int64?
|
var id: Int64?
|
||||||
|
var pos: Int
|
||||||
var title: String
|
var title: String
|
||||||
var book: String
|
var book: String
|
||||||
var scrollId: String
|
var scrollId: String
|
||||||
|
@ -35,6 +36,7 @@ extension Ribbon: Codable, FetchableRecord, MutablePersistableRecord {
|
||||||
// Define database columns from CodingKeys
|
// Define database columns from CodingKeys
|
||||||
fileprivate enum Columns {
|
fileprivate enum Columns {
|
||||||
static let id = Column(CodingKeys.id)
|
static let id = Column(CodingKeys.id)
|
||||||
|
static let pos = Column(CodingKeys.pos)
|
||||||
static let book = Column(CodingKeys.book)
|
static let book = Column(CodingKeys.book)
|
||||||
static let title = Column(CodingKeys.title)
|
static let title = Column(CodingKeys.title)
|
||||||
static let scrollOffset = Column(CodingKeys.scrollOffset)
|
static let scrollOffset = Column(CodingKeys.scrollOffset)
|
||||||
|
|
Loading…
Reference in New Issue