Skip to content

Commit

Permalink
Render comments inside environments
Browse files Browse the repository at this point in the history
  • Loading branch information
Desbeers committed Oct 25, 2023
1 parent 12f4f59 commit eaa0b20
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 77 deletions.
29 changes: 20 additions & 9 deletions Chord Provider/ChordProParser/ChordPro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ enum ChordPro {
var currentSection = Song.Section(id: song.sections.count + 1)
/// Parse each line of the text:
for text in text.components(separatedBy: .newlines) {
switch text.prefix(1) {
switch text.trimmingCharacters(in: .whitespaces).prefix(1) {
case "{":
/// Directive
processDirective(text: text, song: &song, currentSection: &currentSection)
Expand Down Expand Up @@ -129,14 +129,25 @@ enum ChordPro {

case .c, .comment:
if let label {
processSection(
label: label,
type: Environment.comment,
song: &song,
currentSection: &currentSection
)
song.sections.append(currentSection)
currentSection = Song.Section(id: song.sections.count + 1)
/// Start with a new line
var line = Song.Section.Line(id: currentSection.lines.count + 1)
line.comment = label
switch currentSection.type {
case .none:
/// A comment in its own section
processSection(
label: Environment.comment.rawValue,
type: Environment.comment,
song: &song,
currentSection: &currentSection
)
currentSection.lines.append(line)
song.sections.append(currentSection)
currentSection = Song.Section(id: song.sections.count + 1)
default:
/// An inline comment, e.g. inside a verse or chorus
currentSection.lines.append(line)
}
}

// MARK: Environment directives
Expand Down
12 changes: 6 additions & 6 deletions Chord Provider/Export/ExportSong+render.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,19 @@ extension ExportSong {
for section in song.sections {
switch section.type {
case .verse, .bridge:
part = renderPart(view: Song.Render.VerseView(section: section, options: options, chords: song.chords))
part = renderPart(view: Song.Render.VerseSectionView(section: section, options: options, chords: song.chords))
case .chorus:
part = renderPart(view: Song.Render.ChorusView(section: section, options: options, chords: song.chords))
part = renderPart(view: Song.Render.ChorusSectionView(section: section, options: options, chords: song.chords))
case .repeatChorus:
part = renderPart(view: Song.Render.RepeatChorusView(section: section, options: options))
case .tab:
part = renderPart(view: Song.Render.TabView(section: section, options: options))
part = renderPart(view: Song.Render.TabSectionView(section: section, options: options))
case .grid:
part = renderPart(view: Song.Render.GridView(section: section, options: options, chords: song.chords))
part = renderPart(view: Song.Render.GridSectionView(section: section, options: options, chords: song.chords))
case .comment:
part = renderPart(view: Song.Render.CommentView(section: section, options: options))
part = renderPart(view: Song.Render.CommentSectionView(section: section, options: options))
default:
part = renderPart(view: Song.Render.PlainView(section: section, options: options))
part = renderPart(view: Song.Render.PlainSectionView(section: section, options: options))
}
if let part {
parts.append(part)
Expand Down
166 changes: 104 additions & 62 deletions Chord Provider/SongModel/Song+Render/Song+Render.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,19 @@ extension Song {
ForEach(song.sections) { section in
switch section.type {
case .verse, .bridge:
VerseView(section: section, options: options, chords: song.chords)
VerseSectionView(section: section, options: options, chords: song.chords)
case .chorus:
ChorusView(section: section, options: options, chords: song.chords)
ChorusSectionView(section: section, options: options, chords: song.chords)
case .repeatChorus:
RepeatChorusView(section: section, options: options)
case .tab:
TabView(section: section, options: options)
TabSectionView(section: section, options: options)
case .grid:
GridView(section: section, options: options, chords: song.chords)
GridSectionView(section: section, options: options, chords: song.chords)
case .comment:
CommentView(section: section, options: options)
CommentSectionView(section: section, options: options)
default:
PlainView(section: section, options: options)
PlainSectionView(section: section, options: options)
}
}
}
Expand Down Expand Up @@ -131,27 +131,35 @@ extension Song.Render {
}
}

/// SwiftUI `View` for plain text
struct PlainView: View {
// MARK: Verse

/// SwiftUI `View` for a verse section
struct VerseSectionView: View {
/// The `section` of the song
let section: Song.Section
/// The display options
let options: Song.DisplayOptions
/// The chords of the song
let chords: [ChordDefinition]
/// The body of the `View`
var body: some View {
VStack(alignment: .leading) {
ForEach(section.lines) { line in
ForEach(line.parts) { part in
Text(part.text.trimmingCharacters(in: .whitespacesAndNewlines))
if line.comment.isEmpty {
PartsView(options: options, sectionID: section.id, parts: line.parts, chords: chords)
} else {
CommentLabelView(comment: line.comment, options: options)
}
}
}
.modifier(SectionView(options: options, label: section.label))
}
}

/// SwiftUI `View` for a grid
struct GridView: View {
// MARK: Chorus

/// SwiftUI `View` for a chorus section
struct ChorusSectionView: View {
/// The `section` of the song
let section: Song.Section
/// The display options
Expand All @@ -160,50 +168,63 @@ extension Song.Render {
let chords: [ChordDefinition]
/// The body of the `View`
var body: some View {
VStack(alignment: .leading, spacing: 0) {
Grid(alignment: .leading) {
ForEach(section.lines) { line in
GridRow {
ForEach(line.grid) { grid in
Text("|")
ForEach(grid.parts) { part in
if let chord = chords.first(where: { $0.id == part.chord }) {
ChordView(options: options, sectionID: section.id, partID: part.id, chord: chord)
} else {
Text(part.text)
}
}
}
}
VStack(alignment: .leading) {
ForEach(section.lines) { line in
if line.comment.isEmpty {
PartsView(options: options, sectionID: section.id, parts: line.parts, chords: chords)
} else {
CommentLabelView(comment: line.comment, options: options)
}
}
}
.padding(.vertical, options.scale)
.modifier(SectionView(options: options, label: section.label))
.modifier(SectionView(options: options, label: section.label ?? "Chorus", prominent: true))
}
}

/// SwiftUI `View` for a verse
struct VerseView: View {
/// SwiftUI `View` for a chorus repeat
struct RepeatChorusView: View {
/// The `section` of the song
let section: Song.Section
/// The display options
let options: Song.DisplayOptions
/// The body of the `View`
var body: some View {
ProminentLabel(options: options, label: section.label ?? "Repeat Chorus", icon: "arrow.triangle.2.circlepath")
.modifier(SectionView(options: options))
}
}

// MARK: Tab

/// SwiftUI `View` for a tab section
struct TabSectionView: View {
/// The `section` of the song
let section: Song.Section
/// The display options
let options: Song.DisplayOptions
/// The chords of the song
let chords: [ChordDefinition]
/// The body of the `View`
var body: some View {
VStack(alignment: .leading) {
ForEach(section.lines) { line in
PartsView(options: options, sectionID: section.id, parts: line.parts, chords: chords)
if line.comment.isEmpty {
Text(line.tab)
.lineLimit(1)
.minimumScaleFactor(0.01)
.monospaced()
} else {
CommentLabelView(comment: line.comment, options: options)
}
}
}
.padding(.vertical, options.scale)
.modifier(SectionView(options: options, label: section.label))
}
}

/// SwiftUI `View` for a chorus
struct ChorusView: View {
// MARK: Grid

/// SwiftUI `View` for a grid section
struct GridSectionView: View {
/// The `section` of the song
let section: Song.Section
/// The display options
Expand All @@ -212,63 +233,84 @@ extension Song.Render {
let chords: [ChordDefinition]
/// The body of the `View`
var body: some View {
VStack(alignment: .leading) {
ForEach(section.lines) { line in
PartsView(options: options, sectionID: section.id, parts: line.parts, chords: chords)
VStack(alignment: .leading, spacing: 0) {
Grid(alignment: .leading) {
ForEach(section.lines) { line in
if line.comment.isEmpty {
GridRow {
ForEach(line.grid) { grid in
Text("|")
ForEach(grid.parts) { part in
if let chord = chords.first(where: { $0.id == part.chord }) {
ChordView(options: options, sectionID: section.id, partID: part.id, chord: chord)
} else {
Text(part.text)
}
}
}
}
} else {
CommentLabelView(comment: line.comment, options: options)
}
}
}
}
.modifier(SectionView(options: options, label: section.label ?? "Chorus", prominent: true))
.padding(.vertical, options.scale)
.modifier(SectionView(options: options, label: section.label))
}
}

/// SwiftUI `View` for a chorus repeat
struct RepeatChorusView: View {
// MARK: Comment

/// SwiftUI `View` for a comment in its own section
struct CommentSectionView: View {
/// The `section` of the song
let section: Song.Section
/// The display options
let options: Song.DisplayOptions
/// The body of the `View`
var body: some View {
ProminentLabel(options: options, label: section.label ?? "Repeat Chorus", icon: "arrow.triangle.2.circlepath")
CommentLabelView(comment: section.lines.first?.comment ?? "", options: options)
.modifier(SectionView(options: options))
}
}

/// SwiftUI `View` for a tab
struct TabView: View {
/// The `section` of the song
let section: Song.Section
/// SwiftUI `View` for a comment label
struct CommentLabelView: View {
/// The comment
let comment: String
/// The display options
let options: Song.DisplayOptions
/// The body of the `View`
var body: some View {
VStack(alignment: .leading) {
ForEach(section.lines) { line in
Text(line.tab)
}
}
.lineLimit(1)
.minimumScaleFactor(0.01)
.monospaced()
.padding(.vertical, options.scale)
.modifier(SectionView(options: options, label: section.label))
ProminentLabel(options: options, label: comment, icon: "bubble.right", color: .yellow)
.italic()
}
}

/// SwiftUI `View` for a comment
struct CommentView: View {
// MARK: Plain

/// SwiftUI `View` for a plain text section
struct PlainSectionView: View {
/// The `section` of the song
let section: Song.Section
/// The display options
let options: Song.DisplayOptions
/// The body of the `View`
var body: some View {
ProminentLabel(options: options, label: section.label ?? "", icon: "bubble.right", color: .yellow)
.italic()
.modifier(SectionView(options: options))
VStack(alignment: .leading) {
ForEach(section.lines) { line in
ForEach(line.parts) { part in
Text(part.text.trimmingCharacters(in: .whitespacesAndNewlines))
}
}
}
.modifier(SectionView(options: options, label: section.label))
}
}

// MARK: Parts

/// SwiftUI `View` for parts of a line
struct PartsView: View {
/// The display options
Expand Down
2 changes: 2 additions & 0 deletions Chord Provider/SongModel/Song+Section+Line.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ extension Song.Section {
var grid = [Grid]()
/// The optional tab in the line
var tab: String = ""
/// The optional comment in the line
var comment: String = ""
}
}

0 comments on commit eaa0b20

Please sign in to comment.