Skip to content

Commit cdf8a81

Browse files
#1: Display map ornaments on iOS, navigator wheel
To move around the map, a new directional navigator wheel has been introduced. This allows players to jump between map chunks currently. Additionally, for iOS, this counts as an ornament. Ornaments are now properly displayed on the map, and performing a single tap will show or hide them. Other ornaments include the location badge and the dimension picker (only on iOS).
1 parent 112098d commit cdf8a81

File tree

9 files changed

+231
-14
lines changed

9 files changed

+231
-14
lines changed

MCMaps/ContentView.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct ContentView: View {
1818

1919
@State private var viewModel = CartographyMapViewModel()
2020
@State private var displaySidebarSheet = false
21+
@State private var toggleOrnaments = true
2122

2223
var body: some View {
2324
Group {
@@ -28,8 +29,7 @@ struct ContentView: View {
2829
}
2930
#else
3031
AdaptableSidebarSheetView(isPresented: $displaySidebarSheet) {
31-
CartographyMapView(state: viewModel.mapState)
32-
.edgesIgnoringSafeArea(.all)
32+
CartographyOrnamentMap(viewModel: $viewModel, file: $file)
3333
} sheet: {
3434
CartographyMapSidebarSheet(viewModel: $viewModel, file: $file) {
3535
toolbarContent
@@ -78,11 +78,8 @@ struct ContentView: View {
7878
Group {
7979
#if os(iOS)
8080
ToolbarTitleMenu {
81-
WorldDimensionPickerView(selection: $viewModel.worldDimension)
82-
.labelStyle(.titleAndIcon)
83-
.pickerStyle(.palette)
8481
NavigationLink(value: CartographyRoute.editWorld) {
85-
Label("Update World", systemImage: "tree")
82+
Label("Update World", image: "globe.desk.badge.gearshape.fill")
8683
}
8784
}
8885
ToolbarItem(placement: .navigation) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// View+IfModifier.swift
3+
// MCMaps
4+
//
5+
// Created by Marquis Kurt on 23-02-2025.
6+
//
7+
8+
import SwiftUI
9+
10+
extension View {
11+
@ViewBuilder
12+
func `if`<Content: View>(_ condition: Bool, apply transform: (Self) -> Content) -> some View {
13+
if condition {
14+
transform(self)
15+
} else {
16+
self
17+
}
18+
}
19+
}

MCMaps/Resources/Alidade.docc/Alidade.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,16 @@ relevant parts of the app.
4747

4848
### Maps
4949

50+
- ``CartographyOrnamentMap``
5051
- ``CartographyMapView``
5152
- ``CartographyMapViewState``
5253

54+
55+
### Map Ornaments
56+
57+
- ``LocationBadge``
58+
- ``DirectionNavigator``
59+
5360
### Editor Forms
5461

5562
- ``MapCreatorForm``
@@ -58,7 +65,6 @@ relevant parts of the app.
5865

5966
### Badges and Communication
6067

61-
- ``LocationBadge``
6268
- ``CartographyNamedLocationView``
6369

6470
### Pickers
@@ -73,3 +79,7 @@ relevant parts of the app.
7379
- ``RecentLocationsListSection``
7480
- ``PinnedLibrarySection``
7581
- ``SearchedStructuresSection``
82+
83+
### View Modifiers
84+
85+
- ``ZoomableModifier``

MCMaps/Resources/Localizable.xcstrings

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@
9494
},
9595
"Go Here" : {
9696

97+
},
98+
"Go North" : {
99+
97100
},
98101
"Go To..." : {
99102

MCMaps/View Models/CartographyMapViewModel.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ import SwiftUI
1414
@Observable
1515
@MainActor
1616
class CartographyMapViewModel {
17+
/// A enumeration of the cardinal directions.
18+
enum CardinalDirection {
19+
case north, south, east, west
20+
}
21+
1722
/// The current route the app is handling.
1823
///
1924
/// On iOS and iPadOS, the views handled by route should appear in the adaptable sidebar sheet. On macOS, these
@@ -103,6 +108,25 @@ class CartographyMapViewModel {
103108
Task { await refreshMap(for: file) }
104109
}
105110

111+
/// Jump in a specified cardinal direction, reloading the map in the current process.
112+
/// - Parameter direction: The direction to jump towards.
113+
/// - Parameter file: The file to load the map data from.
114+
func go(inDirection direction: CardinalDirection, relativeToFile file: CartographyMapFile) {
115+
var newPosition = worldRange.position
116+
switch direction {
117+
case .north:
118+
newPosition.z -= worldRange.scale.z
119+
case .south:
120+
newPosition.z += worldRange.scale.z
121+
case .east:
122+
newPosition.x += worldRange.scale.x
123+
case .west:
124+
newPosition.x -= worldRange.scale.x
125+
}
126+
worldRange.position = newPosition
127+
Task { await refreshMap(for: file) }
128+
}
129+
106130
/// Submits the player-made changes to the current file and reloads the map.
107131
/// - Parameter file: The file to commit the changes to.
108132
func submitWorldChanges(to file: CartographyMapFile) {
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//
2+
// CartographyOrnamentMap.swift
3+
// MCMaps
4+
//
5+
// Created by Marquis Kurt on 23-02-2025.
6+
//
7+
8+
import SwiftUI
9+
10+
private struct MapOrnament<Content: View>: View {
11+
var alignment: Alignment
12+
var content: () -> Content
13+
14+
var body: some View {
15+
Group {
16+
content()
17+
}
18+
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: alignment)
19+
}
20+
}
21+
22+
/// A map view with various ornaments placed on top.
23+
///
24+
/// The ornament map displays the regular map while having various ornaments on top, such as the location badge,
25+
/// direction navigator wheel, and dimension picker. On iOS and iPadOS, tapping the map will show or hide these
26+
/// ornaments.
27+
struct CartographyOrnamentMap: View {
28+
private enum Constants {
29+
#if os(macOS)
30+
static let locationBadgePlacement = Alignment.bottomLeading
31+
#else
32+
static let locationBadgePlacement = Alignment.topTrailing
33+
#endif
34+
35+
static let navigatorWheelPlacement = Alignment.bottomTrailing
36+
}
37+
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
38+
39+
/// The view model the map will read from/write to.
40+
@Binding var viewModel: CartographyMapViewModel
41+
42+
/// The file that the map will read from/write to.
43+
@Binding var file: CartographyMapFile
44+
45+
@State private var displayOrnaments = true
46+
47+
var body: some View {
48+
ZStack {
49+
MapOrnament(alignment: Constants.navigatorWheelPlacement) {
50+
DirectionNavigator(viewModel: viewModel, file: file)
51+
}
52+
.padding(.trailing, 8)
53+
.padding(.bottom, horizontalSizeClass == .compact ? 116 : 8)
54+
.if(!displayOrnaments) { view in
55+
view.hidden()
56+
}
57+
MapOrnament(alignment: Constants.locationBadgePlacement) {
58+
VStack(alignment: .trailing) {
59+
LocationBadge(location: viewModel.worldRange.position)
60+
#if os(iOS)
61+
Menu {
62+
WorldDimensionPickerView(selection: $viewModel.worldDimension)
63+
.pickerStyle(.inline)
64+
} label: {
65+
Label("Dimension", systemImage: "map")
66+
}
67+
.labelStyle(.iconOnly)
68+
.padding()
69+
.foregroundStyle(.primary)
70+
.background(.thinMaterial)
71+
.clipped()
72+
.clipShape(.rect(cornerRadius: 8))
73+
.padding(.trailing, 6)
74+
#endif
75+
}
76+
}
77+
.padding(.trailing, 8)
78+
.if(!displayOrnaments) { view in
79+
view.hidden()
80+
}
81+
}
82+
.animation(.default, value: viewModel.mapState)
83+
.animation(.spring(duration: 0.3), value: displayOrnaments)
84+
.background(
85+
CartographyMapView(state: viewModel.mapState)
86+
.animation(.interpolatingSpring, value: viewModel.mapState)
87+
.edgesIgnoringSafeArea(.all)
88+
.onTapGesture {
89+
#if os(iOS)
90+
withAnimation(.spring(duration: 0.3)) {
91+
displayOrnaments.toggle()
92+
}
93+
#endif
94+
}
95+
)
96+
}
97+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// DirectionNavigator.swift
3+
// MCMaps
4+
//
5+
// Created by Marquis Kurt on 23-02-2025.
6+
//
7+
8+
import SwiftUI
9+
10+
/// A view that lets players jump between map segments in any given cardinal direction.
11+
///
12+
/// This is typically used as an ornament on the ``CartographyOrnamentMap`` to let players move between "map chunks"
13+
/// in any given one direction so that they can move about the world. The control is automatically resized based on the
14+
/// target platform.
15+
struct DirectionNavigator: View {
16+
private enum Constants {
17+
#if os(macOS)
18+
static let verticalStackSpacing = 4.0
19+
static let horizontalStackSpacing = 24.0
20+
static let innerPadding = 8.0
21+
#else
22+
static let verticalStackSpacing = 24.0
23+
static let horizontalStackSpacing = 64.0
24+
static let innerPadding = 24.0
25+
#endif
26+
}
27+
28+
/// The view model the navigator will read from.
29+
var viewModel: CartographyMapViewModel
30+
31+
/// The file the navigator will read from.
32+
var file: CartographyMapFile
33+
34+
var body: some View {
35+
Group {
36+
VStack(spacing: Constants.verticalStackSpacing) {
37+
Button {
38+
viewModel.go(inDirection: .north, relativeToFile: file)
39+
} label: {
40+
Label("Go North", systemImage: "chevron.up")
41+
.padding(4)
42+
}
43+
HStack(spacing: Constants.horizontalStackSpacing) {
44+
Button {
45+
viewModel.go(inDirection: .west, relativeToFile: file)
46+
} label: {
47+
Label("Go North", systemImage: "chevron.left")
48+
.padding(4)
49+
}
50+
Button {
51+
viewModel.go(inDirection: .east, relativeToFile: file)
52+
} label: {
53+
Label("Go North", systemImage: "chevron.right")
54+
.padding(4)
55+
}
56+
}
57+
Button {
58+
viewModel.go(inDirection: .south, relativeToFile: file)
59+
} label: {
60+
Label("Go North", systemImage: "chevron.down")
61+
.padding(4)
62+
}
63+
}
64+
.labelStyle(.iconOnly)
65+
.buttonStyle(.plain)
66+
}
67+
.padding(Constants.innerPadding)
68+
.background(.thinMaterial)
69+
.clipped()
70+
.clipShape(Circle())
71+
.padding(8)
72+
}
73+
}
File renamed without changes.

MCMaps/Views/CartographyMapSplitView.swift renamed to MCMaps/Views/Navigation/CartographyMapSplitView.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,7 @@ struct CartographyMapSplitView: View {
3131
NavigationSplitView {
3232
CartographyMapSidebar(viewModel: $viewModel, file: $file)
3333
} detail: {
34-
Group {
35-
LocationBadge(location: viewModel.worldRange.position)
36-
}
37-
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomLeading)
38-
.background(
39-
CartographyMapView(state: viewModel.mapState)
40-
)
34+
CartographyOrnamentMap(viewModel: $viewModel, file: $file)
4135
.inspector(isPresented: viewModel.displayCurrentRouteAsInspector) {
4236
Group {
4337
switch viewModel.currentRoute {

0 commit comments

Comments
 (0)