better overview design in dark mode
This commit is contained in:
@@ -107,6 +107,10 @@
|
|||||||
"bom.quantity.count.badge" = "%d×";
|
"bom.quantity.count.badge" = "%d×";
|
||||||
"bom.quantity.length.badge" = "%1$.1f %2$@";
|
"bom.quantity.length.badge" = "%1$.1f %2$@";
|
||||||
"bom.quantity.length.badge.with.spec" = "%1$.1f %2$@ · %3$@";
|
"bom.quantity.length.badge.with.spec" = "%1$.1f %2$@ · %3$@";
|
||||||
|
"bom.quantity.fuse.badge" = "%1$d× · %2$d A";
|
||||||
|
"bom.quantity.terminal.badge" = "%1$d× · %2$@";
|
||||||
|
"bom.quantity.cable.badge" = "%1$.1f %2$@ · %3$@";
|
||||||
|
"bom.quantity.single.badge" = "1× • %@";
|
||||||
"cable.pro.privacy.label" = "Privacy";
|
"cable.pro.privacy.label" = "Privacy";
|
||||||
"cable.pro.privacy.url" = "https://voltplan.app/privacy";
|
"cable.pro.privacy.url" = "https://voltplan.app/privacy";
|
||||||
"cable.pro.terms.label" = "Terms";
|
"cable.pro.terms.label" = "Terms";
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ struct SystemOverviewView: View {
|
|||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 20, style: .continuous)
|
RoundedRectangle(cornerRadius: 20, style: .continuous)
|
||||||
.fill(Color(.systemBackground))
|
.fill(Color(.tertiarySystemBackground))
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Button {
|
Button {
|
||||||
@@ -386,7 +386,7 @@ struct SystemOverviewView: View {
|
|||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 20, style: .continuous)
|
RoundedRectangle(cornerRadius: 20, style: .continuous)
|
||||||
.fill(Color(.systemBackground))
|
.fill(Color(.tertiarySystemBackground))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
@@ -477,7 +477,7 @@ struct SystemOverviewView: View {
|
|||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 20, style: .continuous)
|
RoundedRectangle(cornerRadius: 20, style: .continuous)
|
||||||
.fill(Color(.systemBackground))
|
.fill(Color(.tertiarySystemBackground))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
@@ -560,7 +560,7 @@ struct SystemOverviewView: View {
|
|||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 20, style: .continuous)
|
RoundedRectangle(cornerRadius: 20, style: .continuous)
|
||||||
.fill(Color(.systemBackground))
|
.fill(Color(.tertiarySystemBackground))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
@@ -743,21 +743,47 @@ struct SystemOverviewView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var completedBOMItemCount: Int {
|
private var completedBOMItemCount: Int {
|
||||||
settledLoads.reduce(0) { result, load in
|
let loadCount = settledLoads.reduce(0) { result, load in
|
||||||
let uniqueItems = Set(load.bomCompletedItemIDs)
|
let uniqueItems = Set(load.bomCompletedItemIDs)
|
||||||
let cappedCount = min(uniqueItems.count, Self.bomItemsPerLoad)
|
let cappedCount = min(uniqueItems.count, Self.bomItemsPerLoad)
|
||||||
return result + cappedCount
|
return result + cappedCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let batteryCount = settledBatteries.reduce(0) { result, battery in
|
||||||
|
let uniqueItems = Set(battery.bomCompletedItemIDs)
|
||||||
|
let cappedCount = min(uniqueItems.count, Self.bomItemsPerBattery)
|
||||||
|
return result + cappedCount
|
||||||
|
}
|
||||||
|
|
||||||
|
let chargerCount = settledChargers.reduce(0) { result, charger in
|
||||||
|
let uniqueItems = Set(charger.bomCompletedItemIDs)
|
||||||
|
let cappedCount = min(uniqueItems.count, Self.bomItemsPerCharger)
|
||||||
|
return result + cappedCount
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadCount + batteryCount + chargerCount
|
||||||
}
|
}
|
||||||
|
|
||||||
private var bomItemsCount: Int {
|
private var bomItemsCount: Int {
|
||||||
settledLoads.isEmpty ? 0 : settledLoads.count * Self.bomItemsPerLoad
|
let loadItems = settledLoads.count * Self.bomItemsPerLoad
|
||||||
|
let batteryItems = settledBatteries.count * Self.bomItemsPerBattery
|
||||||
|
let chargerItems = settledChargers.count * Self.bomItemsPerCharger
|
||||||
|
let total = loadItems + batteryItems + chargerItems
|
||||||
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
private var settledLoads: [SavedLoad] {
|
private var settledLoads: [SavedLoad] {
|
||||||
loads.filter { $0.crossSection > 0 && $0.length > 0 }
|
loads.filter { $0.crossSection > 0 && $0.length > 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var settledBatteries: [SavedBattery] {
|
||||||
|
batteries.filter { $0.system == system }
|
||||||
|
}
|
||||||
|
|
||||||
|
private var settledChargers: [SavedCharger] {
|
||||||
|
chargers.filter { $0.system == system }
|
||||||
|
}
|
||||||
|
|
||||||
private func progressBar(progress: CGFloat?, tint: Color) -> some View {
|
private func progressBar(progress: CGFloat?, tint: Color) -> some View {
|
||||||
RoundedRectangle(cornerRadius: 3, style: .continuous)
|
RoundedRectangle(cornerRadius: 3, style: .continuous)
|
||||||
.fill(Color(.tertiarySystemFill))
|
.fill(Color(.tertiarySystemFill))
|
||||||
@@ -1350,6 +1376,8 @@ struct SystemOverviewView: View {
|
|||||||
private static let fallbackGoalHours: Double = 4
|
private static let fallbackGoalHours: Double = 4
|
||||||
|
|
||||||
private static let bomItemsPerLoad = 5
|
private static let bomItemsPerLoad = 5
|
||||||
|
private static let bomItemsPerBattery = 1
|
||||||
|
private static let bomItemsPerCharger = 1
|
||||||
|
|
||||||
private enum BatteryWarning {
|
private enum BatteryWarning {
|
||||||
case voltage(count: Int)
|
case voltage(count: Int)
|
||||||
|
|||||||
@@ -165,26 +165,46 @@ struct SystemBillOfMaterialsView: View {
|
|||||||
if let scale = quantityScale {
|
if let scale = quantityScale {
|
||||||
guard let unit = quantifiedDetailContext else { return nil }
|
guard let unit = quantifiedDetailContext else { return nil }
|
||||||
let value = Double(quantity) / scale
|
let value = Double(quantity) / scale
|
||||||
if let spec = quantifiedDetailSecondaryContext {
|
let format = NSLocalizedString(
|
||||||
let format = NSLocalizedString(
|
"bom.quantity.cable.badge",
|
||||||
"bom.quantity.length.badge.with.spec",
|
comment: "Metric text for total cable length including cross section"
|
||||||
comment: "Badge text for total cable length including cross section"
|
)
|
||||||
)
|
return String(format: format, locale: Locale.current, value, unit, quantifiedDetailSecondaryContext ?? "")
|
||||||
return String(format: format, locale: Locale.current, value, unit, spec)
|
|
||||||
} else {
|
|
||||||
let format = NSLocalizedString(
|
|
||||||
"bom.quantity.length.badge",
|
|
||||||
comment: "Badge text for total cable length"
|
|
||||||
)
|
|
||||||
return String(format: format, locale: Locale.current, value, unit)
|
|
||||||
}
|
|
||||||
} else if quantity > 1 {
|
} else if quantity > 1 {
|
||||||
|
if let fuseRating = quantifiedDetailSecondaryContext, let amps = Int(fuseRating) {
|
||||||
|
let format = NSLocalizedString(
|
||||||
|
"bom.quantity.fuse.badge",
|
||||||
|
comment: "Metric text for consolidated fuses"
|
||||||
|
)
|
||||||
|
return String(format: format, quantity, amps)
|
||||||
|
}
|
||||||
|
if let gauge = quantifiedDetailContext {
|
||||||
|
let format = NSLocalizedString(
|
||||||
|
"bom.quantity.terminal.badge",
|
||||||
|
comment: "Metric text for consolidated terminals"
|
||||||
|
)
|
||||||
|
return String(format: format, quantity, gauge)
|
||||||
|
}
|
||||||
let format = NSLocalizedString(
|
let format = NSLocalizedString(
|
||||||
"bom.quantity.count.badge",
|
"bom.quantity.count.badge",
|
||||||
comment: "Badge text for quantity counts"
|
comment: "Metric text for counted items"
|
||||||
)
|
)
|
||||||
return String(format: format, quantity)
|
return String(format: format, quantity)
|
||||||
}
|
}
|
||||||
|
if let fuseRating = quantifiedDetailSecondaryContext, let amps = Int(fuseRating) {
|
||||||
|
let format = NSLocalizedString(
|
||||||
|
"bom.quantity.fuse.badge",
|
||||||
|
comment: "Metric text for consolidated fuses"
|
||||||
|
)
|
||||||
|
return String(format: format, 1, amps)
|
||||||
|
}
|
||||||
|
if let gauge = quantifiedDetailContext, !gauge.isEmpty {
|
||||||
|
let format = NSLocalizedString(
|
||||||
|
"bom.quantity.single.badge",
|
||||||
|
comment: "Metric text when quantity is one but should be explicit"
|
||||||
|
)
|
||||||
|
return String(format: format, gauge)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,15 +461,6 @@ struct SystemBillOfMaterialsView: View {
|
|||||||
.foregroundColor(.accentColor)
|
.foregroundColor(.accentColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.isPrimaryComponent {
|
|
||||||
Text(String(localized: "component.fallback.name", comment: "Tag label marking an item as the component itself"))
|
|
||||||
.font(.caption2.weight(.medium))
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
.padding(.horizontal, 6)
|
|
||||||
.padding(.vertical, 2)
|
|
||||||
.background(Color.accentColor.opacity(0.15), in: Capsule())
|
|
||||||
}
|
|
||||||
|
|
||||||
if shouldShowDetail(for: item) {
|
if shouldShowDetail(for: item) {
|
||||||
Text(item.detail)
|
Text(item.detail)
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
@@ -647,6 +658,7 @@ struct SystemBillOfMaterialsView: View {
|
|||||||
let lengthQuantity = Int((max(lengthValue, 0) * 100).rounded())
|
let lengthQuantity = Int((max(lengthValue, 0) * 100).rounded())
|
||||||
let redCableMergeKey = "cable.red::\(crossSectionLabel)::\(unitSystem.lengthUnit)"
|
let redCableMergeKey = "cable.red::\(crossSectionLabel)::\(unitSystem.lengthUnit)"
|
||||||
let blackCableMergeKey = "cable.black::\(crossSectionLabel)::\(unitSystem.lengthUnit)"
|
let blackCableMergeKey = "cable.black::\(crossSectionLabel)::\(unitSystem.lengthUnit)"
|
||||||
|
let fuseMergeKey = "fuse::\(fuseRating)"
|
||||||
|
|
||||||
let items: [Item] = [
|
let items: [Item] = [
|
||||||
Item(
|
Item(
|
||||||
@@ -712,9 +724,9 @@ struct SystemBillOfMaterialsView: View {
|
|||||||
components: [component],
|
components: [component],
|
||||||
category: .fuses,
|
category: .fuses,
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
mergeKey: nil,
|
mergeKey: fuseMergeKey,
|
||||||
quantifiedDetailContext: nil,
|
quantifiedDetailContext: nil,
|
||||||
quantifiedDetailSecondaryContext: nil,
|
quantifiedDetailSecondaryContext: String(fuseRating),
|
||||||
quantityScale: nil
|
quantityScale: nil
|
||||||
),
|
),
|
||||||
Item(
|
Item(
|
||||||
@@ -730,7 +742,7 @@ struct SystemBillOfMaterialsView: View {
|
|||||||
category: .accessories,
|
category: .accessories,
|
||||||
quantity: terminalCount,
|
quantity: terminalCount,
|
||||||
mergeKey: "terminals::\(crossSectionLabel.lowercased())",
|
mergeKey: "terminals::\(crossSectionLabel.lowercased())",
|
||||||
quantifiedDetailContext: nil,
|
quantifiedDetailContext: crossSectionLabel,
|
||||||
quantifiedDetailSecondaryContext: nil,
|
quantifiedDetailSecondaryContext: nil,
|
||||||
quantityScale: nil
|
quantityScale: nil
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -167,6 +167,10 @@
|
|||||||
"bom.quantity.count.badge" = "%d×";
|
"bom.quantity.count.badge" = "%d×";
|
||||||
"bom.quantity.length.badge" = "%1$.1f %2$@";
|
"bom.quantity.length.badge" = "%1$.1f %2$@";
|
||||||
"bom.quantity.length.badge.with.spec" = "%1$.1f %2$@ · %3$@";
|
"bom.quantity.length.badge.with.spec" = "%1$.1f %2$@ · %3$@";
|
||||||
|
"bom.quantity.fuse.badge" = "%1$d× · %2$d A";
|
||||||
|
"bom.quantity.terminal.badge" = "%1$d× · %2$@";
|
||||||
|
"bom.quantity.cable.badge" = "%1$.1f %2$@ · %3$@";
|
||||||
|
"bom.quantity.single.badge" = "1× • %@";
|
||||||
"cable.pro.privacy.label" = "Datenschutz";
|
"cable.pro.privacy.label" = "Datenschutz";
|
||||||
"cable.pro.privacy.url" = "https://voltplan.app/de/datenschutz";
|
"cable.pro.privacy.url" = "https://voltplan.app/de/datenschutz";
|
||||||
"cable.pro.terms.label" = "Nutzungsbedingungen";
|
"cable.pro.terms.label" = "Nutzungsbedingungen";
|
||||||
|
|||||||
@@ -37,6 +37,10 @@
|
|||||||
"bom.quantity.count.badge" = "%d×";
|
"bom.quantity.count.badge" = "%d×";
|
||||||
"bom.quantity.length.badge" = "%1$.1f %2$@";
|
"bom.quantity.length.badge" = "%1$.1f %2$@";
|
||||||
"bom.quantity.length.badge.with.spec" = "%1$.1f %2$@ · %3$@";
|
"bom.quantity.length.badge.with.spec" = "%1$.1f %2$@ · %3$@";
|
||||||
|
"bom.quantity.fuse.badge" = "%1$d× · %2$d A";
|
||||||
|
"bom.quantity.terminal.badge" = "%1$d× · %2$@";
|
||||||
|
"bom.quantity.cable.badge" = "%1$.1f %2$@ · %3$@";
|
||||||
|
"bom.quantity.single.badge" = "1× • %@";
|
||||||
"component.fallback.name" = "Componente";
|
"component.fallback.name" = "Componente";
|
||||||
"default.load.library" = "Carga de la biblioteca";
|
"default.load.library" = "Carga de la biblioteca";
|
||||||
"default.load.name" = "Mi carga";
|
"default.load.name" = "Mi carga";
|
||||||
|
|||||||
@@ -37,6 +37,10 @@
|
|||||||
"bom.quantity.count.badge" = "%d×";
|
"bom.quantity.count.badge" = "%d×";
|
||||||
"bom.quantity.length.badge" = "%1$.1f %2$@";
|
"bom.quantity.length.badge" = "%1$.1f %2$@";
|
||||||
"bom.quantity.length.badge.with.spec" = "%1$.1f %2$@ · %3$@";
|
"bom.quantity.length.badge.with.spec" = "%1$.1f %2$@ · %3$@";
|
||||||
|
"bom.quantity.fuse.badge" = "%1$d× · %2$d A";
|
||||||
|
"bom.quantity.terminal.badge" = "%1$d× · %2$@";
|
||||||
|
"bom.quantity.cable.badge" = "%1$.1f %2$@ · %3$@";
|
||||||
|
"bom.quantity.single.badge" = "1× • %@";
|
||||||
"component.fallback.name" = "Composant";
|
"component.fallback.name" = "Composant";
|
||||||
"default.load.library" = "Charge de la bibliothèque";
|
"default.load.library" = "Charge de la bibliothèque";
|
||||||
"default.load.name" = "Ma charge";
|
"default.load.name" = "Ma charge";
|
||||||
|
|||||||
@@ -37,6 +37,10 @@
|
|||||||
"bom.quantity.count.badge" = "%d×";
|
"bom.quantity.count.badge" = "%d×";
|
||||||
"bom.quantity.length.badge" = "%1$.1f %2$@";
|
"bom.quantity.length.badge" = "%1$.1f %2$@";
|
||||||
"bom.quantity.length.badge.with.spec" = "%1$.1f %2$@ · %3$@";
|
"bom.quantity.length.badge.with.spec" = "%1$.1f %2$@ · %3$@";
|
||||||
|
"bom.quantity.fuse.badge" = "%1$d× · %2$d A";
|
||||||
|
"bom.quantity.terminal.badge" = "%1$d× · %2$@";
|
||||||
|
"bom.quantity.cable.badge" = "%1$.1f %2$@ · %3$@";
|
||||||
|
"bom.quantity.single.badge" = "1× • %@";
|
||||||
"component.fallback.name" = "Component";
|
"component.fallback.name" = "Component";
|
||||||
"default.load.library" = "Bibliotheeklast";
|
"default.load.library" = "Bibliotheeklast";
|
||||||
"default.load.name" = "Mijn last";
|
"default.load.name" = "Mijn last";
|
||||||
|
|||||||
Reference in New Issue
Block a user