Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
9247c36721
commit
41578f0941
@ -24,60 +24,63 @@ struct AlarmView: View {
|
|||||||
ZStack {
|
ZStack {
|
||||||
AppSurface.primary.ignoresSafeArea()
|
AppSurface.primary.ignoresSafeArea()
|
||||||
|
|
||||||
Group {
|
GeometryReader { geometry in
|
||||||
if viewModel.alarms.isEmpty {
|
let isLandscape = geometry.size.width > geometry.size.height
|
||||||
VStack(spacing: Design.Spacing.large) {
|
let maxWidth = isLandscape ? Design.Size.maxContentWidthLandscape : Design.Size.maxContentWidthPortrait
|
||||||
if !isKeepAwakeEnabled {
|
|
||||||
AlarmLimitationsBanner()
|
|
||||||
}
|
|
||||||
|
|
||||||
EmptyAlarmsView {
|
Group {
|
||||||
showAddAlarm = true
|
if viewModel.alarms.isEmpty {
|
||||||
|
VStack(spacing: Design.Spacing.large) {
|
||||||
|
if !isKeepAwakeEnabled {
|
||||||
|
AlarmLimitationsBanner()
|
||||||
|
}
|
||||||
|
|
||||||
|
EmptyAlarmsView {
|
||||||
|
showAddAlarm = true
|
||||||
|
}
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.onTapGesture {
|
||||||
|
showAddAlarm = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.contentShape(Rectangle())
|
} else {
|
||||||
.onTapGesture {
|
List {
|
||||||
showAddAlarm = true
|
if !isKeepAwakeEnabled {
|
||||||
}
|
AlarmLimitationsBanner()
|
||||||
}
|
.listRowInsets(EdgeInsets(top: Design.Spacing.large, leading: Design.Spacing.large, bottom: Design.Spacing.small, trailing: Design.Spacing.large))
|
||||||
.frame(maxWidth: Design.Size.maxContentWidthPortrait)
|
.listRowBackground(Color.clear)
|
||||||
.frame(maxWidth: .infinity, alignment: .center)
|
.listRowSeparator(.hidden)
|
||||||
} else {
|
}
|
||||||
List {
|
|
||||||
if !isKeepAwakeEnabled {
|
ForEach(viewModel.alarms) { alarm in
|
||||||
AlarmLimitationsBanner()
|
AlarmRowView(
|
||||||
.listRowInsets(EdgeInsets(top: Design.Spacing.large, leading: Design.Spacing.large, bottom: Design.Spacing.small, trailing: Design.Spacing.large))
|
alarm: alarm,
|
||||||
|
onToggle: {
|
||||||
|
Task {
|
||||||
|
await viewModel.toggleAlarm(id: alarm.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEdit: {
|
||||||
|
selectedAlarmForEdit = alarm
|
||||||
|
},
|
||||||
|
onDelete: {
|
||||||
|
Task {
|
||||||
|
await viewModel.deleteAlarm(id: alarm.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.listRowInsets(EdgeInsets(top: Design.Spacing.small, leading: Design.Spacing.large, bottom: Design.Spacing.small, trailing: Design.Spacing.large))
|
||||||
.listRowBackground(Color.clear)
|
.listRowBackground(Color.clear)
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.listStyle(.plain)
|
||||||
ForEach(viewModel.alarms) { alarm in
|
.scrollContentBackground(.hidden)
|
||||||
AlarmRowView(
|
.background(AppSurface.primary.ignoresSafeArea())
|
||||||
alarm: alarm,
|
|
||||||
onToggle: {
|
|
||||||
Task {
|
|
||||||
await viewModel.toggleAlarm(id: alarm.id)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onEdit: {
|
|
||||||
selectedAlarmForEdit = alarm
|
|
||||||
},
|
|
||||||
onDelete: {
|
|
||||||
Task {
|
|
||||||
await viewModel.deleteAlarm(id: alarm.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.listRowInsets(EdgeInsets(top: Design.Spacing.small, leading: Design.Spacing.large, bottom: Design.Spacing.small, trailing: Design.Spacing.large))
|
|
||||||
.listRowBackground(Color.clear)
|
|
||||||
.listRowSeparator(.hidden)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.listStyle(.plain)
|
|
||||||
.scrollContentBackground(.hidden)
|
|
||||||
.background(AppSurface.primary.ignoresSafeArea())
|
|
||||||
.frame(maxWidth: Design.Size.maxContentWidthPortrait)
|
|
||||||
.frame(maxWidth: .infinity, alignment: .center)
|
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: maxWidth)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle(isPad ? "" : "Alarms")
|
.navigationTitle(isPad ? "" : "Alarms")
|
||||||
|
|||||||
@ -37,25 +37,50 @@ struct NoiseView: View {
|
|||||||
let isLandscape = geometry.size.width > geometry.size.height
|
let isLandscape = geometry.size.width > geometry.size.height
|
||||||
let maxWidth = isLandscape ? Design.Size.maxContentWidthLandscape : Design.Size.maxContentWidthPortrait
|
let maxWidth = isLandscape ? Design.Size.maxContentWidthLandscape : Design.Size.maxContentWidthPortrait
|
||||||
|
|
||||||
Group {
|
VStack(spacing: 0) {
|
||||||
if isLandscape {
|
// Custom Search Bar - Constrained to maxWidth
|
||||||
// Landscape layout: Player on left, sounds on right
|
HStack {
|
||||||
landscapeLayout
|
HStack(spacing: Design.Spacing.small) {
|
||||||
} else {
|
Image(systemName: "magnifyingglass")
|
||||||
// Portrait layout: Stacked vertically
|
.foregroundColor(AppTextColors.secondary)
|
||||||
portraitLayout
|
|
||||||
|
TextField("Search sounds", text: $searchText)
|
||||||
|
.textFieldStyle(.plain)
|
||||||
|
.foregroundColor(AppTextColors.primary)
|
||||||
|
|
||||||
|
if !searchText.isEmpty {
|
||||||
|
Button(action: { searchText = "" }) {
|
||||||
|
Image(systemName: "xmark.circle.fill")
|
||||||
|
.foregroundColor(AppTextColors.tertiary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(Design.Spacing.small)
|
||||||
|
.background(AppSurface.overlay)
|
||||||
|
.cornerRadius(Design.CornerRadius.medium)
|
||||||
}
|
}
|
||||||
|
.padding(.horizontal, Design.Spacing.large)
|
||||||
|
.padding(.top, Design.Spacing.medium)
|
||||||
|
.padding(.bottom, Design.Spacing.small)
|
||||||
|
.frame(maxWidth: maxWidth)
|
||||||
|
|
||||||
|
Group {
|
||||||
|
if isLandscape {
|
||||||
|
// Landscape layout: Player on left, sounds on right
|
||||||
|
landscapeLayout
|
||||||
|
} else {
|
||||||
|
// Portrait layout: Stacked vertically
|
||||||
|
portraitLayout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: maxWidth)
|
||||||
}
|
}
|
||||||
.frame(maxWidth: maxWidth)
|
|
||||||
.frame(maxWidth: .infinity, alignment: .center)
|
.frame(maxWidth: .infinity, alignment: .center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.navigationTitle("Noise")
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.animation(.easeInOut(duration: 0.3), value: selectedSound)
|
.animation(.easeInOut(duration: 0.3), value: selectedSound)
|
||||||
.searchable(
|
|
||||||
text: $searchText,
|
|
||||||
placement: .navigationBarDrawer(displayMode: .automatic),
|
|
||||||
prompt: "Search sounds"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Computed Properties
|
// MARK: - Computed Properties
|
||||||
@ -82,6 +107,7 @@ struct NoiseView: View {
|
|||||||
if selectedSound != nil {
|
if selectedSound != nil {
|
||||||
soundControlView
|
soundControlView
|
||||||
.centered()
|
.centered()
|
||||||
|
.padding(.bottom, Design.Spacing.medium)
|
||||||
} else {
|
} else {
|
||||||
// Placeholder when no sound selected - Enhanced for CRO
|
// Placeholder when no sound selected - Enhanced for CRO
|
||||||
VStack(spacing: Design.Spacing.medium) {
|
VStack(spacing: Design.Spacing.medium) {
|
||||||
@ -108,27 +134,31 @@ struct NoiseView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding(.vertical, Design.Spacing.xLarge)
|
.padding(.vertical, Design.Spacing.large)
|
||||||
.background(AppSurface.overlay, in: RoundedRectangle(cornerRadius: Design.CornerRadius.appLarge))
|
.background(AppSurface.overlay, in: RoundedRectangle(cornerRadius: Design.CornerRadius.appLarge))
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: Design.CornerRadius.appLarge)
|
RoundedRectangle(cornerRadius: Design.CornerRadius.appLarge)
|
||||||
.stroke(AppBorder.subtle, lineWidth: Design.LineWidth.thin)
|
.stroke(AppBorder.subtle, lineWidth: Design.LineWidth.thin)
|
||||||
)
|
)
|
||||||
|
.padding(.bottom, Design.Spacing.medium)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.contentPadding(horizontal: Design.Spacing.large)
|
.padding(.horizontal, Design.Spacing.large)
|
||||||
.padding(.top, Design.Spacing.large)
|
.padding(.top, Design.Spacing.small)
|
||||||
.background(AppSurface.primary)
|
.background(AppSurface.primary)
|
||||||
|
|
||||||
// Scrollable sound selection
|
// Scrollable sound selection
|
||||||
ScrollView {
|
List {
|
||||||
SoundCategoryView(
|
SoundCategoryView(
|
||||||
sounds: viewModel.availableSounds,
|
sounds: viewModel.availableSounds,
|
||||||
selectedSound: $selectedSound,
|
selectedSound: $selectedSound,
|
||||||
searchText: $searchText
|
searchText: $searchText
|
||||||
)
|
)
|
||||||
.contentPadding(horizontal: Design.Spacing.large, vertical: Design.Spacing.large)
|
.listRowInsets(EdgeInsets(top: 0, leading: Design.Spacing.large, bottom: Design.Spacing.large, trailing: Design.Spacing.large))
|
||||||
|
.listRowBackground(Color.clear)
|
||||||
|
.listRowSeparator(.hidden)
|
||||||
}
|
}
|
||||||
|
.listStyle(.plain)
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,8 @@ struct OnboardingView: View {
|
|||||||
.padding(.horizontal, Design.Spacing.xLarge)
|
.padding(.horizontal, Design.Spacing.xLarge)
|
||||||
.padding(.bottom, Design.Spacing.xxLarge)
|
.padding(.bottom, Design.Spacing.xxLarge)
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: Design.Size.maxContentWidthPortrait)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,9 +115,9 @@ struct OnboardingView: View {
|
|||||||
Text(text)
|
Text(text)
|
||||||
.typography(.body)
|
.typography(.body)
|
||||||
.foregroundStyle(AppTextColors.secondary)
|
.foregroundStyle(AppTextColors.secondary)
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: 320, alignment: .leading) // Constrain width and align content to leading
|
||||||
|
.frame(maxWidth: .infinity, alignment: .center) // Center the constrained box in the parent
|
||||||
.padding(.horizontal, Design.Spacing.xxLarge)
|
.padding(.horizontal, Design.Spacing.xxLarge)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,9 +221,9 @@ struct OnboardingView: View {
|
|||||||
Text(text)
|
Text(text)
|
||||||
.typography(.body)
|
.typography(.body)
|
||||||
.foregroundStyle(AppTextColors.secondary)
|
.foregroundStyle(AppTextColors.secondary)
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: 320, alignment: .leading) // Constrain width and align content to leading
|
||||||
|
.frame(maxWidth: .infinity, alignment: .center) // Center the constrained box in the parent
|
||||||
.padding(.horizontal, Design.Spacing.xxLarge)
|
.padding(.horizontal, Design.Spacing.xxLarge)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,6 +313,8 @@ struct OnboardingView: View {
|
|||||||
.typography(.callout)
|
.typography(.callout)
|
||||||
.foregroundStyle(AppTextColors.secondary)
|
.foregroundStyle(AppTextColors.secondary)
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: 320, alignment: .leading) // Constrain width and align content to leading
|
||||||
|
.frame(maxWidth: .infinity, alignment: .center) // Center the constrained box in the parent
|
||||||
.padding(.horizontal, Design.Spacing.xxLarge)
|
.padding(.horizontal, Design.Spacing.xxLarge)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user