Compare commits

...

10 Commits

Author SHA1 Message Date
saint bd1923cfb4 stats sorta working
builds
2024-05-31 13:04:43 -04:00
saint 19ca7be678 builds, still working on undo 2024-05-29 16:02:08 -04:00
saint 168a057a2a okay so working when you manually save ribbon
need to make it save position when you switch ribbon instead of manual save
but good progress
2024-05-28 16:15:07 -04:00
saint 14e1bec9e5 builds and is working, need to fix selected ribbon 2024-05-28 16:04:21 -04:00
saint 08b6116a28 okay this is better
builds and has the foundation for better undo stuff
2024-05-28 00:13:54 -04:00
saint efd05ce33b working on undo - does not build rn 2024-05-27 22:28:13 -04:00
saint 4dfc93ea90 added some back arrows and start of custom picker 2024-05-27 17:24:56 -04:00
saint 32696d7b58 can request separate books 2024-05-26 10:45:30 -04:00
saint 9eb488a87a okay works and the resize works for the overlay too yay 2024-05-24 10:36:58 -04:00
saint c069860c43 builds but idk 2024-05-24 10:19:37 -04:00
20 changed files with 907 additions and 195 deletions

2
.ignore Normal file
View File

@ -0,0 +1,2 @@
*.json
*.xcodeproj/*

55
BackButton.swift Normal file
View File

@ -0,0 +1,55 @@
//
// BackButton.swift
// gloss
//
// Created by Saint on 5/27/24.
//
import Foundation
import SwiftUI
struct BackArrow: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let width = rect.size.width
let height = rect.size.height
path.move(to: CGPoint(x: 0.83333*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.83333*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.25*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.25*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.16667*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.16667*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.25*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.25*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.83333*width, y: 0.45833*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.41667*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.29167*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.41667*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.20833*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.20833*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.29167*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.41667*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.33333*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.70833*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.41667*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.79167*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.79167*height))
path.addLine(to: CGPoint(x: 0.41667*width, y: 0.70833*height))
path.closeSubpath()
return path
}
}

View File

@ -5,6 +5,8 @@
// Created by Saint on 5/20/24. // Created by Saint on 5/20/24.
// //
import GRDB
import GRDBQuery
import Foundation import Foundation
import SwiftUI import SwiftUI
import WrappingHStack import WrappingHStack
@ -14,6 +16,7 @@ struct SegRow: View {
var ribbonId: Int64 var ribbonId: Int64
@State var highlights = Set<Int>() @State var highlights = Set<Int>()
let intraWordSpacing = CGFloat(1.6)
var body: some View { var body: some View {
var segSplit = seg.body.components(separatedBy: ";;") var segSplit = seg.body.components(separatedBy: ";;")
let decoder = JSONDecoder() let decoder = JSONDecoder()
@ -53,7 +56,8 @@ struct SegRow: View {
Text(arrayOfText[index]) Text(arrayOfText[index])
.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)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize)) .font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
.padding(.horizontal, 1.5) // intra word spacing
.padding(.horizontal, intraWordSpacing) // intra word spacing
.if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) } .if(self.highlights.contains(verse.verse)) { $0.background(Color(hex: highlightColor)) }
.foregroundColor(Color.white) .foregroundColor(Color.white)
.onTapGesture { .onTapGesture {
@ -79,7 +83,6 @@ struct SegRow: View {
struct Pane: View { struct Pane: View {
@ObservedObject var paneConnector: PaneConnector @ObservedObject var paneConnector: PaneConnector
@State var segs: [SegDenorm]
@State var selectedRibbon: [Ribbon] @State var selectedRibbon: [Ribbon]
@State var width: CGFloat @State var width: CGFloat
@ -89,13 +92,15 @@ struct Pane: View {
@State var refresh: Bool = false @State var refresh: Bool = false
@State var vertSep = CGFloat(20) @Query(SegDenormRequest(book: "bible.mark")) private var segs: [SegDenorm]
@Environment(\.appDatabase) private var appDatabase @Environment(\.appDatabase) private var appDatabase
// var handleVisibilityChanged: (String, VisibilityChange, VisibilityTracker<String>) -> Void // var handleVisibilityChanged: (String, VisibilityChange, VisibilityTracker<String>) -> Void
var body: some View { var body: some View {
var adjustedHeight = height - paneConnector.vertSep
ZStack {
ScrollViewReader { proxy in ScrollViewReader { proxy in
VisibilityTrackingScrollView(action: handleVisibilityChanged) { VisibilityTrackingScrollView(action: handleVisibilityChanged) {
LazyVStack { LazyVStack {
@ -116,8 +121,8 @@ struct Pane: View {
destRibbon: selectedRibbon[0], destRibbon: selectedRibbon[0],
appDatabase: appDatabase, appDatabase: appDatabase,
paneConnector: paneConnector, paneConnector: paneConnector,
refresh: $refresh, loading: true,
loading: true) bump: false)
} }
.onChange(of: paneConnector.refresh) { _ in .onChange(of: paneConnector.refresh) { _ in
print("inside change") print("inside change")
@ -125,6 +130,9 @@ struct Pane: View {
Task { Task {
DispatchQueue.main.async { DispatchQueue.main.async {
if paneConnector.visibilityTracker == nil {
return
}
let gTracker = paneConnector.visibilityTracker! let gTracker = paneConnector.visibilityTracker!
Print("scroll Id target: \(paneConnector.scrollId)") Print("scroll Id target: \(paneConnector.scrollId)")
@ -190,7 +198,27 @@ struct Pane: View {
} }
.zIndex(1) .zIndex(1)
.background(Color(red: 0.2, green: 0.2, blue: 0.2)) .background(Color(red: 0.2, green: 0.2, blue: 0.2))
.frame(width: width, height: height) .frame(width: width, height: adjustedHeight)
if self.paneConnector.showOverlay {
Rectangle()
// .frame(width: width, height: height + 200)
.background(.ultraThinMaterial)
.opacity(0.98)
.offset(y: -50)
.frame(width: width, height: adjustedHeight + 100)
// .blur(radius: 0.8)
// .opacity(1)
.transition(.opacity)
// .frame(width: geometry.size.width - 50)
// .offset(x: pulledOut.width)
// .offset(x: viewState.width, y: viewState.height)
.zIndex(2)
}
}
.frame(width: width, height: adjustedHeight)
} }
func handleVisibilityChanged(_: String, change _: VisibilityChange, tracker: VisibilityTracker<String>) { func handleVisibilityChanged(_: String, change _: VisibilityChange, tracker: VisibilityTracker<String>) {

56
ForwardArrow.swift Normal file
View File

@ -0,0 +1,56 @@
//
// ForwardArrow.swift
// gloss
//
// Created by Saint on 5/27/24.
//
import Foundation
import SwiftUI
struct ForwardArrow: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let width = rect.size.width
let height = rect.size.height
path.move(to: CGPoint(x: 0.16667*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.16667*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.83333*width, y: 0.54167*height))
path.addLine(to: CGPoint(x: 0.83333*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.45833*height))
path.addLine(to: CGPoint(x: 0.16667*width, y: 0.45833*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.58333*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.375*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.29167*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.58333*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.29167*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.20833*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.20833*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.29167*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.58333*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.66667*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.625*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.70833*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.58333*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.70833*height))
path.addLine(to: CGPoint(x: 0.5*width, y: 0.79167*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.79167*height))
path.addLine(to: CGPoint(x: 0.58333*width, y: 0.70833*height))
path.closeSubpath()
return path
}
}

74
NaviBar.swift Normal file
View File

@ -0,0 +1,74 @@
import GRDB
import GRDBQuery
import Foundation
import SwiftUI
struct NaviBar: View {
@ObservedObject var paneConnector: PaneConnector
@Query(RibbonRequest(dir: .prev, groupId: 1)) private var backRibbon: [Ribbon]
@Query(RibbonRequest(dir: .next, groupId: 1)) private var nextRibbon: [Ribbon]
@Query(SelectedRibbonRequest()) private var selectedRibbon: [Ribbon]
@Environment(\.appDatabase) private var appDatabase
var body: some View {
VStack {
HStack {
Print("meow navi reloaded back ribbon: \(backRibbon[0])")
BackArrow()
.frame(width: CGFloat(30), height: CGFloat(30))
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
.foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
.onTapGesture {
print("back backRibbon: \(backRibbon)")
Task {
print("back backRibbon: \(backRibbon)")
if backRibbon.count == 0 {
return
}
var br = backRibbon[0]
//var sr = selectedRibbon[0]
do {
var sr = try await appDatabase.getSelectedRibbon()
print("meow first sr:\(sr)")
print("meow first selectedRibbon:\(selectedRibbon[0])")
try await updateRibbon(selectedRibbon: selectedRibbon[0],
appDatabase: appDatabase,
paneConnector: paneConnector)
print("meow back from update in main")
sr = try await appDatabase.getSelectedRibbon()
print("meow second sr:\(sr)")
print("meow backribbon br:\(br)")
_ = try await appDatabase.undoRibbon(&sr[0])
goToRibbon(selectedRibbon: sr[0],
destRibbon: br,
appDatabase: appDatabase,
paneConnector: paneConnector,
loading: false,
bump:false)
} catch {
print("back 2 error")
print("Error info: \(error)")
}
}
}
ForwardArrow()
.frame(width: CGFloat(30), height: CGFloat(30))
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
.foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
}
.cornerRadius(5)
}
}
}

View File

@ -2,30 +2,18 @@ import Combine
import GRDB import GRDB
import GRDBQuery import GRDBQuery
/// A player request can be used with the `@Query` property wrapper in order to
/// feed a view with a list of players.
///
/// For example:
///
/// struct MyView: View {
/// @Query(RibbonRequest(ordering: .byName)) private var players: [Ribbon]
///
/// var body: some View {
/// List(players) { player in ... )
/// }
/// }
var idColumn = Column("id") var idColumn = Column("id")
struct RibbonRequest: Queryable { struct RibbonRequest: Queryable {
// enum Ordering { enum UndoDir {
// case byScore case prev
// case byName case next
// } }
/// The ordering used by the player request. /// The ordering used by the player request.
// var ordering: Ordering // var ordering: Ordering
var id: Int64! var id: Int64!
var dir: UndoDir?
var groupId: Int?
// MARK: - Queryable Implementation // MARK: - Queryable Implementation
@ -49,12 +37,103 @@ 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) {
return try Ribbon.order(Column("pos")).fetchAll(db) var ret: [Ribbon]
} else { var sql: String
return try Ribbon.filter(idColumn == id).fetchAll(db)
// this has to be a global variable
let totalLevels = 3
do {
print("back reload")
if dir != nil && groupId != nil {
sql = """
SELECT * FROM Ribbon \
WHERE groupId = ?
"""
ret = try Ribbon.fetchAll(db, sql: sql, arguments: [groupId])
if ret.count == 0 {
print("error no ribbons found")
return []
} }
print("back all ribbon all: \(ret)")
let currentLevel = ret[0].currentLevel
let minLevel = ret[0].minLevel
let maxLevel = ret[0].maxLevel
var newCurrentLevel = (currentLevel - 1) %% totalLevels
// probably need more error checking to check
// if current level gets into an error state
// between minLevel and maxLevel somehow but there
// are probably a bunch of edge cases casue of the
// mod stuff
if dir == .prev {
// no back undo steps left
if currentLevel == minLevel {
newCurrentLevel = currentLevel
}
} else if dir == .prev {
// no forward redo steps left
if currentLevel == maxLevel {
newCurrentLevel = maxLevel
} else {
newCurrentLevel = (currentLevel + 1) %% totalLevels
}
}
print("back newcurrentlevel \(newCurrentLevel)")
sql = """
SELECT * FROM Ribbon \
WHERE groupId = ? AND
undoLevel = ?
LIMIT 1
"""
ret = try Ribbon.fetchAll(db, sql: sql, arguments: [groupId, newCurrentLevel])
print("back ribbon return: \(ret)")
return ret
} else {
if groupId != nil {
let sql = """
SELECT * from Ribbon r1 \
WHERE r1.groupId = ?
ORDER BY undoLevel ASC
"""
var ret = try Ribbon.fetchAll(db, sql: sql, arguments: [groupId])
print("xxxxx fetching ribbons")
print(ret)
return ret
} else {
let sql = """
select distinct r1.* from Ribbon r1 join Ribbon r2 ON \
r1.undoLevel = r2.currentLevel AND r1.id = r2.id ORDER BY pos ASC
"""
var ret = try Ribbon.fetchAll(db, sql: sql)
print("xxxxx fetching ribbons")
print(ret)
return ret
}
}
} catch {
print(error.localizedDescription)
print(error)
print("Error")
return []
}
// if id == nil {
// return try Ribbon.order(Column("pos")).fetchAll(db)
// } else {
// return try Ribbon.filter(idColumn == id).fetchAll(db)
// }
// {
// if book == "" { // if book == "" {
// return try Ribbon.filter(bookColumn == Ribbon.randomBook()).fetchAll(db) // return try Ribbon.filter(bookColumn == Ribbon.randomBook()).fetchAll(db)
// } else { // } else {
@ -69,3 +148,14 @@ struct RibbonRequest: Queryable {
// } // }
} }
} }
infix operator %%
extension Int {
static func %% (_ left: Int, _ right: Int) -> Int {
let mod = left % right
return mod >= 0 ? mod : mod + right
}
}

View File

@ -24,15 +24,37 @@ struct SegDenormRequest: Queryable {
} }
func fetchValue(_ db: Database) throws -> [SegDenorm] { func fetchValue(_ db: Database) throws -> [SegDenorm] {
print("WOOOOOOF") print("segs denorm fetching for \(book)")
var sql = "select seg_id as id, seg.book as book, group_concat(line.body, ';;') as body from seg join line on seg.line_id = line.rowid WHERE seg.book = 'bible.john' group by seg.seg_id" print(book)
var sql = """
select seg_id as id, seg.book as book, group_concat(line.body, ';;') as body from \
(select * from seg where seg.book = '\(book)') as seg \
join (select * from line where line.book = '\(book)') as line \
on seg.line_id = line.line_id group by seg.seg_id
"""
do { do
var ret = try SegDenorm.fetchAll(db, sql: sql) // [Player] {
var ret = try SegDenorm.fetchAll(db, sql: sql)
// print("SEGS DENORM") // print("SEGS DENORM")
// print(ret) // print(ret[0])
// var sql2 = """
// select count(1) from seg where seg.book = '\(book)'
// """
// var ret2 = try SegDenorm.fetchAll(db, sql: sql2)
// print("test sql result")
// print(ret2[0])
return ret return ret
} catch let error { } catch let error {
print(error.localizedDescription) print(error.localizedDescription)
print(error) print(error)

26
SegmentedSelector.swift Normal file
View File

@ -0,0 +1,26 @@
@State var selection = 0
var body: some View {
HStack {
BackArrow()
.frame(width: CGFloat(30), height: CGFloat(30))
.foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
.if(selection == 0) { $0.background(Color.white) }
.if(selection != 0) { $0.background(Color.black) }
.onTapGesture {
withAnimation(.spring(response: 0.5)) {
self.selection = 0
}
}
ForwardArrow()
.frame(width: CGFloat(30), height: CGFloat(30))
.foregroundColor(Color(UIColor(red: 0.30, green: 0.30, blue: 0.30, alpha: 0.4)))
.if(selection == 1) { $0.background(Color.white) }
.if(selection != 1) { $0.background(Color.black) }
.onTapGesture {
withAnimation(.spring(response: 0.5)) {
self.selection = 1
}
}
}
}

View File

@ -17,7 +17,7 @@ struct SelectedRibbon: 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 ribbonId: Int64 var ribbonGroupId: Int64
} }
extension SelectedRibbon { extension SelectedRibbon {
@ -32,7 +32,7 @@ extension SelectedRibbon: 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 ribbonId = Column(CodingKeys.ribbonId) static let ribbonGroupId = Column(CodingKeys.ribbonGroupId)
} }
/// Updates a player id after it has been inserted in the database. /// Updates a player id after it has been inserted in the database.

View File

@ -51,11 +51,16 @@ struct SelectedRibbonRequest: Queryable {
// var ret3 = try Ribbon.fetchAll(db, sql: "SELECT * FROM Ribbon") // [Player] // var ret3 = try Ribbon.fetchAll(db, sql: "SELECT * FROM Ribbon") // [Player]
// print(ret3) // print(ret3)
// print("FETCH JOIN RIBBON") // print("FETCH JOIN RIBBON")
var ret = try Ribbon.fetchAll(db, sql: "SELECT Ribbon.* FROM SelectedRibbon join Ribbon on SelectedRibbon.ribbonId = ribbon.rowId WHERE SelectedRibbon.rowId = 1") // [Player] var ret = try Ribbon.fetchAll(db, sql: """
// print(ret) SELECT Ribbon.* FROM SelectedRibbon \
JOIN (select distinct r1.* from Ribbon r1 join Ribbon r2 ON \
r1.undoLevel = r2.currentLevel AND r1.id = r2.id ORDER BY pos ASC) as Ribbon \
ON SelectedRibbon.ribbonGroupId = Ribbon.groupId \
WHERE SelectedRibbon.rowId = 1
""")
// [Player]
print("Selected Ribbon query result: \(ret)")
return ret return ret
} }
} }

113
Stats.swift Normal file
View File

@ -0,0 +1,113 @@
import GRDB
import GRDBQuery
import Foundation
import SwiftUI
var fontSize = CGFloat(12)
struct StatsPanel: View {
@ObservedObject var paneConnector: PaneConnector
@Query(RibbonRequest(dir: .prev, groupId: 1)) private var backRibbon: [Ribbon]
@Query(RibbonRequest(dir: .next, groupId: 1)) private var nextRibbon: [Ribbon]
@Query(RibbonRequest(groupId: 1)) private var allRibbons: [Ribbon]
@Query(SelectedRibbonRequest()) private var selectedRibbon: [Ribbon]
@Environment(\.appDatabase) private var appDatabase
var body: some View {
VStack (spacing: 10) {
VStack {
Text("back Ribbon")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
RibbonDebug(ribbonDebug: RibbonDebugPrint(ribbon: backRibbon[0]))
}
VStack {
Text("next Ribbon")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
if (nextRibbon.count > 0) {
RibbonDebug(ribbonDebug: RibbonDebugPrint(ribbon: nextRibbon[0]))
}
}
VStack {
Text("selected Ribbon")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
RibbonDebug(ribbonDebug: RibbonDebugPrint(ribbon: selectedRibbon[0]))
}
ForEach(RibbonMap(ribbons: allRibbons), id: \.self) { ribbon in
Print("quack3: \(ribbon)")
RibbonDebug(ribbonDebug: ribbon)
}
//VStack(spacing: 10) {
// Text("All Ribbons")
// .foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
// .font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
// ForEach(RibbonMap(ribbons: allRibbons), id: \.self) { ribbon in
// //Print("quack2: \(ribbon)")
// RibbonDebug(ribbonDebug: RibbonDebugPrint(ribbon: ribbon))
// }
//}
VStack {
Text("pc offset: \(paneConnector.currentOffset)")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
}
VStack {
Text("pc id: \(paneConnector.currentId)")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
}
}
}
}
func RibbonMap(ribbons: [Ribbon]) -> [[String]] {
var retStrings = [[String]]()
for r in ribbons {
var debugString = RibbonDebugPrint(ribbon:r)
retStrings.append(debugString)
}
return retStrings
}
func RibbonDebugPrint(ribbon: Ribbon) -> [String] {
var ribbonStats = [String]()
ribbonStats.append("id: \(ribbon.id) ")
ribbonStats.append("scrollOffset: \(ribbon.scrollOffset)")
ribbonStats.append("scrollId: \(ribbon.scrollId)")
ribbonStats.append("undoLevel: \(ribbon.undoLevel)")
ribbonStats.append("currentLevel: \(ribbon.currentLevel)")
ribbonStats.append("minLevel: \(ribbon.minLevel)")
ribbonStats.append("maxLevel: \(ribbon.maxLevel)")
return ribbonStats
}
struct RibbonDebug: View {
@State var ribbonDebug: [String]
var body: some View {
VStack {
VStack {
// let ribbonStats = RibbonDebugPrint(ribbon: ribbon)
Print("quack2: \(ribbonDebug)")
ForEach(ribbonDebug, id: \.self) {
Print("quack2 : \($0)")
Text($0)
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
}
}
}
}
}

View File

@ -7,6 +7,10 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
851259B02C05281300BE70F8 /* BackButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851259AF2C05281300BE70F8 /* BackButton.swift */; };
851259B22C05299200BE70F8 /* ForwardArrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851259B12C05299200BE70F8 /* ForwardArrow.swift */; };
851259B62C07560800BE70F8 /* NaviBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851259B52C07560800BE70F8 /* NaviBar.swift */; };
851259B82C0A145500BE70F8 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851259B72C0A145500BE70F8 /* Stats.swift */; };
8514D5BC299EFB780054F185 /* store.db in Resources */ = {isa = PBXBuildFile; fileRef = 8514D5BB299EFB780054F185 /* store.db */; }; 8514D5BC299EFB780054F185 /* store.db in Resources */ = {isa = PBXBuildFile; fileRef = 8514D5BB299EFB780054F185 /* store.db */; };
8514D5BF299F04710054F185 /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 8514D5BE299F04710054F185 /* GRDB */; }; 8514D5BF299F04710054F185 /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 8514D5BE299F04710054F185 /* GRDB */; };
852774C129A150B100458CA7 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852774C029A150B100458CA7 /* Line.swift */; }; 852774C129A150B100458CA7 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852774C029A150B100458CA7 /* Line.swift */; };
@ -45,6 +49,10 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
851259AF2C05281300BE70F8 /* BackButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackButton.swift; sourceTree = "<group>"; };
851259B12C05299200BE70F8 /* ForwardArrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardArrow.swift; sourceTree = "<group>"; };
851259B52C07560800BE70F8 /* NaviBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NaviBar.swift; sourceTree = "<group>"; };
851259B72C0A145500BE70F8 /* Stats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Stats.swift; sourceTree = "<group>"; };
8514D5BB299EFB780054F185 /* store.db */ = {isa = PBXFileReference; lastKnownFileType = file; path = store.db; sourceTree = "<group>"; }; 8514D5BB299EFB780054F185 /* store.db */ = {isa = PBXFileReference; lastKnownFileType = file; path = store.db; sourceTree = "<group>"; };
852774C029A150B100458CA7 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; }; 852774C029A150B100458CA7 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
8528897429B2B86B003F2E16 /* CrownOfThorns.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrownOfThorns.swift; sourceTree = "<group>"; }; 8528897429B2B86B003F2E16 /* CrownOfThorns.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrownOfThorns.swift; sourceTree = "<group>"; };
@ -108,6 +116,8 @@
85431A7C2905F4F500EE0760 = { 85431A7C2905F4F500EE0760 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
851259B12C05299200BE70F8 /* ForwardArrow.swift */,
851259AF2C05281300BE70F8 /* BackButton.swift */,
857C34482BFB7DC800661A63 /* Fenestra.swift */, 857C34482BFB7DC800661A63 /* Fenestra.swift */,
8594ED972BF6845F001213F2 /* HexColor.swift */, 8594ED972BF6845F001213F2 /* HexColor.swift */,
85E00E7B29F34D2D00FF9E78 /* ScrollState.swift */, 85E00E7B29F34D2D00FF9E78 /* ScrollState.swift */,
@ -117,6 +127,8 @@
85942EEE29AEA18300307621 /* SelectedRibbonRequest.swift */, 85942EEE29AEA18300307621 /* SelectedRibbonRequest.swift */,
85942EF429B108C600307621 /* Seg.swift */, 85942EF429B108C600307621 /* Seg.swift */,
85942EF629B108EA00307621 /* SegDenormRequest.swift */, 85942EF629B108EA00307621 /* SegDenormRequest.swift */,
851259B52C07560800BE70F8 /* NaviBar.swift */,
851259B72C0A145500BE70F8 /* Stats.swift */,
85942EF829B1150B00307621 /* SegDenorm.swift */, 85942EF829B1150B00307621 /* SegDenorm.swift */,
85942EEA29AD55A400307621 /* RibbonRequest.swift */, 85942EEA29AD55A400307621 /* RibbonRequest.swift */,
85942EE329ACF54A00307621 /* ScrollableView.swift */, 85942EE329ACF54A00307621 /* ScrollableView.swift */,
@ -285,6 +297,7 @@
857C34492BFB7DC800661A63 /* Fenestra.swift in Sources */, 857C34492BFB7DC800661A63 /* Fenestra.swift in Sources */,
85942EEB29AD55A400307621 /* RibbonRequest.swift in Sources */, 85942EEB29AD55A400307621 /* RibbonRequest.swift in Sources */,
85431A8B2905F4F500EE0760 /* ContentView.swift in Sources */, 85431A8B2905F4F500EE0760 /* ContentView.swift in Sources */,
851259B02C05281300BE70F8 /* BackButton.swift in Sources */,
85942EF529B108C600307621 /* Seg.swift in Sources */, 85942EF529B108C600307621 /* Seg.swift in Sources */,
85E00E7C29F34D2D00FF9E78 /* ScrollState.swift in Sources */, 85E00E7C29F34D2D00FF9E78 /* ScrollState.swift in Sources */,
8594ED982BF6845F001213F2 /* HexColor.swift in Sources */, 8594ED982BF6845F001213F2 /* HexColor.swift in Sources */,
@ -297,12 +310,15 @@
85942EEF29AEA18300307621 /* SelectedRibbonRequest.swift in Sources */, 85942EEF29AEA18300307621 /* SelectedRibbonRequest.swift in Sources */,
8590D96C29A92146001EF84F /* JsonImport.swift in Sources */, 8590D96C29A92146001EF84F /* JsonImport.swift in Sources */,
85942EED29AEA04200307621 /* SelectedRibbon.swift in Sources */, 85942EED29AEA04200307621 /* SelectedRibbon.swift in Sources */,
851259B82C0A145500BE70F8 /* Stats.swift in Sources */,
85431A892905F4F500EE0760 /* glossApp.swift in Sources */, 85431A892905F4F500EE0760 /* glossApp.swift in Sources */,
8528897C29BD69B2003F2E16 /* VisibilityTrackingScrollView.swift in Sources */, 8528897C29BD69B2003F2E16 /* VisibilityTrackingScrollView.swift in Sources */,
85942EF929B1150B00307621 /* SegDenorm.swift in Sources */, 85942EF929B1150B00307621 /* SegDenorm.swift in Sources */,
85431A9C2905F5D800EE0760 /* SwiftUIView.swift in Sources */, 85431A9C2905F5D800EE0760 /* SwiftUIView.swift in Sources */,
851259B22C05299200BE70F8 /* ForwardArrow.swift in Sources */,
8528897E29BD69B2003F2E16 /* VisibilityTracker.swift in Sources */, 8528897E29BD69B2003F2E16 /* VisibilityTracker.swift in Sources */,
85942EF729B108EA00307621 /* SegDenormRequest.swift in Sources */, 85942EF729B108EA00307621 /* SegDenormRequest.swift in Sources */,
851259B62C07560800BE70F8 /* NaviBar.swift in Sources */,
8528897D29BD69B2003F2E16 /* VisibilityTrackingModifier.swift in Sources */, 8528897D29BD69B2003F2E16 /* VisibilityTrackingModifier.swift in Sources */,
85942EE429ACF54A00307621 /* ScrollableView.swift in Sources */, 85942EE429ACF54A00307621 /* ScrollableView.swift in Sources */,
); );

View File

@ -1,6 +1,10 @@
import Foundation import Foundation
import GRDB import GRDB
let totalLevels = 3
/// AppDatabase lets the application access the database. /// AppDatabase lets the application access the database.
/// ///
/// It applies the pratices recommended at /// It applies the pratices recommended at
@ -39,6 +43,7 @@ struct AppDatabase {
t.autoIncrementedPrimaryKey("id") t.autoIncrementedPrimaryKey("id")
t.column("body", .text).notNull() t.column("body", .text).notNull()
t.column("chap", .integer).notNull() t.column("chap", .integer).notNull()
t.column("line_id", .integer).notNull()
t.column("book", .text).notNull() t.column("book", .text).notNull()
t.column("verse", .integer) t.column("verse", .integer)
} }
@ -53,6 +58,13 @@ 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("pos", .integer).notNull()
t.column("groupId", .integer).notNull()
t.column("undoLevel", .integer).notNull()
t.column("currentLevel", .integer).notNull()
t.column("minLevel", .integer).notNull()
t.column("maxLevel", .integer).notNull()
.defaults(to: 1)
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()
@ -61,7 +73,7 @@ struct AppDatabase {
try db.create(table: "SelectedRibbon") { t in try db.create(table: "SelectedRibbon") { t in
t.autoIncrementedPrimaryKey("id") t.autoIncrementedPrimaryKey("id")
t.column("ribbonId", .integer).notNull() t.column("ribbonGroupId", .integer).notNull()
} }
try db.create(table: "ScrollState") { t in try db.create(table: "ScrollState") { t in
@ -70,7 +82,8 @@ struct AppDatabase {
t.column("scrollOffset", .integer).notNull() t.column("scrollOffset", .integer).notNull()
} }
try db.create(table: "foo2") { t in // change this to nuke/remake the database
try db.create(table: "foo1") { t in
t.autoIncrementedPrimaryKey("id") t.autoIncrementedPrimaryKey("id")
t.column("ribbonId", .integer).notNull() t.column("ribbonId", .integer).notNull()
} }
@ -113,6 +126,22 @@ func load<T: Decodable>(_ filename: String) -> T {
extension AppDatabase { extension AppDatabase {
func getSelectedRibbon() async throws -> [Ribbon] {
try await dbWriter.write { db in
var sr = try Ribbon.fetchAll(db, sql: """
SELECT Ribbon.* FROM SelectedRibbon \
JOIN (select distinct r1.* from Ribbon r1 join Ribbon r2 ON \
r1.undoLevel = r2.currentLevel AND r1.id = r2.id ORDER BY pos ASC) as Ribbon \
ON SelectedRibbon.ribbonGroupId = Ribbon.groupId \
WHERE SelectedRibbon.rowId = 1
""")
print("meow get selected ribbon \(sr)")
return sr
}
}
func updateRibbonPosition(_ ribbon: inout Ribbon, _ oldPos: Int, _ newPos: Int) async throws { func updateRibbonPosition(_ ribbon: inout Ribbon, _ oldPos: Int, _ newPos: Int) async throws {
try await dbWriter.write { [ribbon] db in try await dbWriter.write { [ribbon] db in
@ -193,6 +222,121 @@ extension AppDatabase {
} }
} }
func undoRibbon(_ ribbon: inout Ribbon) async throws {
let currentLevel = ribbon.currentLevel
let minLevel = ribbon.minLevel
if currentLevel == minLevel {
print("no where to undo")
return
}
let newCurrent = (ribbon.currentLevel - 1) %% totalLevels
print("meow new current: \(newCurrent)")
do {
try await dbWriter.write { [ribbon] db in
print("back executing")
try db.execute(sql: """
UPDATE Ribbon \
SET currentLevel = ? WHERE groupId = ?
""", arguments: [newCurrent, ribbon.groupId])
var ret3 = try Ribbon.fetchAll(db, sql: """
SELECT * from Ribbon \
WHERE groupId = ?
""", arguments: [ribbon.groupId])
print("back ret3: \(ret3)")
}
} catch {
print("back error")
print("Error info: \(error)")
}
}
func bumpRibbon(_ ribbon: inout Ribbon) async throws -> [Ribbon] {
var level = ribbon.currentLevel
let maxLevel = ribbon.maxLevel
var delLevels2 = [Int]()
while level != maxLevel {
level = (level + 1) % totalLevels
delLevels2.append(level)
}
let delLevels = delLevels2
let newMax = (ribbon.currentLevel + 1) %% totalLevels
let newCurrent = newMax
let newMin = newMax == ribbon.minLevel ? (ribbon.minLevel + 1) %% totalLevels
: ribbon.minLevel
ribbon.minLevel = newMin
ribbon.maxLevel = newMax
ribbon.undoLevel = newCurrent
ribbon.currentLevel = newCurrent
ribbon.id = nil
do {
try await dbWriter.write { [ribbon] db in
print("meow enter bump 1")
for l in delLevels {
try db.execute(sql: """
DELETE FROM Ribbon \
WHERE groupId = ? \
AND undoLevel = ?
""", arguments: [ribbon.groupId, l])
}
try db.execute(sql: """
UPDATE Ribbon \
SET minLevel = ?, maxLevel = ?, currentLevel = ? WHERE groupId = ?
""", arguments: [newMin, newMax, newCurrent, ribbon.groupId])
// upsert
var ret = try Ribbon.fetchAll(db, sql: """
SELECT * from Ribbon WHERE groupId = ? AND undoLevel = ?
""", arguments: [ribbon.groupId, ribbon.undoLevel])
print("meow enter bump 3")
if ret.count == 0 {
// insert
_ = try ribbon.inserted(db)
} else {
var updatedRibbon = ret[0]
updatedRibbon.minLevel = newMin
updatedRibbon.maxLevel = newMax
updatedRibbon.undoLevel = newCurrent
updatedRibbon.currentLevel = newCurrent
updatedRibbon.scrollId = ribbon.scrollId
updatedRibbon.scrollOffset = ribbon.scrollOffset
try updatedRibbon.update(db)
}
ret = try Ribbon.fetchAll(db, sql: """
SELECT * from Ribbon WHERE groupId = ? AND undoLevel = ?
""", arguments: [ribbon.groupId, ribbon.undoLevel])
let ret2 = try Ribbon.fetchAll(db, sql: """
SELECT * from Ribbon WHERE groupId = 1 ORDER BY undoLevel ASC
""")
for r2 in ret2 {
print("meow ribbon dump: \(r2)")
}
print("meow bumped ribbon: \(ret)")
return ret
}
} catch {
print("Error info: \(error)")
}
return []
}
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
@ -214,33 +358,104 @@ 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)
if try Line.all().isEmpty(db) { var x = 0
// if try Line.all().isEmpty(db) {
for l in importJson.lines { for l in importJson.lines {
print("importing Lines") // print("importing Lines")
if x < 5 {
print(l)
x += 1
}
_ = try l.inserted(db) _ = try l.inserted(db)
} }
x = 0
for l in importJson.segs { for l in importJson.segs {
print("importing SEGS") // print("importing SEGS")
_ = try l.inserted(db)
if x < 5 {
print(l)
x += 1
} }
_ = try l.inserted(db)
} }
} }
/// Create random Lines if the database is empty. /// Create random Lines if the database is empty.
func initDatabase() throws { func initDatabase() throws {
do {
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, pos: 1, title: "John", book: "bible.john", scrollId: "1", scrollOffset: 0).inserted(db) _ = try Ribbon(id: 1,
_ = try Ribbon(id: 2, pos: 2, title: "Gospel of Mark", book: "bible.mark", scrollId: "1", scrollOffset: 300).inserted(db) groupId: 1,
_ = try Ribbon(id: 3, pos: 3, title: "John 2", book: "bible.john", scrollId: "1", scrollOffset: 0).inserted(db) pos: 1,
_ = try SelectedRibbon(id: 1, ribbonId: 1).inserted(db) undoLevel: 0,
currentLevel: 0,
minLevel: 0,
maxLevel: 0,
title: "John",
book: "bible.john",
scrollId: "1",
scrollOffset: 0).inserted(db)
_ = try Ribbon(id: 2,
groupId: 2,
pos: 2,
undoLevel: 0,
currentLevel: 0,
minLevel: 0,
maxLevel: 0,
title: "Gospel of Mark",
book: "bible.mark",
scrollId: "1",
scrollOffset: 300).inserted(db)
/////
_ = try Ribbon(id: 3,
groupId: 3,
pos: 3,
undoLevel: 0,
currentLevel: 2,
minLevel: 0,
maxLevel: 2,
title: "bottom",
book: "bible.john",
scrollId: "1",
scrollOffset: 0).inserted(db)
_ = try Ribbon(id: 4,
groupId: 3,
pos: 3,
undoLevel: 1,
currentLevel: 2,
minLevel: 0,
maxLevel: 2,
title: "topp",
book: "bible.john",
scrollId: "1",
scrollOffset: 0).inserted(db)
_ = try Ribbon(id: 5,
groupId: 3,
pos: 3,
undoLevel: 2,
currentLevel: 2,
minLevel: 0,
maxLevel: 2,
title: "topp",
book: "bible.john",
scrollId: "1",
scrollOffset: 0).inserted(db)
_ = try SelectedRibbon(id: 1, ribbonGroupId: 1).inserted(db)
} }
} }
} catch {
print("Error info: \(error)")
}
} }
} }

View File

@ -39,20 +39,45 @@ public extension UserDefaults {
} }
} }
func updateRibbon(selectedRibbon: Ribbon,
appDatabase : AppDatabase,
paneConnector: PaneConnector) async throws -> [Ribbon]
{
print("meow updating ribbon")
var updatedRibbon = selectedRibbon
var scrollOffsetToSave = Int(floor(paneConnector.currentOffset))
var scrollIdToSave = paneConnector.currentId
print("meow scrolloffsets \(scrollIdToSave) \(scrollOffsetToSave)")
var offsetDiff = abs(scrollOffsetToSave - updatedRibbon.scrollOffset) > 30
var idDiff = Int(updatedRibbon.scrollId) != Int(scrollIdToSave)
if idDiff || offsetDiff {
updatedRibbon.scrollId = scrollIdToSave
updatedRibbon.scrollOffset = scrollOffsetToSave
print("meow bumping")
let ret = try await appDatabase.bumpRibbon(&updatedRibbon)
print("meow finished bumping")
return ret
}
print("meow no bump")
return []
}
func goToRibbon(selectedRibbon: Ribbon, func goToRibbon(selectedRibbon: Ribbon,
destRibbon: Ribbon, destRibbon: Ribbon,
appDatabase: AppDatabase, appDatabase: AppDatabase,
paneConnector: PaneConnector, paneConnector: PaneConnector,
refresh: Binding<Bool>, loading: Bool,
loading: Bool) bump: Bool)
{ {
print("meow goto ribbon - selected ribbon: \(selectedRibbon), dest ribbon: \(destRibbon) ")
DispatchQueue.main.asyncAfter(deadline: .now()) { DispatchQueue.main.asyncAfter(deadline: .now()) {
Task { Task {
var scrollOffsetToSave = paneConnector.currentOffset var scrollOffsetToSave = paneConnector.currentOffset
var scrollIdToSave = paneConnector.currentId var scrollIdToSave = paneConnector.currentId
var updatedRibbon = selectedRibbon
print("go to ribbon") print("go to ribbon")
print("\(selectedRibbon.id) \(destRibbon.id!)") print("\(selectedRibbon.id) \(destRibbon.id!)")
@ -72,9 +97,7 @@ func goToRibbon(selectedRibbon: Ribbon,
print("toggling") print("toggling")
print("paneconnector: \(paneConnector.refresh)") print("paneconnector: \(paneConnector.refresh)")
refresh.wrappedValue.toggle() var updateSelectRibbon = SelectedRibbon(id: Int64(1), ribbonGroupId: Int64(destRibbon.groupId))
var updateSelectRibbon = SelectedRibbon(id: Int64(1), ribbonId: destRibbon.id!)
// print("Saving selected ribbon") // print("Saving selected ribbon")
// print(updateSelectRibbon) // print(updateSelectRibbon)
do { do {
@ -84,15 +107,26 @@ func goToRibbon(selectedRibbon: Ribbon,
} }
} }
if !loading { // // this gets run regardless of if we switch ribbons or not
print("not loading") // // so if you click the same ribbon or a different ribbon
updatedRibbon.scrollOffset = Int(floor(scrollOffsetToSave)) // if !loading || bump {
updatedRibbon.scrollId = scrollIdToSave // print("not loading")
_ = try await appDatabase.saveRibbon(&updatedRibbon)
} else {
print("loading") // print("saving ribbon")
} // // updating the ribbon location
// updatedRibbon.scrollOffset = Int(floor(scrollOffsetToSave))
// updatedRibbon.scrollId = scrollIdToSave
// // updatedRibbon.undoLevel = updatedRibbon.undoLevel + 1
// // updatedRibbon.currentLevel = updatedRibbon.currentLevel + 1
// if bump {
// _ = try await appDatabase.bumpRibbon(&updatedRibbon)
// }
// } else {
// print("loading")
// }
} }
} }
@ -117,7 +151,7 @@ struct RibbonCrown: View {
@Environment(\.appDatabase) private var appDatabase @Environment(\.appDatabase) private var appDatabase
@Query(SelectedRibbonRequest()) private var sr: [Ribbon] @Query(SelectedRibbonRequest()) private var selectedRibbon: [Ribbon]
@State var saveOffset = CGFloat() @State var saveOffset = CGFloat()
@Binding var refresh: Bool @Binding var refresh: Bool
@ -149,12 +183,18 @@ struct RibbonCrown: View {
} }
.onTapGesture { .onTapGesture {
Task { Task {
goToRibbon(selectedRibbon: sr[0],
let sr = selectedRibbon[0]
let updatedRibbon = try await updateRibbon(selectedRibbon: sr,
appDatabase: appDatabase,
paneConnector: paneConnector)
goToRibbon(selectedRibbon: sr,
destRibbon: ribbon, destRibbon: ribbon,
appDatabase: appDatabase, appDatabase: appDatabase,
paneConnector: paneConnector, paneConnector: paneConnector,
refresh: $refresh, loading: false,
loading: false) bump: true)
} }
} }
.frame(width: CGFloat(100 * 1.66 * scale + 10), height: CGFloat(100 * scale + 5)) .frame(width: CGFloat(100 * 1.66 * scale + 10), height: CGFloat(100 * scale + 5))
@ -191,6 +231,7 @@ class PaneConnector: NSObject, ObservableObject {
// var setScrollOffset: CGFloat // var setScrollOffset: CGFloat
var showOverlay: Bool = false var showOverlay: Bool = false
@Published var refresh: Bool = false @Published var refresh: Bool = false
@Published var vertSep = CGFloat(20)
var currentId = "" var currentId = ""
var currentOffset = CGFloat() var currentOffset = CGFloat()
var visibilityTracker: VisibilityTracker<String>? var visibilityTracker: VisibilityTracker<String>?
@ -204,25 +245,21 @@ struct ContentView: View {
@State var viewState = CGSize.zero @State var viewState = CGSize.zero
@State var pulledOut = CGSize.zero @State var pulledOut = CGSize.zero
@State var selection = 0
@StateObject var paneConnector = PaneConnector() @StateObject var paneConnector = PaneConnector()
@State var refresh: Bool = false @State var refresh: Bool = false
@State var vertSep = CGFloat(20)
@State var endedDrag = true
@State var readOffset = CGPoint() @State var readOffset = CGPoint()
@State var dragOffset = CGFloat()
@Query(SegDenormRequest(book: "bible.john")) private var segs: [SegDenorm]
@State var draggedRibbon: Ribbon? @State var draggedRibbon: Ribbon?
@State var isDragging = false @State var isDragging = false
@Environment(\.appDatabase) private var appDatabase @Environment(\.appDatabase) private var appDatabase
@Query(SegDenormRequest(book: "bible.mark")) private var segs: [SegDenorm]
@Query(RibbonRequest()) private var ribbons: [Ribbon] @Query(RibbonRequest()) private var ribbons: [Ribbon]
@Query<SelectedRibbonRequest> var selectedRibbon: [Ribbon] @Query<SelectedRibbonRequest> var selectedRibbon: [Ribbon]
@ -271,13 +308,25 @@ struct ContentView: View {
.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)
VStack {
Text("pc offset: \(paneConnector.currentOffset)")
.foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
.font(Font.custom("AveriaSerifLibre-Regular", size: fontSize))
}
VStack {
NaviBar(paneConnector: paneConnector)
StatsPanel(paneConnector: paneConnector)
}
.frame(maxWidth: 250)
.offset(x: geometry.size.width - 250)
VStack { VStack {
// Top pane // Top pane
Pane(paneConnector: paneConnector, Pane(paneConnector: paneConnector,
segs: segs,
selectedRibbon: selectedRibbon, selectedRibbon: selectedRibbon,
width: geometry.size.width - 50, width: geometry.size.width - 50,
height: geometry.size.height / 2 - vertSep) height: geometry.size.height / 2)
////// //////
Text("separator").foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00))) Text("separator").foregroundColor(Color(UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 1.00)))
@ -285,7 +334,7 @@ struct ContentView: View {
DragGesture() DragGesture()
.onChanged { gesture in .onChanged { gesture in
vertSep = vertSep - gesture.translation.height paneConnector.vertSep = paneConnector.vertSep - gesture.translation.height
Print(gesture.translation.width) Print(gesture.translation.width)
Print(gesture.translation.height) Print(gesture.translation.height)
@ -335,33 +384,30 @@ struct ContentView: View {
DragGesture() DragGesture()
.onChanged { gesture in .onChanged { gesture in
if endedDrag { print(viewState.width)
endedDrag = false print(pulledOut.width)
// threshold of how much to swipe before the view drags
//TODO: should this still be adjusted if abs(gesture.translation.width) > 10 {
//scrollOffset = readOffset.y - 20
}
Print(viewState.width)
if abs(gesture.translation.width) > 20 {
viewState.width = gesture.translation.width viewState.width = gesture.translation.width
if gesture.translation.width < -50, pulledOut.width == CGFloat(0) { // if gesture.translation.width < -50, pulledOut.width == CGFloat(0) {
dragOffset = gesture.translation.width + 50 // }
}
} }
} }
.onEnded { _ in .onEnded { _ in
endedDrag = true var setPulledOutWith = CGFloat(0)
var pulledOutWidth = CGFloat(0) if viewState.width < 0 && pulledOut.width > 0 {
if viewState.width < 0 { setPulledOutWith = CGFloat(0)
pulledOutWidth = CGFloat(0) } else if viewState.width > 0 && pulledOut.width < 0 {
setPulledOutWith = CGFloat(0)
} else if viewState.width < 0 && pulledOut.width == 0 {
setPulledOutWith = CGFloat(-200)
} else if abs(viewState.width + pulledOut.width) > 30 { } else if abs(viewState.width + pulledOut.width) > 30 {
pulledOutWidth = CGFloat(200) setPulledOutWith = CGFloat(200)
} }
withAnimation(.spring(response: 0.2)) { withAnimation(.spring(response: 0.2)) {
pulledOut.width = pulledOutWidth pulledOut.width = setPulledOutWith
viewState = .zero viewState = .zero
dragOffset = .zero
} }
} }
) )
@ -389,27 +435,7 @@ struct ContentView: View {
} }
} }
} }
func handleVisibilityChanged2(_: String, change _: VisibilityChange, tracker _: VisibilityTracker<String>) {} func handleVisibilityChanged2(_: String, change _: VisibilityChange, tracker _: VisibilityTracker<String>) {}
func handleVisibilityChanged(_: String, change _: VisibilityChange, tracker: VisibilityTracker<String>) {
// var printRate: Int64 = 10
// gTracker = tracker
self.paneConnector.visibilityTracker = tracker
let visibleViews2 = Array(tracker.visibleViews.keys)
if visibleViews2.count == 0 {
return
}
// currentId = tracker.sortedViewIDs[tracker.sortedViewIDs.count - 1]
currentId = tracker.sortedViewIDs[0]
currentOffset = tracker.visibleViews[currentId!]!
self.paneConnector.currentId = tracker.sortedViewIDs[0]
self.paneConnector.currentOffset = tracker.visibleViews[currentId!]!
}
} }
private let itemFormatter: DateFormatter = { private let itemFormatter: DateFormatter = {

View File

@ -1,39 +1,17 @@
import GRDB import GRDB
/// The Line struct. /// The Line struct.
///
/// Identifiable conformance supports SwiftUI list animations, and type-safe
/// GRDB primary key methods.
/// Equatable conformance supports tests.
struct Line: Identifiable, Equatable { struct Line: Identifiable, Equatable {
/// The player id.
///
/// Int64 is the recommended type for auto-incremented database ids.
/// Use nil for players that are not inserted yet in the database.
var id: Int64? var id: Int64?
var chap: Int var chap: Int
var line_id: Int // this is a line_id per book
var verse: Int var verse: Int
var body: String var body: String
var book: String var book: String
} }
extension Line { extension Line {
private static let books = [ private static let books = [
"John", "Matthew", "Imitation of Christ"] "John", "Matthew", "Imitation of Christ"]
/// Creates a new player with empty name and zero score
// static func new() -> Line {
// Line(id: nil, chap: 1, body: "")
// }
/// Returns a random score
static func randomScore() -> Int {
10 * Int.random(in: 0...100)
}
static func randomBook() -> String {
books.randomElement()!
}
} }
// MARK: - Persistence // MARK: - Persistence

View File

@ -49,11 +49,12 @@ struct LineRequest: 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
// to test LineRequest. // to test LineRequest.
func fetchValue(_ db: Database) throws -> [Line] { func fetchValue(_ db: Database) throws -> [Line] {
if book == "" {
return try Line.filter(bookColumn == Line.randomBook()).fetchAll(db)
} else {
return try Line.filter(bookColumn == book).fetchAll(db) return try Line.filter(bookColumn == book).fetchAll(db)
} // if book == "" {
// return try Line.filter(bookColumn == Line.randomBook()).fetchAll(db)
// } else {
// return try Line.filter(bookColumn == book).fetchAll(db)
// }
// switch ordering { // switch ordering {
// case .byScore: // case .byScore:
// return try Line.all().fetchAll(db) // return try Line.all().fetchAll(db)

View File

@ -40,6 +40,7 @@ extension AppDatabase {
// // demo purpose. // // demo purpose.
// try appDatabase.createRandomPlayersIfEmpty() // try appDatabase.createRandomPlayersIfEmpty()
// } // }
print("initing database")
try appDatabase.initDatabase() try appDatabase.initDatabase()

View File

@ -17,7 +17,12 @@ 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 groupId: Int
var pos: Int var pos: Int
var undoLevel: Int
var currentLevel: Int
var minLevel: Int
var maxLevel: Int
var title: String var title: String
var book: String var book: String
var scrollId: String var scrollId: String
@ -27,7 +32,6 @@ struct Ribbon: Identifiable, Equatable {
extension Ribbon { extension Ribbon {
} }
// MARK: - Persistence
/// Make Line a Codable Record. /// Make Line a Codable Record.
/// ///

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long