Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
51d6859209
commit
c93d80e591
3
PRD.md
3
PRD.md
@ -324,6 +324,7 @@ These principles are fundamental to the project's long-term success and must be
|
||||
- **Navigation destinations**: Deep linking for alarm editing
|
||||
- **Toolbar integration**: Settings and add buttons in navigation bars
|
||||
- **Sheet presentations**: Modal settings and alarm creation
|
||||
- **Title presentation**: Inline titles on iPhone; titles hidden on iPad tab screens
|
||||
|
||||
### Visual Design
|
||||
- **Rounded corners**: Modern iOS design language
|
||||
@ -556,7 +557,7 @@ The following changes **automatically require** PRD updates:
|
||||
- Snooze duration settings
|
||||
|
||||
### Noise Tab
|
||||
1. **Sound Selection**: Browse sounds by category with search functionality
|
||||
1. **Sound Selection**: Browse sounds by category with system search in the navigation bar (iPhone and iPad)
|
||||
2. **Sound Preview**: Long-press for 3-second preview
|
||||
3. **Visual Feedback**: Grid layout with clear selection states
|
||||
4. **Auto-stop**: Automatically stops current sound when selecting new one
|
||||
|
||||
@ -52,8 +52,6 @@ struct ContentView: View {
|
||||
ClockSettingsView(style: clockViewModel.style) { newStyle in
|
||||
clockViewModel.updateStyle(newStyle)
|
||||
}
|
||||
.navigationTitle("Settings")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
.tabItem {
|
||||
Label("Settings", systemImage: "gearshape")
|
||||
|
||||
@ -18,6 +18,7 @@ struct AlarmView: View {
|
||||
|
||||
// MARK: - Body
|
||||
var body: some View {
|
||||
let isPad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
Group {
|
||||
if viewModel.alarms.isEmpty {
|
||||
EmptyAlarmsView {
|
||||
@ -50,7 +51,8 @@ struct AlarmView: View {
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
}
|
||||
.navigationTitle("Alarms")
|
||||
.navigationTitle(isPad ? "" : "Alarms")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button {
|
||||
|
||||
@ -27,6 +27,7 @@ struct ClockSettingsView: View {
|
||||
|
||||
// MARK: - Body
|
||||
var body: some View {
|
||||
let isPad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
ScrollView {
|
||||
VStack(spacing: Design.Spacing.xxLarge) {
|
||||
BasicAppearanceSection(
|
||||
@ -101,7 +102,7 @@ struct ClockSettingsView: View {
|
||||
.padding(.bottom, Design.Spacing.xxxLarge)
|
||||
}
|
||||
.background(AppSurface.primary)
|
||||
.navigationTitle("Clock Settings")
|
||||
.navigationTitle(isPad ? "" : "Settings")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.onAppear {
|
||||
digitColor = Color(hex: style.digitColorHex) ?? .white
|
||||
|
||||
@ -15,8 +15,10 @@ struct ClockToolbar: View {
|
||||
|
||||
// MARK: - Body
|
||||
var body: some View {
|
||||
let isPad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
EmptyView()
|
||||
.navigationTitle(isDisplayMode ? "" : "Clock")
|
||||
.navigationTitle(isDisplayMode || isPad ? "" : "Clock")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationBarBackButtonHidden(isDisplayMode)
|
||||
.toolbar(isDisplayMode ? .hidden : .automatic)
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ struct SoundCategoryView: View {
|
||||
let sounds: [Sound]
|
||||
@Binding var selectedSound: Sound?
|
||||
@State private var selectedCategory: SoundCategory = .all
|
||||
@State private var searchText: String = ""
|
||||
@Binding var searchText: String
|
||||
@State private var viewModel = SoundViewModel()
|
||||
|
||||
// MARK: - Computed Properties
|
||||
@ -69,9 +69,6 @@ struct SoundCategoryView: View {
|
||||
// MARK: - Body
|
||||
var body: some View {
|
||||
VStack(spacing: Design.Spacing.medium) {
|
||||
// Search Bar
|
||||
searchBar
|
||||
|
||||
// Category Tabs
|
||||
categoryTabs
|
||||
|
||||
@ -83,24 +80,6 @@ struct SoundCategoryView: View {
|
||||
.padding(.top, Design.Spacing.medium)
|
||||
}
|
||||
|
||||
// MARK: - Subviews
|
||||
private var searchBar: some View {
|
||||
HStack {
|
||||
Image(systemName: "magnifyingglass")
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
TextField("Search sounds...", text: $searchText)
|
||||
.textFieldStyle(.plain)
|
||||
.foregroundColor(.primary)
|
||||
.autocorrectionDisabled()
|
||||
.textInputAutocapitalization(.never)
|
||||
}
|
||||
.padding(.horizontal, Design.Spacing.medium)
|
||||
.padding(.vertical, Design.Spacing.small)
|
||||
.background(Color(.systemGray6))
|
||||
.cornerRadius(10)
|
||||
}
|
||||
|
||||
private var categoryTabs: some View {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack(spacing: Design.Spacing.small) {
|
||||
@ -257,7 +236,8 @@ struct SoundCard: View {
|
||||
Sound(name: "Fan Noise", fileName: "fan-noise.mp3", category: "mechanical", description: "Fan sounds"),
|
||||
Sound(name: "Digital Alarm", fileName: "digital-alarm.mp3", category: "alarm", description: "Alarm sound")
|
||||
],
|
||||
selectedSound: .constant(nil)
|
||||
selectedSound: .constant(nil),
|
||||
searchText: .constant("")
|
||||
)
|
||||
.padding()
|
||||
}
|
||||
|
||||
@ -22,6 +22,11 @@ struct NoiseView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
@State private var searchText: String = ""
|
||||
|
||||
private var isPad: Bool {
|
||||
UIDevice.current.userInterfaceIdiom == .pad
|
||||
}
|
||||
|
||||
// MARK: - Body
|
||||
var body: some View {
|
||||
@ -42,6 +47,11 @@ struct NoiseView: View {
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
.animation(.easeInOut(duration: 0.3), value: selectedSound)
|
||||
.searchable(
|
||||
text: $searchText,
|
||||
placement: .navigationBarDrawer(displayMode: .automatic),
|
||||
prompt: "Search sounds"
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Computed Properties
|
||||
@ -64,8 +74,10 @@ struct NoiseView: View {
|
||||
VStack(spacing: 0) {
|
||||
// Fixed header
|
||||
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
|
||||
Text("Ambient Sounds")
|
||||
.sectionTitleStyle()
|
||||
if !isPad {
|
||||
Text("Ambient Sounds")
|
||||
.sectionTitleStyle()
|
||||
}
|
||||
|
||||
// Playback controls - always visible when sound is selected
|
||||
if selectedSound != nil {
|
||||
@ -81,7 +93,8 @@ struct NoiseView: View {
|
||||
ScrollView {
|
||||
SoundCategoryView(
|
||||
sounds: viewModel.availableSounds,
|
||||
selectedSound: $selectedSound
|
||||
selectedSound: $selectedSound,
|
||||
searchText: $searchText
|
||||
)
|
||||
.contentPadding(horizontal: Design.Spacing.large, vertical: Design.Spacing.large)
|
||||
}
|
||||
@ -92,8 +105,10 @@ struct NoiseView: View {
|
||||
HStack(spacing: Design.Spacing.large) {
|
||||
// Left side: Player controls
|
||||
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
|
||||
Text("Ambient Sounds")
|
||||
.sectionTitleStyle()
|
||||
if !isPad {
|
||||
Text("Ambient Sounds")
|
||||
.sectionTitleStyle()
|
||||
}
|
||||
|
||||
if selectedSound != nil {
|
||||
soundControlView
|
||||
@ -123,7 +138,8 @@ struct NoiseView: View {
|
||||
ScrollView {
|
||||
SoundCategoryView(
|
||||
sounds: viewModel.availableSounds,
|
||||
selectedSound: $selectedSound
|
||||
selectedSound: $selectedSound,
|
||||
searchText: $searchText
|
||||
)
|
||||
.contentPadding(horizontal: Design.Spacing.large, vertical: Design.Spacing.large)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user