Develop Apps for iOSをやってみる 〜その8〜
はじめに
DX推進室の野上です。
前回 の続きです。
どこから?
今回はここから続けます。
最初に
今回も用意されたプロジェクトファイルがあります。
前回の反省を踏まえて、プロジェクトファイルを使うことにします。
アプリのデータを更新する
EditViewを使って新しいScrumを作る
ScrumsViewに新しいScrumを作成するボタンを追加します。
@State をつけた isPresented でEditViewの表示を制御します。
Scrum Listにsheet modifierをつけて、EditViewの呼び出しを追加します。
EditViewから戻ってきた際に、Scrum Listに追加する処理も追加します。
import SwiftUI
struct ScrumsView: View {
@Binding var scrums: [DailyScrum]
@State private var isPresented = false
@State private var newScrumData = DailyScrum.Data()
var body: some View {
List {
ForEach(scrums) { scrum in
NavigationLink(destination: DetailView(scrum: binding(for: scrum))) {
CardView(scrum: scrum)
}
.listRowBackground(scrum.color)
}
}
.navigationTitle("Daily Scrums")
.navigationBarItems(trailing: Button(action: {
isPresented = true
}) {
Image(systemName: "plus")
})
.sheet(isPresented: $isPresented) {
NavigationView {
EditView(scrumData: $newScrumData)
.navigationBarItems(leading: Button("Dismiss") {
isPresented = false
}, trailing: Button("Add") {
let newScrum = DailyScrum(title: newScrumData.title, attendees: newScrumData.attendees,
lengthInMinutes: Int(newScrumData.lengthInMinutes), color: newScrumData.color)
scrums.append(newScrum)
isPresented = false
})
}
}
}
private func binding(for scrum: DailyScrum) -> Binding<DailyScrum> {
guard let scrumIndex = scrums.firstIndex(where: { $0.id == scrum.id }) else {
fatalError("Can't find scrum in array")
}
return $scrums[scrumIndex]
}
}
struct ScrumsView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
ScrumsView(scrums: .constant(DailyScrum.data))
}
}
}
シミュレータで動作を確認すると、新しいScrumを作成してリストに追加されるまでが確認できると思います。
Scrum履歴を追加する
デイリーミーティングが終了したら、日付、長さ、参加者を記録する処理を追加します。
MeetingViewにHistory要素を追加します。
Historyクラスはダウンロードしたプロジェクトに入っています。
import SwiftUI
import AVFoundation
struct MeetingView: View {
@Binding var scrum: DailyScrum
@StateObject var scrumTimer = ScrumTimer()
var player: AVPlayer { AVPlayer.sharedDingPlayer }
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 16.0)
.fill(scrum.color)
VStack {
MeetingHeaderView(secondsElapsed: scrumTimer.secondsElapsed, secondsRemaining: scrumTimer.secondsRemaining, scrumColor: scrum.color)
Circle()
.strokeBorder(lineWidth: 24, antialiased: true)
MeetingFooterView(speakers: scrumTimer.speakers, skipAction: scrumTimer.skipSpeaker)
}
}
.padding()
.foregroundColor(scrum.color.accessibleFontColor)
.onAppear {
scrumTimer.reset(lengthInMinutes: scrum.lengthInMinutes, attendees: scrum.attendees)
scrumTimer.speakerChangedAction = {
player.seek(to: .zero)
player.play()
}
scrumTimer.startScrum()
}
.onDisappear {
scrumTimer.stopScrum()
let newHistory = History(attendees: scrum.attendees, lengthInMinutes: scrumTimer.secondsElapsed / 60)
scrum.history.insert(newHistory, at: 0)
}
}
}
struct MeetingView_Previews: PreviewProvider {
static var previews: some View {
MeetingView(scrum: .constant(DailyScrum.data[0]))
}
}
DetailViewにHistoryのヘッダーを追加します。
まだHisotryがない場合はその旨文言を表示し、デイリーミーティングを実施したら記録するように修正します。
import SwiftUI
struct DetailView: View {
@Binding var scrum: DailyScrum
@State private var data: DailyScrum.Data = DailyScrum.Data()
@State private var isPresented = false
var body: some View {
List {
Section(header: Text("Meeting Info")) {
NavigationLink(
destination: MeetingView(scrum: $scrum)) {
Label("Start Meeting", systemImage: "timer")
.font(.headline)
.foregroundColor(.accentColor)
.accessibilityLabel(Text("start meeting"))
}
HStack {
Label("Length", systemImage: "clock")
.accessibilityLabel(Text("meeting length"))
Spacer()
Text("\(scrum.lengthInMinutes) minutes")
}
HStack {
Label("Color", systemImage: "paintpalette")
Spacer()
Image(systemName: "checkmark.circle.fill")
.foregroundColor(scrum.color)
}
.accessibilityElement(children: .ignore)
}
Section(header: Text("Attendees")) {
ForEach(scrum.attendees, id: \.self) { attendee in
Label(attendee, systemImage: "person")
.accessibilityLabel(Text("person"))
.accessibilityValue(Text(attendee))
}
}
Section(header: Text("History")) {
if scrum.history.isEmpty {
Label("No meetings yet", systemImage: "calendar.badge.exclamationmark")
}
ForEach(scrum.history) { history in
HStack {
Image(systemName: "calendar")
Text(history.date, style: .date)
}
}
}
}
.listStyle(InsetGroupedListStyle())
.navigationBarItems(trailing: Button("Edit") {
isPresented = true
data = scrum.data
})
.navigationTitle(scrum.title)
.fullScreenCover(isPresented: $isPresented) {
NavigationView {
EditView(scrumData: $data)
.navigationTitle(scrum.title)
.navigationBarItems(leading: Button("Cancel") {
isPresented = false
}, trailing: Button("Done") {
isPresented = false
scrum.update(from: data)
})
}
}
}
}
struct DetailView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
DetailView(scrum: .constant(DailyScrum.data[0]))
}
}
}
こちらもシミュレータで動かしてみて、Historyが記録されることを確認してください。
複数回実施するとHistoryが追加されていきます。
ここまでのまとめ
今回は特に難しいこともなく追加できたかと思います。
次回は データの永続化です。
あと3回ぐらいで終わる・・・はず。