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
7 changes: 4 additions & 3 deletions Nifro/Screens/DisplayPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,8 @@ private struct DisplayColumn: View {
PanelButton(
symbol: column.rotationMode.symbol,
label: column.rotationMode.label,
// Lit while it is doing something. Pinned is the resting state and says so by staying dark.
isOn: column.rotationMode != .pinned
// This always names the selected mode, so Pin, Loop and Random all use the selected state.
isOn: true
) {
model.cycleRotationMode(on: column.display)
}
Expand Down Expand Up @@ -442,6 +442,7 @@ private struct DisplayColumn: View {
PanelButton(
symbol: column.isMuted ? "speaker.slash.fill" : "speaker.wave.2.fill",
label: column.isMuted ? String(localized: "Muted") : String(localized: "Playing sound"),
isOn: !column.isMuted,
isEnabled: hasPage
) {
model.toggleMuted(on: column.display)
Expand All @@ -453,7 +454,7 @@ private struct DisplayColumn: View {
// Lit while the wallpaper is up, like every other lit control in the panel. It used
// to be the inverse — lit while the display was switched *off* — which made this the
// one control reading its lit state as "this button is engaged" instead of as "the
// thing it turns on is on". Five controls now answer that question the same way.
// thing it turns on is on". The panel's stateful controls answer that question the same way.
isOn: column.isShowing
) {
model.toggleShowing(on: column.display)
Expand Down
55 changes: 55 additions & 0 deletions Tests/PanelControlStateTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Foundation
import Testing

/**
The panel uses button-shaped toggles for state that is already in effect. Their colour is the
quick reading of that state, so treating one selected mode or an audible page as unselected makes
the panel contradict itself even though its actions still work.
*/
@Suite("Panel controls show enabled state")
struct PanelControlStateTests {
private static let repository = URL(filePath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()

@Test("The current rotation mode is always highlighted, including Pin")
func currentRotationModeIsHighlighted() throws {
let controls = try Self.rotationControls()

#expect(
controls.contains("isOn: true"),
"Pin is a selected rotation mode, so it must be highlighted just like Loop and Random."
)
}

@Test("Sound is highlighted only while it is playing")
func playingSoundIsHighlighted() throws {
let controls = try Self.pictureControls()

#expect(
controls.contains("isOn: !column.isMuted"),
"The speaker control must be highlighted when sound is playing and unhighlighted when it is muted."
)
}

private static func rotationControls() throws -> Substring {
try controls(between: "private var rotationControls: some View", and: "private var modeButtons: some View")
}

private static func pictureControls() throws -> Substring {
try controls(between: "private var preview: some View", and: "private func reading(")
}

private static func controls(between start: String, and end: String) throws -> Substring {
let source = try String(
contentsOf: repository.appending(path: "Nifro/Screens/DisplayPanel.swift"),
encoding: .utf8
)

guard let range = source.range(of: start)?.lowerBound, let end = source.range(of: end)?.lowerBound else {
throw CocoaError(.fileReadCorruptFile)
}

return source[range..<end]
}
}
Loading