automated screenshots with fastlane
@@ -40,7 +40,7 @@
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "boat-ob-inv.png",
|
||||
"filename" : "boat-dark.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
||||
BIN
Cable/Assets.xcassets/boat-onboarding.imageset/boat-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 310 KiB |
@@ -40,7 +40,7 @@
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "cabin-ob-inv.png",
|
||||
"filename" : "cabin-dark.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
||||
BIN
Cable/Assets.xcassets/cabin-onboarding.imageset/cabin-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 391 KiB |
52
Cable/Assets.xcassets/charger-onboarding.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "charger-light.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "charger-dark.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Cable/Assets.xcassets/charger-onboarding.imageset/charger-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
Cable/Assets.xcassets/charger-onboarding.imageset/charger-light.png
vendored
Normal file
|
After Width: | Height: | Size: 79 KiB |
@@ -1,7 +1,16 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "coffee-ob.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
@@ -10,6 +19,28 @@
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "coffee-light.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "coffee-dark.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
||||
BIN
Cable/Assets.xcassets/coffee-onboarding.imageset/coffee-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
Cable/Assets.xcassets/coffee-onboarding.imageset/coffee-light.png
vendored
Normal file
|
After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 331 KiB |
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "fridge-ob.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 230 KiB |
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "light-ob.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 306 KiB |
52
Cable/Assets.xcassets/router-onboarding.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "router-light.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "router-dark.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Cable/Assets.xcassets/router-onboarding.imageset/router-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
Cable/Assets.xcassets/router-onboarding.imageset/router-light.png
vendored
Normal file
|
After Width: | Height: | Size: 74 KiB |
@@ -40,7 +40,7 @@
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "van-ob-inv.png",
|
||||
"filename" : "bus-dark.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
||||
BIN
Cable/Assets.xcassets/van-onboarding.imageset/bus-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 414 KiB |
@@ -101,29 +101,55 @@ final class ComponentLibraryViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
private func fetchComponents() async throws -> [ComponentLibraryItem] {
|
||||
var components = URLComponents(url: baseURL.appendingPathComponent("api/collections/components/records"), resolvingAgainstBaseURL: false)
|
||||
components?.queryItems = [
|
||||
URLQueryItem(name: "filter", value: "(type='load')"),
|
||||
URLQueryItem(name: "sort", value: "+name"),
|
||||
URLQueryItem(name: "fields", value: "id,collectionId,name,icon,voltage_in,voltage_out,watt")
|
||||
]
|
||||
let perPage = 200
|
||||
var page = 1
|
||||
var allRecords: [PocketBaseRecord] = []
|
||||
|
||||
guard let url = components?.url else {
|
||||
throw URLError(.badURL)
|
||||
while true {
|
||||
var components = URLComponents(
|
||||
url: baseURL.appendingPathComponent("api/collections/components/records"),
|
||||
resolvingAgainstBaseURL: false
|
||||
)
|
||||
components?.queryItems = [
|
||||
URLQueryItem(name: "filter", value: "(type='load')"),
|
||||
URLQueryItem(name: "sort", value: "+name"),
|
||||
URLQueryItem(name: "fields", value: "id,collectionId,name,icon,voltage_in,voltage_out,watt"),
|
||||
URLQueryItem(name: "page", value: "\(page)"),
|
||||
URLQueryItem(name: "perPage", value: "\(perPage)")
|
||||
]
|
||||
|
||||
guard let url = components?.url else {
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.cachePolicy = .reloadIgnoringLocalCacheData
|
||||
|
||||
let (data, response) = try await urlSession.data(for: request)
|
||||
|
||||
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
|
||||
let decoded = try JSONDecoder().decode(PocketBaseResponse.self, from: data)
|
||||
allRecords.append(contentsOf: decoded.items)
|
||||
|
||||
let isLastPage: Bool
|
||||
if let totalPages = decoded.totalPages, totalPages > 0 {
|
||||
isLastPage = page >= totalPages
|
||||
} else {
|
||||
isLastPage = decoded.items.count < perPage
|
||||
}
|
||||
|
||||
if isLastPage {
|
||||
break
|
||||
}
|
||||
|
||||
page += 1
|
||||
}
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.cachePolicy = .reloadIgnoringLocalCacheData
|
||||
|
||||
let (data, response) = try await urlSession.data(for: request)
|
||||
|
||||
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
|
||||
let decoded = try JSONDecoder().decode(PocketBaseResponse.self, from: data)
|
||||
let affiliateLinksByComponent = try await fetchAffiliateLinks(for: decoded.items.map(\.id))
|
||||
let mappedItems = decoded.items.map { record in
|
||||
let affiliateLinksByComponent = try await fetchAffiliateLinks(for: allRecords.map(\.id))
|
||||
let mappedItems = allRecords.map { record in
|
||||
ComponentLibraryItem(
|
||||
id: record.id,
|
||||
name: record.name,
|
||||
@@ -264,6 +290,9 @@ final class ComponentLibraryViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
private struct PocketBaseResponse: Decodable {
|
||||
let page: Int?
|
||||
let perPage: Int?
|
||||
let totalPages: Int?
|
||||
let items: [PocketBaseRecord]
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ struct ComponentsOnboardingView: View {
|
||||
let onBrowse: () -> Void
|
||||
|
||||
private let imageNames = [
|
||||
"fridge-onboarding",
|
||||
"router-onboarding",
|
||||
"coffee-onboarding",
|
||||
"light-onboarding"
|
||||
"charger-onboarding"
|
||||
]
|
||||
|
||||
private let timer = Timer.publish(every: 8, on: .main, in: .common).autoconnect()
|
||||
@@ -57,6 +57,7 @@ struct ComponentsOnboardingView: View {
|
||||
.background(Color.blue)
|
||||
.cornerRadius(12)
|
||||
}
|
||||
.accessibilityIdentifier("create-component-button")
|
||||
.buttonStyle(.plain)
|
||||
|
||||
Button(action: onBrowse) {
|
||||
|
||||
@@ -81,6 +81,7 @@ struct SystemsOnboardingView: View {
|
||||
.background(Color.blue)
|
||||
.cornerRadius(12)
|
||||
}
|
||||
.accessibilityIdentifier("create-system-button")
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
.padding(.horizontal, 24)
|
||||
|
||||