Standard Loadout Upgrade View
Standard Loadout Upgrade View
The upgrade view for a standard loadout should look like:

- Which is represented by a Swift UI view
- The body consists of Text and Symbol segments

- The upgrade text is taken from the Blank Signature sides.ability node in upgrades/sensor.json
findDelimitedSubstrings(input:) -> [String]returns an array of the substrings. This function is a member of UpgradeTextView class (Views/UpgradeView.swift)
| Index | Value |
|---|---|
| 0 | “While defending, if you are “ |
| 1 | “[Charge]” |
| 2 | ” to change 1 “ |
| 3 | “[Focus]” |
| 4 | ” result to an “ |
| 5 | “[Evade]” |
| 6 | ” result.” |
createSubstringArray(input:) -> [SubstringType]converts the string array into a[SubstringType]array
|Index|Value| |-|-| |0|SubstringType.Text(“While defending, if you are “)| |1|SubstringType.Symbol(“[Charge]”)| more…
- Merge any contiguous substrings, if needed.
For the cases where the string is “ perform a [1 [Straight]] “ in the sides.ability node of the upgrade.
mergeSameSubstringTypes(_ input: [SubstringType]) -> [SubstringType]
- Build a SwiftUI view from the
[SubstringType]array.
func buildViews(_ input: [SubstringType]) -> some View {
func buildView(_ type: SubstringType) -> Text {
switch(type) {
case .text(let val):
return Text(val)
case .symbol(let val):
return Text(getSymbol(val))
.font(.custom("xwing-miniatures", size: 18))
}
}
return VStack(alignment: .center) {
input.reduce(Text(""), { $0 + buildView($1) } )
}
}
getSymbol(val:)returns a character from the xwing-miniatures font that corresponds to the associated type of the symbol in the[SubstringType]array. (SubstringType.Symbol("[Charge]")corresponds to thegcharacter in the xwing-miniatures font)
flowchart TD
A[Redux_ShipView.body.content] --> B[Redux_ShipView.imageOverlayView]
B --> C[Redux_ShipView.imageOverlayView.upgradeImageOverlay]
C --> D[Redux_ShipView.imageOverlayView.upgradeImageOverlay.upgradeCardImage]
D --> E[UpgradeCardFlipView]
D -->|selectedUpgrade.upgrade.isStandardLoadoutUpgrade| F[UpgradeTextView]
classDiagram
class Redux_ShipView {
var viewModel: Redux_ShipViewModel
"@State var showImageOverlay: Bool = false"
"@State var selectedUpgrade: UpgradeView.UpgradeViewModel? = nil"
}
class UpgradesView {
let upgrades: [Upgrade]
@Binding var showImageOverlay: Bool
"@Binding var selectedUpgrade: UpgradeView.UpgradeViewModel?"
}
The UpgradesView is built, passing in the [Upgrades] and any @State variables which are used as @Binding variables in UpgradesView.
Redux_ShipView.body.content.footer:
var footer: some View {
UpgradesView(upgrades: viewModel.shipPilot.upgrades,
showImageOverlay: $showImageOverlay,
imageOverlayUrl: $imageOverlayUrl,
imageOverlayUrlBack: $imageOverlayUrlBack,
selectedUpgrade: $selectedUpgrade)
.environmentObject(viewModel)
}
UpgradesView.swift:
ForEach(upgrades) {
UpgradeView(viewModel: UpgradeView.UpgradeViewModel(upgrade: $0))
{ upgradeViewModel in
self.showImageOverlay = true
self.imageOverlayUrl = upgradeViewModel.imageUrl
self.imageOverlayUrlBack = upgradeViewModel.imageUrlBack
self.selectedUpgrade = upgradeViewModel
}
.environmentObject(viewModel)
}
The closure passed into UpgradeView is executed when an upgrade button is tapped.
- The
showImageOverlayis set to true when the upgrade button is tapped - The
selectedUpgradeis set when the upgrade button in the footer of the ship view is tapped. It is set to theUpgradeView.UpgradeViewModelwhich is initialized from theUpgrade
The body of Redux_ShipView adds the imageOverlayView as an overlay:
Redux_ShipView.body:
return VStack(alignment: .leading) {
headerView
bodyContent
footer
}
.padding()
.overlay(imageOverlayView)
The showImageOverlay toggles whether the upgradeImageOverlay or the defaultView is displayed:
Redux_ShipView.imageOverlayView:
if (self.showImageOverlay == true) {
return AnyView(upgradeImageOverlay)
} else {
return defaultView
}
The upgradeImageOverlay references the upgradeCardImage which displays the UpgradeCardFlipView:
if (self.imageOverlayUrlBack != "") {
guard let selectedUpgrade = self.selectedUpgrade else { return emptyView }
guard let upgradeState = getUpgradeStateData(upgrade: selectedUpgrade.upgrade) else { return emptyView }
// if not standard loadout upgrade
ret =
UpgradeCardFlipView(
side: (upgradeState.selected_side == 0) ? false : true,
frontUrl: self.imageOverlayUrl,
backUrl: self.imageOverlayUrlBack,
viewModel: self.viewModel) { side in
self.viewModel.update(
type: PilotStatePropertyType.selectedSide(upgradeState,
side), active: -1, inactive: -1
)
}.eraseToAnyView()
// if standard loadout upgrade
// ret = UpgradeTextView
}
flowchart TD
A[Redux_ShipView.body.content.footer] -->|Upgrades, selectedUpgrade| B[UpgradesView]
B -->|UpgradeViewModel| C[UpgradeView]
C -->|selectedUpgrade, showImageOverlay| D[Redux_ShipView.imageOverlayView]
D --> E[upgradeImageOverlay]
E --> F[UpgradeCardFlipView]
E -->|selectedUpgrade.isStandardLoadout| G[UpgradeTextView]
Tasks
- Add
var isStandardLoadout: Bool = falsetoUpgrade - Set
isStandardLoadoutwhen building theRedux_ShipViewModel.shipPilot.upgradesthat is injected intoRedux_ShipViewfromContentView.Redux_buildView(). which is triggered from tapping a ship card on the squad view.
ContentView.swift
func Redux_buildView(type: ViewType) -> AnyView {
case .shipViewNew(let shipPilot, let squad):
return buildShipView(shipPilot: shipPilot, squad: squad)
}
func buildShipView(shipPilot: ShipPilot, squad: Squad) -> AnyView {
let viewModel = Redux_ShipViewModel(moc: self.moc,
shipPilot: shipPilot,
squad: squad,
pilotStateService: self.diContainer.pilotStateService,
store: store)
return AnyView(Redux_ShipView(viewModel: viewModel)
.environmentObject(self)
)
}
flowchart TD
A[Ship card tap on SquadView] -->|"ViewType.shipViewNew(shipPilot,squad)"| B["buildShipView(shipPilot, squad)"]
B -->|"shipPilot, squad"| C[Redux_ShipViewModel]
C -->|"viewModel"| D[Redux_ShipView]
flowchart TD
Y["Redux_SquadViewNewViewModel.loadShips(squad, squadData)"] --> W["squadReducer.getShips(squad,data)"]
W -->|squad, SquadData| C["SquadService.getShips"]
Z["Redux_SquadView.loadShips"] --> A
V["Redux_SquadView.content.onAppear"] --> Z
A["factionReducer(.getShips(SquadData))"] -->|SquadData| C["SquadService.getShips"]
B["squadReducer(.flipDialFix)"] -->|squad, SquadData| C["SquadService.getShips"]
C -->|squad, squadPilot, pilotState| D["CacheService.getShip"]
D -->|squad, squadPilot, pilotState| E["CacheService.getShipV1"]
E -->|inout Ship| F["CacheService.getShipV1.getPilot"]
F --> G["CacheService.getShipV1.getPilot.getUpgradesFromCache"]
G --> H["CacheService.getShipV1.getPilot.getUpgradesFromCache.getUpgrade(key:)"]
H --> I["UpgradeUtility.getUpgrades(upgradeCategory)"]