mirror of
https://github.com/ivanvorobei/SwiftUI.git
synced 2026-04-11 03:27:12 +02:00
Minimum changes for Xcode 11 beta 5
This commit is contained in:
@@ -89,7 +89,7 @@ struct BlockView : View {
|
|||||||
.foregroundColor(colorPair.1)
|
.foregroundColor(colorPair.1)
|
||||||
.id(numberText)
|
.id(numberText)
|
||||||
.transition(AnyTransition.scale(scale: 0.5, anchor: .center).combined(with: .opacity))
|
.transition(AnyTransition.scale(scale: 0.5, anchor: .center).combined(with: .opacity))
|
||||||
.animation(.fluidSpring())
|
// .animation(.fluidSpring())
|
||||||
}
|
}
|
||||||
.clipped()
|
.clipped()
|
||||||
.cornerRadius(6)
|
.cornerRadius(6)
|
||||||
@@ -104,7 +104,7 @@ struct BlockView_Previews : PreviewProvider {
|
|||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
Group {
|
Group {
|
||||||
ForEach((1...11).map { Int(pow(2, Double($0))) }) { i in
|
ForEach((1...11).map { Int(pow(2.0, Double($0))) }, id: \.self) { i in
|
||||||
BlockView(number: i)
|
BlockView(number: i)
|
||||||
.previewLayout(.sizeThatFits)
|
.previewLayout(.sizeThatFits)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ struct HikeDetail: View {
|
|||||||
.frame(height: 200, alignment: .center)
|
.frame(height: 200, alignment: .center)
|
||||||
|
|
||||||
HStack(spacing: 25) {
|
HStack(spacing: 25) {
|
||||||
ForEach(buttons.identified(by: \.0)) { value in
|
ForEach(buttons, id: \.0) { value in
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.dataToShow = value.1
|
self.dataToShow = value.1
|
||||||
}) {
|
}) {
|
||||||
Text(verbatim: value.0)
|
Text(verbatim: value.0)
|
||||||
.font(.system(size: 15))
|
.font(.system(size: 15))
|
||||||
.color(value.1 == self.dataToShow
|
.foregroundColor(value.1 == self.dataToShow
|
||||||
? Color.gray
|
? Color.gray
|
||||||
: Color.accentColor)
|
: Color.accentColor)
|
||||||
.animation(nil)
|
.animation(nil)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ final class ImageStore {
|
|||||||
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
||||||
images.values[index][size] = sizedImage
|
images.values[index][size] = sizedImage
|
||||||
|
|
||||||
return Image(sizedImage, scale: Length(ImageStore.scale), label: Text(verbatim: name))
|
return Image(sizedImage, scale: CGFloat(ImageStore.scale), label: Text(verbatim: name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
||||||
|
|||||||
@@ -9,20 +9,20 @@ import SwiftUI
|
|||||||
|
|
||||||
struct GraphCapsule: View {
|
struct GraphCapsule: View {
|
||||||
var index: Int
|
var index: Int
|
||||||
var height: Length
|
var height: CGFloat
|
||||||
var range: Range<Double>
|
var range: Range<Double>
|
||||||
var overallRange: Range<Double>
|
var overallRange: Range<Double>
|
||||||
|
|
||||||
var heightRatio: Length {
|
var heightRatio: CGFloat {
|
||||||
max(Length(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
|
max(CGFloat(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
|
||||||
}
|
}
|
||||||
|
|
||||||
var offsetRatio: Length {
|
var offsetRatio: CGFloat {
|
||||||
Length((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
|
CGFloat((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
|
||||||
}
|
}
|
||||||
|
|
||||||
var animation: Animation {
|
var animation: Animation {
|
||||||
Animation.spring(initialVelocity: 5)
|
Animation.spring()
|
||||||
.speed(2)
|
.speed(2)
|
||||||
.delay(0.03 * Double(index))
|
.delay(0.03 * Double(index))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ struct HikeGraph: View {
|
|||||||
let data = hike.observations
|
let data = hike.observations
|
||||||
let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
|
let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
|
||||||
let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
|
let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
|
||||||
let heightRatio = 1 - Length(maxMagnitude / magnitude(of: overallRange))
|
let heightRatio = 1 - CGFloat(maxMagnitude / magnitude(of: overallRange))
|
||||||
|
|
||||||
return GeometryReader { proxy in
|
return GeometryReader { proxy in
|
||||||
HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
|
HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ final class ImageStore {
|
|||||||
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
||||||
images.values[index][size] = sizedImage
|
images.values[index][size] = sizedImage
|
||||||
|
|
||||||
return Image(sizedImage, scale: Length(ImageStore.scale), label: Text(verbatim: name))
|
return Image(sizedImage, scale: CGFloat(ImageStore.scale), label: Text(verbatim: name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ struct SearchUserBar: View {
|
|||||||
ZStack {
|
ZStack {
|
||||||
HStack {
|
HStack {
|
||||||
TextField(
|
TextField(
|
||||||
$text,
|
"Search User", text: $text
|
||||||
placeholder: Text("Search User")
|
|
||||||
.foregroundColor(Color.gray)
|
|
||||||
)
|
)
|
||||||
.padding([.leading, .trailing], 8)
|
.padding([.leading, .trailing], 8)
|
||||||
.frame(height: 32)
|
.frame(height: 32)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ final class SearchUserViewModel: BindableObject {
|
|||||||
.replaceError(with: nil)
|
.replaceError(with: nil)
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.receive(subscriber: Subscribers.Sink<UIImage?, Never> { [weak self] image in
|
.receive(subscriber: Subscribers.Sink<UIImage?, Never>(receiveCompletion: {_ in}) { [weak self] image in
|
||||||
self?.userImages[user] = image
|
self?.userImages[user] = image
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ A view showing featured landmarks above a list of all of the landmarks.
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct CategoryHome: View {
|
struct CategoryHome: View {
|
||||||
|
@State private var isProfilePresented = false
|
||||||
|
|
||||||
var categories: [String: [Landmark]] {
|
var categories: [String: [Landmark]] {
|
||||||
.init(
|
.init(
|
||||||
grouping: landmarkData,
|
grouping: landmarkData,
|
||||||
@@ -39,13 +41,16 @@ struct CategoryHome: View {
|
|||||||
}
|
}
|
||||||
.navigationBarTitle(Text("Featured"))
|
.navigationBarTitle(Text("Featured"))
|
||||||
.navigationBarItems(trailing:
|
.navigationBarItems(trailing:
|
||||||
PresentationLink(destination: Text("User Profile")) {
|
Button(action: {
|
||||||
|
self.isProfilePresented = true
|
||||||
|
}) {
|
||||||
Image(systemName: "person.crop.circle")
|
Image(systemName: "person.crop.circle")
|
||||||
.imageScale(.large)
|
.imageScale(.large)
|
||||||
.accessibility(label: Text("User Profile"))
|
.accessibility(label: Text("User Profile"))
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
)
|
).sheet(isPresented: $isProfilePresented,
|
||||||
|
content: { Text("User Profile") })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ final class ImageStore {
|
|||||||
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
||||||
images.values[index][size] = sizedImage
|
images.values[index][size] = sizedImage
|
||||||
|
|
||||||
return Image(sizedImage, scale: Length(ImageStore.scale), label: Text(verbatim: name))
|
return Image(sizedImage, scale: CGFloat(ImageStore.scale), label: Text(verbatim: name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
||||||
|
|||||||
@@ -9,20 +9,20 @@ import SwiftUI
|
|||||||
|
|
||||||
struct GraphCapsule: View {
|
struct GraphCapsule: View {
|
||||||
var index: Int
|
var index: Int
|
||||||
var height: Length
|
var height: CGFloat
|
||||||
var range: Range<Double>
|
var range: Range<Double>
|
||||||
var overallRange: Range<Double>
|
var overallRange: Range<Double>
|
||||||
|
|
||||||
var heightRatio: Length {
|
var heightRatio: CGFloat {
|
||||||
max(Length(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
|
max(CGFloat(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
|
||||||
}
|
}
|
||||||
|
|
||||||
var offsetRatio: Length {
|
var offsetRatio: CGFloat {
|
||||||
Length((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
|
CGFloat((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
|
||||||
}
|
}
|
||||||
|
|
||||||
var animation: Animation {
|
var animation: Animation {
|
||||||
Animation.spring(initialVelocity: 5)
|
Animation.spring()
|
||||||
.speed(2)
|
.speed(2)
|
||||||
.delay(0.03 * Double(index))
|
.delay(0.03 * Double(index))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ struct HikeGraph: View {
|
|||||||
let data = hike.observations
|
let data = hike.observations
|
||||||
let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
|
let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
|
||||||
let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
|
let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
|
||||||
let heightRatio = 1 - Length(maxMagnitude / magnitude(of: overallRange))
|
let heightRatio = 1 - CGFloat(maxMagnitude / magnitude(of: overallRange))
|
||||||
|
|
||||||
return GeometryReader { proxy in
|
return GeometryReader { proxy in
|
||||||
HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
|
HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ struct ConverterView : View {
|
|||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
// Amount and conversion
|
// Amount and conversion
|
||||||
TextField($baseAmount, placeholder: Text("1.0"), onCommit: {
|
TextField("1.0", text: $baseAmount, onCommit: {
|
||||||
// TODO: update all currencies on the following list
|
// TODO: update all currencies on the following list
|
||||||
}).foregroundColor(.white)
|
}).foregroundColor(.white)
|
||||||
.background(
|
.background(
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ final class ImageStore {
|
|||||||
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
||||||
images.values[index][size] = sizedImage
|
images.values[index][size] = sizedImage
|
||||||
|
|
||||||
return Image(sizedImage, scale: Length(ImageStore.scale), label: Text(verbatim: name))
|
return Image(sizedImage, scale: CGFloat(ImageStore.scale), label: Text(verbatim: name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ struct TaskEditView: View {
|
|||||||
let inset = EdgeInsets(top: -8, leading: -10, bottom: -7, trailing: -10)
|
let inset = EdgeInsets(top: -8, leading: -10, bottom: -7, trailing: -10)
|
||||||
return VStack(alignment: .leading, spacing: 0) {
|
return VStack(alignment: .leading, spacing: 0) {
|
||||||
TextField(
|
TextField(
|
||||||
self.draftTitle.binding,
|
"Enter New Title...", text: self.draftTitle.binding,
|
||||||
placeholder: Text("Enter New Title..."),
|
|
||||||
onEditingChanged: { _ in self.updateTask() },
|
onEditingChanged: { _ in self.updateTask() },
|
||||||
onCommit: {}
|
onCommit: {}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ struct TaskListView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
List {
|
List {
|
||||||
TextField($draftTitle, placeholder: Text("Create a New Task..."), onCommit: self.createTask)
|
TextField("Create a New Task...", text: $draftTitle, onCommit: self.createTask)
|
||||||
ForEach(self.userData.tasks) { task in
|
ForEach(self.userData.tasks) { task in
|
||||||
TaskItemView(task: task, isEditing: self.$isEditing)
|
TaskItemView(task: task, isEditing: self.$isEditing)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1100"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "EDDF069D22A6C61C00B23D44"
|
||||||
|
BuildableName = "GitHubSearchWithSwiftUI.app"
|
||||||
|
BlueprintName = "GitHubSearchWithSwiftUI"
|
||||||
|
ReferencedContainer = "container:GitHubSearchWithSwiftUI.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<TestPlans>
|
||||||
|
</TestPlans>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "EDDF069D22A6C61C00B23D44"
|
||||||
|
BuildableName = "GitHubSearchWithSwiftUI.app"
|
||||||
|
BlueprintName = "GitHubSearchWithSwiftUI"
|
||||||
|
ReferencedContainer = "container:GitHubSearchWithSwiftUI.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "EDDF069D22A6C61C00B23D44"
|
||||||
|
BuildableName = "GitHubSearchWithSwiftUI.app"
|
||||||
|
BlueprintName = "GitHubSearchWithSwiftUI"
|
||||||
|
ReferencedContainer = "container:GitHubSearchWithSwiftUI.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -20,8 +20,7 @@ struct RepositoryListView : View {
|
|||||||
VStack {
|
VStack {
|
||||||
HStack {
|
HStack {
|
||||||
|
|
||||||
TextField($viewModel.text,
|
TextField("Search repositories...", text: $viewModel.text,
|
||||||
placeholder: Text("Search reposipories..."),
|
|
||||||
onCommit: { self.viewModel.search() })
|
onCommit: { self.viewModel.search() })
|
||||||
.frame(height: 40)
|
.frame(height: 40)
|
||||||
.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8))
|
.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8))
|
||||||
@@ -43,7 +42,7 @@ struct RepositoryListView : View {
|
|||||||
.lineLimit(nil)
|
.lineLimit(nil)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
|
|
||||||
ForEach(viewModel.repositories.identified(by: \.id)) { repository in
|
ForEach(viewModel.repositories, id: \.id) { repository in
|
||||||
|
|
||||||
NavigationLink(destination:
|
NavigationLink(destination:
|
||||||
WebView(url: repository.htmlUrl)
|
WebView(url: repository.htmlUrl)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ final class ImageStore {
|
|||||||
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
||||||
images.values[index][size] = sizedImage
|
images.values[index][size] = sizedImage
|
||||||
|
|
||||||
return Image(sizedImage, scale: Length(ImageStore.scale), label: Text(verbatim: name))
|
return Image(sizedImage, scale: CGFloat(ImageStore.scale), label: Text(verbatim: name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import AVKit
|
|||||||
import CoreLocation
|
import CoreLocation
|
||||||
|
|
||||||
struct ContentView : View {
|
struct ContentView : View {
|
||||||
|
@State private var isCameraPresented = false
|
||||||
var instaPhotos: [InstaPhoto]
|
var instaPhotos: [InstaPhoto]
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -19,7 +20,17 @@ struct ContentView : View {
|
|||||||
ForEach(instaPhotos, id: \.id) {
|
ForEach(instaPhotos, id: \.id) {
|
||||||
ImageCell(photo: $0)
|
ImageCell(photo: $0)
|
||||||
}
|
}
|
||||||
}.navigationBarTitle("WWDC").navigationBarItems(trailing: PresentationLink("Camera", destination: CameraView()))
|
}.navigationBarTitle("WWDC").navigationBarItems(trailing:
|
||||||
|
Button(action: {
|
||||||
|
self.isCameraPresented = true
|
||||||
|
}) {
|
||||||
|
Image(systemName: "person.crop.circle")
|
||||||
|
.imageScale(.large)
|
||||||
|
.accessibility(label: Text("User Profile"))
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
).sheet(isPresented: $isCameraPresented,
|
||||||
|
content: { CameraView() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ struct HikeBadge: View {
|
|||||||
var name: String
|
var name: String
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .center) {
|
VStack(alignment: .center) {
|
||||||
Badge()
|
// crashes in Beta 5
|
||||||
.frame(width: 300, height: 300)
|
// Badge()
|
||||||
.scaleEffect(1.0 / 3.0)
|
// .frame(width: 300, height: 300)
|
||||||
.frame(width: 100, height: 100)
|
// .scaleEffect(1.0 / 3.0)
|
||||||
|
// .frame(width: 100, height: 100)
|
||||||
Text(name)
|
Text(name)
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.accessibility(label: Text("Badge for \(name)."))
|
.accessibility(label: Text("Badge for \(name)."))
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ A view showing featured landmarks above a list of all of the landmarks.
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct CategoryHome: View {
|
struct CategoryHome: View {
|
||||||
|
@State private var isProfilePresented = false
|
||||||
|
|
||||||
var categories: [String: [Landmark]] {
|
var categories: [String: [Landmark]] {
|
||||||
.init(
|
.init(
|
||||||
grouping: landmarkData,
|
grouping: landmarkData,
|
||||||
@@ -39,13 +41,16 @@ struct CategoryHome: View {
|
|||||||
}
|
}
|
||||||
.navigationBarTitle(Text("Featured"))
|
.navigationBarTitle(Text("Featured"))
|
||||||
.navigationBarItems(trailing:
|
.navigationBarItems(trailing:
|
||||||
PresentationLink(destination: ProfileHost()) {
|
Button(action: {
|
||||||
|
self.isProfilePresented = true
|
||||||
|
}) {
|
||||||
Image(systemName: "person.crop.circle")
|
Image(systemName: "person.crop.circle")
|
||||||
.imageScale(.large)
|
.imageScale(.large)
|
||||||
.accessibility(label: Text("User Profile"))
|
.accessibility(label: Text("User Profile"))
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
)
|
).sheet(isPresented: $isProfilePresented,
|
||||||
|
content: { ProfileHost().environmentObject(UserData()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ final class ImageStore {
|
|||||||
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
||||||
images.values[index][size] = sizedImage
|
images.values[index][size] = sizedImage
|
||||||
|
|
||||||
return Image(sizedImage, scale: Length(ImageStore.scale), label: Text(verbatim: name))
|
return Image(sizedImage, scale: CGFloat(ImageStore.scale), label: Text(verbatim: name))
|
||||||
}
|
}
|
||||||
|
|
||||||
static func loadImage(name: String) -> CGImage {
|
static func loadImage(name: String) -> CGImage {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ struct ProfileEditor: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Text("Username").bold()
|
Text("Username").bold()
|
||||||
Divider()
|
Divider()
|
||||||
TextField($profile.username)
|
TextField("", text: $profile.username)
|
||||||
}
|
}
|
||||||
|
|
||||||
Toggle(isOn: $profile.prefersNotifications) {
|
Toggle(isOn: $profile.prefersNotifications) {
|
||||||
@@ -25,20 +25,19 @@ struct ProfileEditor: View {
|
|||||||
VStack(alignment: .leading, spacing: 20) {
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
Text("Seasonal Photo").bold()
|
Text("Seasonal Photo").bold()
|
||||||
|
|
||||||
SegmentedControl(selection: $profile.seasonalPhoto) {
|
Picker("", selection: $profile.seasonalPhoto) {
|
||||||
ForEach(Profile.Season.allCases.identified(by: \.self)) { season in
|
ForEach(Profile.Season.allCases, id: \.self) { season in
|
||||||
Text(season.rawValue).tag(season)
|
Text(season.rawValue).tag(season)
|
||||||
}
|
}
|
||||||
}
|
}.pickerStyle(SegmentedPickerStyle())
|
||||||
}
|
}
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 20) {
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
Text("Goal Date").bold()
|
Text("Goal Date").bold()
|
||||||
DatePicker(
|
DatePicker(
|
||||||
$profile.goalDate,
|
"", selection: $profile.goalDate,
|
||||||
minimumDate: Calendar.current.date(byAdding: .year, value: -1, to: profile.goalDate),
|
in: Calendar.current.date(byAdding: .year, value: -1, to: profile.goalDate)! ... Calendar.current.date(byAdding: .year, value: 1, to: profile.goalDate)!,
|
||||||
maximumDate: Calendar.current.date(byAdding: .year, value: 1, to: profile.goalDate),
|
|
||||||
displayedComponents: .date
|
displayedComponents: .date
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ struct ProfileHost: View {
|
|||||||
HStack {
|
HStack {
|
||||||
if self.mode?.value == .active {
|
if self.mode?.value == .active {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.profile = self.draftProfile
|
self.draftProfile = self.profile
|
||||||
self.mode?.animation().value = .inactive
|
self.mode?.animation().value = .inactive
|
||||||
}) {
|
}) {
|
||||||
Text("Done")
|
Text("Done")
|
||||||
@@ -33,7 +33,7 @@ struct ProfileHost: View {
|
|||||||
} else {
|
} else {
|
||||||
ProfileEditor(profile: $draftProfile)
|
ProfileEditor(profile: $draftProfile)
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
self.draftProfile = self.profile
|
self.profile = self.draftProfile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ struct ProfileSummary: View {
|
|||||||
.bold()
|
.bold()
|
||||||
.font(.title)
|
.font(.title)
|
||||||
|
|
||||||
Text("Notifications: \(self.profile.prefersNotifications ? "On": "Off" )")
|
Text("Notifications: \(self.profile.prefersNotifications ? "Onn": "Off" )")
|
||||||
|
|
||||||
Text("Seasonal Photos: \(self.profile.seasonalPhoto.rawValue)")
|
Text("Seasonal Photos: \(self.profile.seasonalPhoto.rawValue)")
|
||||||
|
|
||||||
|
|||||||
@@ -9,20 +9,20 @@ import SwiftUI
|
|||||||
|
|
||||||
struct GraphCapsule: View {
|
struct GraphCapsule: View {
|
||||||
var index: Int
|
var index: Int
|
||||||
var height: Length
|
var height: CGFloat
|
||||||
var range: Range<Double>
|
var range: Range<Double>
|
||||||
var overallRange: Range<Double>
|
var overallRange: Range<Double>
|
||||||
|
|
||||||
var heightRatio: Length {
|
var heightRatio: CGFloat {
|
||||||
max(Length(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
|
max(CGFloat(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
|
||||||
}
|
}
|
||||||
|
|
||||||
var offsetRatio: Length {
|
var offsetRatio: CGFloat {
|
||||||
Length((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
|
CGFloat((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
|
||||||
}
|
}
|
||||||
|
|
||||||
var animation: Animation {
|
var animation: Animation {
|
||||||
Animation.spring(initialVelocity: 5)
|
Animation.spring()
|
||||||
.speed(2)
|
.speed(2)
|
||||||
.delay(0.03 * Double(index))
|
.delay(0.03 * Double(index))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ struct HikeGraph: View {
|
|||||||
let data = hike.observations
|
let data = hike.observations
|
||||||
let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
|
let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
|
||||||
let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
|
let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
|
||||||
let heightRatio = 1 - Length(maxMagnitude / magnitude(of: overallRange))
|
let heightRatio = 1 - CGFloat(maxMagnitude / magnitude(of: overallRange))
|
||||||
|
|
||||||
return GeometryReader { proxy in
|
return GeometryReader { proxy in
|
||||||
HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
|
HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ final class ImageStore {
|
|||||||
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
||||||
images.values[index][size] = sizedImage
|
images.values[index][size] = sizedImage
|
||||||
|
|
||||||
return Image(sizedImage, scale: Length(ImageStore.scale), label: Text(verbatim: name))
|
return Image(sizedImage, scale: CGFloat(ImageStore.scale), label: Text(verbatim: name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ struct ContentView : View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
ForEach(state.moviesState.popular) { id in
|
ForEach(state.moviesState.popular, id: \.self) { id in
|
||||||
Text(self.state.moviesState.movies[id]?.original_title ?? "No title")
|
Text(self.state.moviesState.movies[id]?.original_title ?? "No title")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ struct TabbarView : View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
TabbedView(selection: $selectedIndex) {
|
TabbedView(selection: $selectedIndex) {
|
||||||
UsersListView()
|
UsersListView()
|
||||||
.tabItemLabel(Text("Users"))
|
.tabItem({ Text("Users") })
|
||||||
MapView()
|
MapView()
|
||||||
.tabItemLabel(Text("Map"))
|
.tabItem({ Text("Map") })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,6 @@ struct UserDetailView : View {
|
|||||||
@EnvironmentObject var state: AppState
|
@EnvironmentObject var state: AppState
|
||||||
let userId: Int
|
let userId: Int
|
||||||
|
|
||||||
var editModal: Modal {
|
|
||||||
let user = state.usersState.users[userId]
|
|
||||||
return Modal(UserEditForm(userId: user.id, saveHandler: { saved in
|
|
||||||
self.state.dispatch(action: UserActions.stopEditUser)
|
|
||||||
}).environmentObject(state)) {
|
|
||||||
self.state.dispatch(action: UserActions.stopEditUser)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let user = state.usersState.users[userId]
|
let user = state.usersState.users[userId]
|
||||||
return VStack {
|
return VStack {
|
||||||
@@ -36,7 +27,11 @@ struct UserDetailView : View {
|
|||||||
}) {
|
}) {
|
||||||
Text("Edit user")
|
Text("Edit user")
|
||||||
}
|
}
|
||||||
.presentation(self.state.usersState.isEditingUser ? self.editModal : nil))
|
.sheet(isPresented: $state.usersState.isEditingUser) {
|
||||||
|
UserEditForm(userId: user.id, saveHandler: { saved in
|
||||||
|
self.state.dispatch(action: UserActions.stopEditUser)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,11 @@
|
|||||||
return NavigationView {
|
return NavigationView {
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
Text("User name")
|
Text("User name")
|
||||||
TextField($newUserName, placeholder: Text("New name"))
|
TextField("New name", text: $newUserName)
|
||||||
.textFieldStyle(.roundedBorder)
|
.textFieldStyle(.roundedBorder)
|
||||||
Divider()
|
Divider()
|
||||||
Text("Username")
|
Text("Username")
|
||||||
TextField($newUserUsername, placeholder: Text("New username"))
|
TextField("New username", text: $newUserUsername)
|
||||||
.textFieldStyle(.roundedBorder)
|
.textFieldStyle(.roundedBorder)
|
||||||
}.padding(16)
|
}.padding(16)
|
||||||
Button(action: save) {
|
Button(action: save) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ struct Badge : View {
|
|||||||
|
|
||||||
var animation: Animation {
|
var animation: Animation {
|
||||||
Animation
|
Animation
|
||||||
.spring(initialVelocity: 5)
|
.spring()
|
||||||
.speed(2)
|
.speed(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ struct TimeTravelBarView : View {
|
|||||||
getValue: { Double(self.store.currentStateIndex) },
|
getValue: { Double(self.store.currentStateIndex) },
|
||||||
setValue: { self.store.currentStateIndex = Int($0) })
|
setValue: { self.store.currentStateIndex = Int($0) })
|
||||||
|
|
||||||
return Slider(value: indexBinding, from: 0, through: Double(store.stateCount-1))
|
return Slider(value: indexBinding, in: 0...Double(store.stateCount-1))
|
||||||
.background(Color.white)
|
.background(Color.white)
|
||||||
.frame(height: 44.0, alignment: .bottom)
|
.frame(height: 44.0, alignment: .bottom)
|
||||||
.padding()
|
.padding()
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ struct AddItemView: View {
|
|||||||
setValue: { self.store.dispatch(event: .changePartialItemName($0)) })
|
setValue: { self.store.dispatch(event: .changePartialItemName($0)) })
|
||||||
|
|
||||||
return VStack(spacing: 16) {
|
return VStack(spacing: 16) {
|
||||||
TextField(textBinding, placeholder: Text("Title"))
|
TextField("Title", text: textBinding)
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.store.dispatch(event: .addItem)
|
self.store.dispatch(event: .addItem)
|
||||||
}) {
|
}) {
|
||||||
@@ -22,7 +22,7 @@ struct AddItemView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.relativeWidth(1.0)
|
// .relativeWidth(1.0)
|
||||||
.background(Color.accentColor)
|
.background(Color.accentColor)
|
||||||
.disabled(store.state.partialItemName.isEmpty)
|
.disabled(store.state.partialItemName.isEmpty)
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ struct ModalDimmingView : View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
Color
|
Color
|
||||||
.black
|
.black
|
||||||
.relativeWidth(1.0)
|
// .relativeWidth(1.0)
|
||||||
.relativeHeight(1.0)
|
// .relativeHeight(1.0)
|
||||||
.opacity(0.3)
|
.opacity(0.3)
|
||||||
.edgesIgnoringSafeArea([.bottom, .top])
|
.edgesIgnoringSafeArea([.bottom, .top])
|
||||||
.transition(.opacity)
|
.transition(.opacity)
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ struct TodoListItemView : View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let binding = Binding(
|
let binding = Binding(
|
||||||
getValue: { self.item.isFinished },
|
get: { self.item.isFinished },
|
||||||
setValue: { self.store.dispatch(event: .setItemDone(identifier: self.item.id, isDone: $0)) })
|
set: { self.store.dispatch(event: .setItemDone(identifier: self.item.id, isDone: $0)) })
|
||||||
|
|
||||||
return Toggle(isOn: binding) {
|
return Toggle(isOn: binding) {
|
||||||
Text(item.title)
|
Text(item.title)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ struct TodoListView : View {
|
|||||||
VStack {
|
VStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
AddItemView()
|
AddItemView()
|
||||||
.relativeWidth(1.0)
|
// .relativeWidth(1.0)
|
||||||
.background(Color.white)
|
.background(Color.white)
|
||||||
.cornerRadius(12.0)
|
.cornerRadius(12.0)
|
||||||
.shadow(radius: 16.0)
|
.shadow(radius: 16.0)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ struct ContentView: View {
|
|||||||
.fontWeight(.semibold)
|
.fontWeight(.semibold)
|
||||||
.foregroundColor(.black)
|
.foregroundColor(.black)
|
||||||
.padding(4)
|
.padding(4)
|
||||||
.animation(.basic(duration: 0.3, curve: .easeOut))
|
// .animation(.basic(duration: 0.3, curve: .easeOut))
|
||||||
|
|
||||||
Image("ui")
|
Image("ui")
|
||||||
.frame(width: show ? 414 : 300, height: show ? 600 : 300)
|
.frame(width: show ? 414 : 300, height: show ? 600 : 300)
|
||||||
@@ -35,7 +35,7 @@ struct ContentView: View {
|
|||||||
.fontWeight(.regular)
|
.fontWeight(.regular)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
.padding(4)
|
.padding(4)
|
||||||
.animation(.basic(duration: 0.4, curve: .easeIn))
|
// .animation(.basic(duration: 0.4, curve: .easeIn))
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
withAnimation {
|
withAnimation {
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ struct NoteDetail : View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
TextField(self.text.binding,
|
TextField("", text: self.text.binding,
|
||||||
placeholder: nil,
|
|
||||||
onEditingChanged: { _ in self.updateNote()},
|
onEditingChanged: { _ in self.updateNote()},
|
||||||
onCommit: {})
|
onCommit: {})
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ struct HikeBadge: View {
|
|||||||
var name: String
|
var name: String
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .center) {
|
VStack(alignment: .center) {
|
||||||
Badge()
|
// crashes in Beta 5
|
||||||
.frame(width: 300, height: 300)
|
// Badge()
|
||||||
.scaleEffect(1.0 / 3.0)
|
// .frame(width: 300, height: 300)
|
||||||
.frame(width: 100, height: 100)
|
// .scaleEffect(1.0 / 3.0)
|
||||||
|
// .frame(width: 100, height: 100)
|
||||||
Text(name)
|
Text(name)
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.accessibility(label: Text("Badge for \(name)."))
|
.accessibility(label: Text("Badge for \(name)."))
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ A view showing featured landmarks above a list of all of the landmarks.
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct CategoryHome: View {
|
struct CategoryHome: View {
|
||||||
|
@State private var isProfilePresented = false
|
||||||
|
|
||||||
var categories: [String: [Landmark]] {
|
var categories: [String: [Landmark]] {
|
||||||
.init(
|
.init(
|
||||||
grouping: landmarkData,
|
grouping: landmarkData,
|
||||||
@@ -39,12 +41,16 @@ struct CategoryHome: View {
|
|||||||
}
|
}
|
||||||
.navigationBarTitle(Text("Featured"))
|
.navigationBarTitle(Text("Featured"))
|
||||||
.navigationBarItems(trailing:
|
.navigationBarItems(trailing:
|
||||||
PresentationLink(destination: ProfileHost()) {
|
Button(action: {
|
||||||
|
self.isProfilePresented = true
|
||||||
|
}) {
|
||||||
Image(systemName: "person.crop.circle")
|
Image(systemName: "person.crop.circle")
|
||||||
.imageScale(.large)
|
.imageScale(.large)
|
||||||
.accessibility(label: Text("User Profile"))
|
.accessibility(label: Text("User Profile"))
|
||||||
.padding()
|
.padding()
|
||||||
})
|
}
|
||||||
|
).sheet(isPresented: $isProfilePresented,
|
||||||
|
content: { ProfileHost().environmentObject(UserData()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ final class ImageStore {
|
|||||||
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
?? _sizeImage(images.values[index][ImageStore.originalSize]!, to: size * ImageStore.scale)
|
||||||
images.values[index][size] = sizedImage
|
images.values[index][size] = sizedImage
|
||||||
|
|
||||||
return Image(sizedImage, scale: Length(ImageStore.scale), label: Text(verbatim: name))
|
return Image(sizedImage, scale: CGFloat(ImageStore.scale), label: Text(verbatim: name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
fileprivate func _guaranteeInitialImage(name: String) -> _ImageDictionary.Index {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ struct ProfileEditor: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Text("Username").bold()
|
Text("Username").bold()
|
||||||
Divider()
|
Divider()
|
||||||
TextField($profile.username)
|
TextField("", text: $profile.username)
|
||||||
}
|
}
|
||||||
|
|
||||||
Toggle(isOn: $profile.prefersNotifications) {
|
Toggle(isOn: $profile.prefersNotifications) {
|
||||||
@@ -25,20 +25,19 @@ struct ProfileEditor: View {
|
|||||||
VStack(alignment: .leading, spacing: 20) {
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
Text("Seasonal Photo").bold()
|
Text("Seasonal Photo").bold()
|
||||||
|
|
||||||
SegmentedControl(selection: $profile.seasonalPhoto) {
|
Picker("", selection: $profile.seasonalPhoto) {
|
||||||
ForEach(Profile.Season.allCases, id: \.self) { season in
|
ForEach(Profile.Season.allCases, id: \.self) { season in
|
||||||
Text(season.rawValue).tag(season)
|
Text(season.rawValue).tag(season)
|
||||||
}
|
}
|
||||||
}
|
}.pickerStyle(SegmentedPickerStyle())
|
||||||
}
|
}
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 20) {
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
Text("Goal Date").bold()
|
Text("Goal Date").bold()
|
||||||
DatePicker(
|
DatePicker(
|
||||||
$profile.goalDate,
|
"", selection: $profile.goalDate,
|
||||||
minimumDate: Calendar.current.date(byAdding: .year, value: -1, to: profile.goalDate),
|
in: Calendar.current.date(byAdding: .year, value: -1, to: profile.goalDate)! ... Calendar.current.date(byAdding: .year, value: 1, to: profile.goalDate)!,
|
||||||
maximumDate: Calendar.current.date(byAdding: .year, value: 1, to: profile.goalDate),
|
|
||||||
displayedComponents: .date
|
displayedComponents: .date
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ struct ProfileHost: View {
|
|||||||
HStack {
|
HStack {
|
||||||
if self.mode?.value == .active {
|
if self.mode?.value == .active {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.profile = self.draftProfile
|
self.draftProfile = self.profile
|
||||||
self.mode?.animation().value = .inactive
|
self.mode?.animation().value = .inactive
|
||||||
}) {
|
}) {
|
||||||
Text("Done")
|
Text("Done")
|
||||||
@@ -33,7 +33,7 @@ struct ProfileHost: View {
|
|||||||
} else {
|
} else {
|
||||||
ProfileEditor(profile: $draftProfile)
|
ProfileEditor(profile: $draftProfile)
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
self.draftProfile = self.profile
|
self.profile = self.draftProfile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,20 +9,20 @@ import SwiftUI
|
|||||||
|
|
||||||
struct GraphCapsule: View {
|
struct GraphCapsule: View {
|
||||||
var index: Int
|
var index: Int
|
||||||
var height: Length
|
var height: CGFloat
|
||||||
var range: Range<Double>
|
var range: Range<Double>
|
||||||
var overallRange: Range<Double>
|
var overallRange: Range<Double>
|
||||||
|
|
||||||
var heightRatio: Length {
|
var heightRatio: CGFloat {
|
||||||
max(Length(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
|
max(CGFloat(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
|
||||||
}
|
}
|
||||||
|
|
||||||
var offsetRatio: Length {
|
var offsetRatio: CGFloat {
|
||||||
Length((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
|
CGFloat((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
|
||||||
}
|
}
|
||||||
|
|
||||||
var animation: Animation {
|
var animation: Animation {
|
||||||
Animation.spring(initialVelocity: 5)
|
Animation.spring()
|
||||||
.speed(2)
|
.speed(2)
|
||||||
.delay(0.03 * Double(index))
|
.delay(0.03 * Double(index))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ struct HikeGraph: View {
|
|||||||
let data = hike.observations
|
let data = hike.observations
|
||||||
let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
|
let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
|
||||||
let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
|
let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
|
||||||
let heightRatio = 1 - Length(maxMagnitude / magnitude(of: overallRange))
|
let heightRatio = 1 - CGFloat(maxMagnitude / magnitude(of: overallRange))
|
||||||
|
|
||||||
return GeometryReader { proxy in
|
return GeometryReader { proxy in
|
||||||
HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
|
HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
|
||||||
|
|||||||
Reference in New Issue
Block a user