Skip and docs
This commit is contained in:
177
pedi-foods/Sources/PediFoods/ContentView.swift
Normal file
177
pedi-foods/Sources/PediFoods/ContentView.swift
Normal file
@@ -0,0 +1,177 @@
|
||||
import SwiftUI
|
||||
|
||||
enum ContentTab: String, Hashable {
|
||||
case welcome, home, settings
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
@AppStorage("tab") var tab = ContentTab.welcome
|
||||
@AppStorage("name") var welcomeName = "Skipper"
|
||||
@AppStorage("appearance") var appearance = ""
|
||||
@State var viewModel = ViewModel()
|
||||
|
||||
var body: some View {
|
||||
TabView(selection: $tab) {
|
||||
NavigationStack {
|
||||
WelcomeView(welcomeName: $welcomeName)
|
||||
}
|
||||
.tabItem { Label("Welcome", systemImage: "heart.fill") }
|
||||
.tag(ContentTab.welcome)
|
||||
|
||||
NavigationStack {
|
||||
ItemListView()
|
||||
.navigationTitle(Text("\(viewModel.items.count) Items"))
|
||||
}
|
||||
.tabItem { Label("Home", systemImage: "house.fill") }
|
||||
.tag(ContentTab.home)
|
||||
|
||||
NavigationStack {
|
||||
SettingsView(appearance: $appearance, welcomeName: $welcomeName)
|
||||
.navigationTitle("Settings")
|
||||
}
|
||||
.tabItem { Label("Settings", systemImage: "gearshape.fill") }
|
||||
.tag(ContentTab.settings)
|
||||
}
|
||||
.environment(viewModel)
|
||||
.preferredColorScheme(appearance == "dark" ? .dark : appearance == "light" ? .light : nil)
|
||||
}
|
||||
}
|
||||
|
||||
struct WelcomeView : View {
|
||||
@State var heartBeating = false
|
||||
@Binding var welcomeName: String
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
Text("Hello [\(welcomeName)](https://skip.tools)!")
|
||||
.padding()
|
||||
Image(systemName: "heart.fill")
|
||||
.foregroundStyle(.red)
|
||||
.scaleEffect(heartBeating ? 1.5 : 1.0)
|
||||
.animation(.easeInOut(duration: 1).repeatForever(), value: heartBeating)
|
||||
.task { heartBeating = true }
|
||||
}
|
||||
.font(.largeTitle)
|
||||
}
|
||||
}
|
||||
|
||||
struct ItemListView : View {
|
||||
@Environment(ViewModel.self) var viewModel: ViewModel
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
ForEach(viewModel.items) { item in
|
||||
NavigationLink(value: item) {
|
||||
Label {
|
||||
Text(item.itemTitle)
|
||||
} icon: {
|
||||
if item.favorite {
|
||||
Image(systemName: "star.fill")
|
||||
.foregroundStyle(.yellow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.onDelete { offsets in
|
||||
viewModel.items.remove(atOffsets: offsets)
|
||||
}
|
||||
.onMove { fromOffsets, toOffset in
|
||||
viewModel.items.move(fromOffsets: fromOffsets, toOffset: toOffset)
|
||||
}
|
||||
}
|
||||
.navigationDestination(for: Item.self) { item in
|
||||
ItemView(item: item)
|
||||
.navigationTitle(item.itemTitle)
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItemGroup {
|
||||
Button {
|
||||
withAnimation {
|
||||
viewModel.items.insert(Item(), at: 0)
|
||||
}
|
||||
} label: {
|
||||
Label("Add", systemImage: "plus")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ItemView : View {
|
||||
@State var item: Item
|
||||
@Environment(ViewModel.self) var viewModel: ViewModel
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
TextField("Title", text: $item.title)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
Toggle("Favorite", isOn: $item.favorite)
|
||||
DatePicker("Date", selection: $item.date)
|
||||
Text("Notes").font(.title3)
|
||||
TextEditor(text: $item.notes)
|
||||
.border(Color.secondary, width: 1.0)
|
||||
}
|
||||
.navigationBarBackButtonHidden()
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Cancel") {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
Button("Save") {
|
||||
viewModel.save(item: item)
|
||||
dismiss()
|
||||
}
|
||||
.disabled(!viewModel.isUpdated(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SettingsView : View {
|
||||
@Binding var appearance: String
|
||||
@Binding var welcomeName: String
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
TextField("Name", text: $welcomeName)
|
||||
Picker("Appearance", selection: $appearance) {
|
||||
Text("System").tag("")
|
||||
Text("Light").tag("light")
|
||||
Text("Dark").tag("dark")
|
||||
}
|
||||
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
|
||||
let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
|
||||
Text("Version \(version) (\(buildNumber))")
|
||||
}
|
||||
HStack {
|
||||
PlatformHeartView()
|
||||
Text("Powered by [Skip](https://skip.tools)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A view that shows a blue heart on iOS and a green heart on Android.
|
||||
struct PlatformHeartView : View {
|
||||
var body: some View {
|
||||
#if os(Android)
|
||||
ComposeView {
|
||||
HeartComposer()
|
||||
}
|
||||
#else
|
||||
Text(verbatim: "💙")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if SKIP
|
||||
/// Use a ContentComposer to integrate Compose content. This code will be transpiled to Kotlin.
|
||||
struct HeartComposer : ContentComposer {
|
||||
@Composable func Compose(context: ComposeContext) {
|
||||
androidx.compose.material3.Text("💚", modifier: context.modifier)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user