Skip to content

Commit

Permalink
Add "App Design and Layout" > "Working with UI Controls"
Browse files Browse the repository at this point in the history
  • Loading branch information
WillieWangWei committed Jun 9, 2019
1 parent bc18c83 commit 8790e77
Show file tree
Hide file tree
Showing 9 changed files with 388 additions and 1 deletion.
31 changes: 31 additions & 0 deletions App-Design-and-Layout/HikeBadge.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// HikeBadge.swift
// App-Design-and-Layout
//
// Created by 王炜 on 2019/6/9.
//

import SwiftUI

struct HikeBadge: View {
var name: String
var body: some View {
VStack(alignment: .center) {
Badge()
.frame(width: 300, height: 300)
.scaleEffect(1.0 / 3.0)
.frame(width: 100, height: 100)
Text(name)
.font(.caption)
.accessibility(label: Text("Badge for \(name)."))
}
}
}

#if DEBUG
struct HikeBadge_Previews : PreviewProvider {
static var previews: some View {
HikeBadge(name: "Preview Testing")
}
}
#endif
49 changes: 49 additions & 0 deletions App-Design-and-Layout/HikeDetail.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
See LICENSE folder for this sample’s licensing information.

Abstract:
A view showing the details for a hike.
*/

import SwiftUI

struct HikeDetail: View {
let hike: Hike
@State var dataToShow = \Hike.Observation.elevation

var buttons = [
("Elevation", \Hike.Observation.elevation),
("Heart Rate", \Hike.Observation.heartRate),
("Pace", \Hike.Observation.pace),
]

var body: some View {
return VStack {
HikeGraph(hike: hike, path: dataToShow)
.frame(height: 200, alignment: .center)

HStack(spacing: 25) {
ForEach(buttons.identified(by: \.0)) { value in
Button(action: {
self.dataToShow = value.1
}) {
Text(verbatim: value.0)
.font(.system(size: 15))
.color(value.1 == self.dataToShow
? Color.gray
: Color.accentColor)
.animation(nil)
}
}
}
}
}
}

#if DEBUG
struct HikeDetail_Previews: PreviewProvider {
static var previews: some View {
HikeDetail(hike: hikeData[0])
}
}
#endif
68 changes: 68 additions & 0 deletions App-Design-and-Layout/HikeView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
See LICENSE folder for this sample’s licensing information.

Abstract:
A view displaying inforamtion about a hike, including an elevation graph.
*/

import SwiftUI

struct HikeView: View {
var hike: Hike
@State private var showDetail = false

var transition: AnyTransition {
let insertion = AnyTransition.move(edge: .trailing)
.combined(with: .opacity)
let removal = AnyTransition.scale()
.combined(with: .opacity)
return .asymmetric(insertion: insertion, removal: removal)
}

var body: some View {
VStack {
HStack {
HikeGraph(hike: hike, path: \.elevation)
.frame(width: 50, height: 30)
.animation(nil)

VStack(alignment: .leading) {
Text(verbatim: hike.name)
.font(.headline)
Text(verbatim: hike.distanceText)
}

Spacer()

Button(action: {
withAnimation {
self.showDetail.toggle()
}
}) {
Image(systemName: "chevron.right.circle")
.imageScale(.large)
.rotationEffect(.degrees(showDetail ? 90 : 0))
.scaleEffect(showDetail ? 1.5 : 1)
.padding()
}
}

if showDetail {
HikeDetail(hike: hike)
.transition(transition)
}
}
}
}

#if DEBUG
struct HikeView_Previews: PreviewProvider {
static var previews: some View {
VStack {
HikeView(hike: hikeData[0])
.padding()
Spacer()
}
}
}
#endif
2 changes: 1 addition & 1 deletion App-Design-and-Layout/Home.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct CategoryHome: View {
.imageScale(.large)
.accessibility(label: Text("User Profile"))
.padding(),
destination: Text("User Profile")
destination: ProfileHost()
)
)
}
Expand Down
31 changes: 31 additions & 0 deletions App-Design-and-Layout/Models/Profile.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
See LICENSE folder for this sample’s licensing information.

Abstract:
A model object that stores user profile data.
*/

import Foundation

struct Profile {
var username: String
var prefersNotifications: Bool
var seasonalPhoto: Season
var goalDate: Date

static let `default` = Self(username: "g_kumar", prefersNotifications: true, seasonalPhoto: .winter)

init(username: String, prefersNotifications: Bool = true, seasonalPhoto: Season = .winter) {
self.username = username
self.prefersNotifications = prefersNotifications
self.seasonalPhoto = seasonalPhoto
self.goalDate = Date()
}

enum Season: String, CaseIterable {
case spring = "🌷"
case summer = "🌞"
case autumn = "🍂"
case winter = "☃️"
}
}
56 changes: 56 additions & 0 deletions App-Design-and-Layout/Profile/ProfileEditor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// ProfileEditor.swift
// App-Design-and-Layout
//
// Created by 王炜 on 2019/6/9.
//

import SwiftUI

struct ProfileEditor: View {
@Binding var profile: Profile

var body: some View {
List {
HStack {
Text("Username").bold()
Divider()
TextField($profile.username)
}

Toggle(isOn: $profile.prefersNotifications) {
Text("Enable Notifications")
}

VStack(alignment: .leading, spacing: 20) {
Text("Seasonal Photo").bold()

SegmentedControl(selection: $profile.seasonalPhoto) {
ForEach(Profile.Season.allCases.identified(by: \.self)) { season in
Text(season.rawValue).tag(season)
}
}
}
.padding(.top)

VStack(alignment: .leading, spacing: 20) {
Text("Goal Date").bold()
DatePicker(
$profile.goalDate,
minimumDate: Calendar.current.date(byAdding: .year, value: -1, to: profile.goalDate),
maximumDate: Calendar.current.date(byAdding: .year, value: 1, to: profile.goalDate),
displayedComponents: .date
)
}
.padding(.top)
}
}
}

#if DEBUG
struct ProfileEditor_Previews: PreviewProvider {
static var previews: some View {
ProfileEditor(profile: .constant(.default))
}
}
#endif
50 changes: 50 additions & 0 deletions App-Design-and-Layout/Profile/ProfileHost.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// ProfileHost.swift
// App-Design-and-Layout
//
// Created by 王炜 on 2019/6/9.
//

import SwiftUI

struct ProfileHost: View {
@Environment(\.editMode) var mode
@State var profile = Profile.default
@State var draftProfile = Profile.default

var body: some View {
VStack(alignment: .leading, spacing: 20) {
HStack {
if self.mode?.value == .active {
Button(action: {
self.profile = self.draftProfile
self.mode?.animation().value = .inactive
}) {
Text("Done")
}
}

Spacer()

EditButton()
}
if self.mode?.value == .inactive {
ProfileSummary(profile: profile)
} else {
ProfileEditor(profile: $draftProfile)
.onDisappear {
self.draftProfile = self.profile
}
}
}
.padding()
}
}

#if DEBUG
struct ProfileHost_Previews: PreviewProvider {
static var previews: some View {
ProfileHost()
}
}
#endif
66 changes: 66 additions & 0 deletions App-Design-and-Layout/Profile/ProfileSummary.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// ProfileSummary.swift
// App-Design-and-Layout
//
// Created by 王炜 on 2019/6/9.
//

import SwiftUI

struct ProfileSummary: View {
var profile: Profile

static var goalFormat: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "MMMM d, yyyy"
return formatter
}

var body: some View {
List {
Text(profile.username)
.bold()
.font(.title)

Text("Notifications: \(self.profile.prefersNotifications ? "On": "Off" )")

Text("Seasonal Photos: \(self.profile.seasonalPhoto.rawValue)")

Text("Goal Date: \(self.profile.goalDate, formatter: Self.goalFormat)")

VStack(alignment: .leading) {
Text("Completed Badges")
.font(.headline)
ScrollView {
HStack {
HikeBadge(name: "First Hike")

HikeBadge(name: "Earth Day")
.hueRotation(Angle(degrees: 90))


HikeBadge(name: "Tenth Hike")
.grayscale(0.5)
.hueRotation(Angle(degrees: 45))
}
}
.frame(height: 140)
}

VStack(alignment: .leading) {
Text("Recent Hikes")
.font(.headline)

HikeView(hike: hikeData[0])
}
}
}
}

#if DEBUG
struct ProfileSummary_Previews: PreviewProvider {
static var previews: some View {
ProfileSummary(profile: Profile.default)
}
}
#endif
Loading

0 comments on commit 8790e77

Please sign in to comment.