From 84c0e191b10b05fa4a21c2afaf1e348daf0a8e1b Mon Sep 17 00:00:00 2001 From: Trey t Date: Wed, 10 Dec 2025 09:53:51 -0600 Subject: [PATCH] inisights use selected theme --- .../Views/CustomizeView/CustomizeView.swift | 744 +++++++++++++++++- Shared/Views/InsightsView/InsightsView.swift | 37 +- 2 files changed, 735 insertions(+), 46 deletions(-) diff --git a/Shared/Views/CustomizeView/CustomizeView.swift b/Shared/Views/CustomizeView/CustomizeView.swift index f0dc4b9..0de20ce 100644 --- a/Shared/Views/CustomizeView/CustomizeView.swift +++ b/Shared/Views/CustomizeView/CustomizeView.swift @@ -6,37 +6,88 @@ // import SwiftUI +import StoreKit struct CustomizeView: View { @State private var showSettings = false - + @State private var showSubscriptionStore = false + @EnvironmentObject var iapManager: IAPManager + @Environment(\.colorScheme) private var colorScheme + @AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system - + @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor + var body: some View { ScrollView { - settingsButtonView - VStack { - Group { - CustomWigetView() - IconPickerView() - ThemePickerView() - Divider() - VotingLayoutPickerView() - Divider() - SampleEntryView() - ImagePackPickerView() + VStack(spacing: 24) { + // Header + headerView + + // Subscription Banner + SubscriptionBannerView(showSubscriptionStore: $showSubscriptionStore) + .environmentObject(iapManager) + + // Preview showing current style + SampleEntryView() + + // APPEARANCE + SettingsSection(title: "Appearance") { + VStack(spacing: 16) { + // Theme + SettingsRow(title: "Theme") { + ThemePickerCompact() + } + + Divider() + + // Text Color + SettingsRow(title: "Text Color") { + TextColorPickerCompact() + } + } } - Group { - TintPickerView() - TextColorPickerView() + + // MOOD STYLE + SettingsSection(title: "Mood Style") { + VStack(spacing: 16) { + // Icon Style + SettingsRow(title: "Icons") { + ImagePackPickerCompact() + } + + Divider() + + // Mood Colors + SettingsRow(title: "Colors") { + TintPickerCompact() + } + + Divider() + + // Voting Layout + SettingsRow(title: "Voting Layout") { + VotingLayoutPickerCompact() + } + } + } + + // WIDGETS + SettingsSection(title: "Widgets") { + CustomWidgetSection() + } + + // NOTIFICATIONS + SettingsSection(title: "Notifications") { + PersonalityPackPickerCompact() + } + + // FILTERS + SettingsSection(title: "Day Filter") { + DayFilterPickerCompact() } - Divider() - DayFilterPickerView() - Divider() - ShapePickerView() - Divider() - PersonalityPackPickerView() } + .padding(.horizontal, 16) + .padding(.bottom, 32) } .onAppear(perform: { EventLogger.log(event: "show_customize_view") @@ -44,23 +95,656 @@ struct CustomizeView: View { .sheet(isPresented: $showSettings) { SettingsView() } - .padding() + .sheet(isPresented: $showSubscriptionStore) { + FeelsSubscriptionStoreView() + } .background( theme.currentTheme.bg .edgesIgnoringSafeArea(.all) ) } - - private var settingsButtonView: some View { + + private var headerView: some View { HStack { + Text("Customize") + .font(.system(size: 28, weight: .bold, design: .rounded)) + .foregroundColor(textColor) + Spacer() + Button(action: { showSettings.toggle() - }, label: { + }) { Image(systemName: "gear") - .foregroundColor(Color(UIColor.darkGray)) .font(.system(size: 20)) - }).padding(.trailing) + .foregroundColor(textColor.opacity(0.6)) + } + } + .padding(.top, 8) + } +} + +// MARK: - Settings Section +struct SettingsSection: View { + let title: String + @ViewBuilder let content: Content + + @Environment(\.colorScheme) private var colorScheme + @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor + + var body: some View { + VStack(alignment: .leading, spacing: 12) { + Text(title.uppercased()) + .font(.system(size: 13, weight: .semibold)) + .foregroundColor(textColor.opacity(0.4)) + .tracking(0.5) + + VStack(spacing: 0) { + content + } + .padding(16) + .background( + RoundedRectangle(cornerRadius: 16) + .fill(colorScheme == .dark ? Color(.systemGray6) : .white) + ) + } + } +} + +// MARK: - Settings Row +struct SettingsRow: View { + let title: String + @ViewBuilder let content: Content + + @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor + + var body: some View { + VStack(alignment: .leading, spacing: 12) { + Text(title) + .font(.system(size: 15, weight: .medium)) + .foregroundColor(textColor.opacity(0.7)) + + content + } + } +} + +// MARK: - Theme Picker +struct ThemePickerCompact: View { + @Environment(\.colorScheme) var colorScheme + @AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system + @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor + + var body: some View { + HStack(spacing: 20) { + ForEach(Theme.allCases, id: \.rawValue) { aTheme in + Button(action: { + theme = aTheme + changeTextColor(forTheme: aTheme) + EventLogger.log(event: "change_theme_id", withData: ["id": aTheme.rawValue]) + }) { + VStack(spacing: 8) { + ZStack { + aTheme.currentTheme.preview + .overlay( + Circle() + .stroke(theme == aTheme ? Color.accentColor : Color(.systemGray4), lineWidth: 2) + ) + + if theme == aTheme { + Image(systemName: "checkmark.circle.fill") + .font(.system(size: 18)) + .foregroundColor(.accentColor) + .background(Circle().fill(.white).padding(2)) + .offset(x: 14, y: 14) + } + } + + Text(aTheme.title) + .font(.system(size: 12, weight: .medium)) + .foregroundColor(theme == aTheme ? .accentColor : textColor.opacity(0.6)) + } + } + .buttonStyle(.plain) + } + Spacer() + } + } + + private func changeTextColor(forTheme theme: Theme) { + if [Theme.iFeel, Theme.system].contains(theme) { + let currentSystemScheme = UITraitCollection.current.userInterfaceStyle + textColor = currentSystemScheme == .dark ? .white : .black + } + if theme == Theme.dark { textColor = .white } + if theme == Theme.light { textColor = .black } + } +} + +// MARK: - Text Color Picker +struct TextColorPickerCompact: View { + @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor + + var body: some View { + HStack(spacing: 16) { + ColorPicker("", selection: $textColor) + .labelsHidden() + + Text("Sample Text") + .font(.system(size: 16, weight: .medium)) + .foregroundColor(textColor) + + Spacer() + } + } +} + +// MARK: - Image Pack Picker +struct ImagePackPickerCompact: View { + @AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default + @AppStorage(UserDefaultsStore.Keys.moodImages.rawValue, store: GroupUserDefaults.groupDefaults) private var imagePack: MoodImages = .FontAwesome + @AppStorage(UserDefaultsStore.Keys.customMoodTintUpdateNumber.rawValue, store: GroupUserDefaults.groupDefaults) private var customMoodTintUpdateNumber: Int = 0 + @Environment(\.colorScheme) private var colorScheme + + var body: some View { + Text(String(customMoodTintUpdateNumber)).hidden().frame(height: 0) + + VStack(spacing: 8) { + ForEach(MoodImages.allCases, id: \.rawValue) { images in + Button(action: { + let impactMed = UIImpactFeedbackGenerator(style: .medium) + impactMed.impactOccurred() + imagePack = images + EventLogger.log(event: "change_image_pack_id", withData: ["id": images.rawValue]) + }) { + HStack { + HStack(spacing: 16) { + ForEach(Mood.allValues, id: \.self) { mood in + images.icon(forMood: mood) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 28, height: 28) + .foregroundColor(moodTint.color(forMood: mood)) + } + } + + Spacer() + + if imagePack == images { + Image(systemName: "checkmark.circle.fill") + .font(.system(size: 22)) + .foregroundColor(.accentColor) + } + } + .padding(14) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(imagePack == images + ? Color.accentColor.opacity(0.08) + : (colorScheme == .dark ? Color(.systemGray5) : Color(.systemGray6))) + ) + } + .buttonStyle(.plain) + } + } + } +} + +// MARK: - Tint Picker +struct TintPickerCompact: View { + @AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default + @AppStorage(UserDefaultsStore.Keys.customMoodTintUpdateNumber.rawValue, store: GroupUserDefaults.groupDefaults) private var customMoodTintUpdateNumber: Int = 0 + @StateObject private var customMoodTint = UserDefaultsStore.getCustomMoodTint() + @Environment(\.colorScheme) private var colorScheme + + var body: some View { + VStack(spacing: 8) { + ForEach(MoodTints.defaultOptions, id: \.rawValue) { tint in + Button(action: { + let impactMed = UIImpactFeedbackGenerator(style: .medium) + impactMed.impactOccurred() + moodTint = tint + EventLogger.log(event: "change_mood_tint_id", withData: ["id": tint.rawValue]) + }) { + HStack { + HStack(spacing: 12) { + ForEach(Mood.allValues, id: \.self) { mood in + Circle() + .fill(tint.color(forMood: mood)) + .frame(width: 28, height: 28) + } + } + + Spacer() + + if moodTint == tint { + Image(systemName: "checkmark.circle.fill") + .font(.system(size: 22)) + .foregroundColor(.accentColor) + } + } + .padding(14) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(moodTint == tint + ? Color.accentColor.opacity(0.08) + : (colorScheme == .dark ? Color(.systemGray5) : Color(.systemGray6))) + ) + } + .buttonStyle(.plain) + } + + // Custom colors + Button(action: { + moodTint = .Custom + }) { + HStack { + HStack(spacing: 12) { + ForEach(0..<5, id: \.self) { index in + ColorPicker("", selection: colorBinding(for: index)) + .labelsHidden() + .onChange(of: colorBinding(for: index).wrappedValue) { _ in + saveCustomMoodTint() + } + } + } + + Spacer() + + if moodTint == .Custom { + Image(systemName: "checkmark.circle.fill") + .font(.system(size: 22)) + .foregroundColor(.accentColor) + } else { + Text("Custom") + .font(.system(size: 13)) + .foregroundColor(.secondary) + } + } + .padding(14) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(moodTint == .Custom + ? Color.accentColor.opacity(0.08) + : (colorScheme == .dark ? Color(.systemGray5) : Color(.systemGray6))) + ) + } + .buttonStyle(.plain) + } + } + + private func colorBinding(for index: Int) -> Binding { + switch index { + case 0: return $customMoodTint.colorOne + case 1: return $customMoodTint.colorTwo + case 2: return $customMoodTint.colorThree + case 3: return $customMoodTint.colorFour + default: return $customMoodTint.colorFive + } + } + + private func saveCustomMoodTint() { + UserDefaultsStore.saveCustomMoodTint(customTint: customMoodTint) + moodTint = .Custom + EventLogger.log(event: "change_mood_tint_id", withData: ["id": MoodTints.Custom.rawValue]) + customMoodTintUpdateNumber += 1 + } +} + +// MARK: - Voting Layout Picker +struct VotingLayoutPickerCompact: View { + @AppStorage(UserDefaultsStore.Keys.votingLayoutStyle.rawValue, store: GroupUserDefaults.groupDefaults) private var votingLayoutStyle: Int = 0 + @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor + @Environment(\.colorScheme) private var colorScheme + + private var currentLayout: VotingLayoutStyle { + VotingLayoutStyle(rawValue: votingLayoutStyle) ?? .horizontal + } + + var body: some View { + HStack(spacing: 10) { + ForEach(VotingLayoutStyle.allCases, id: \.rawValue) { layout in + Button(action: { + withAnimation(.easeInOut(duration: 0.2)) { + votingLayoutStyle = layout.rawValue + } + EventLogger.log(event: "change_voting_layout", withData: ["layout": layout.displayName]) + }) { + VStack(spacing: 6) { + layoutIcon(for: layout) + .frame(width: 44, height: 44) + .foregroundColor(currentLayout == layout ? .accentColor : textColor.opacity(0.4)) + + Text(layout.displayName) + .font(.system(size: 11, weight: .medium)) + .foregroundColor(currentLayout == layout ? .accentColor : textColor.opacity(0.5)) + } + .frame(maxWidth: .infinity) + .padding(.vertical, 12) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(currentLayout == layout + ? Color.accentColor.opacity(0.1) + : (colorScheme == .dark ? Color(.systemGray5) : Color(.systemGray6))) + ) + } + .buttonStyle(.plain) + } + } + } + + @ViewBuilder + private func layoutIcon(for layout: VotingLayoutStyle) -> some View { + switch layout { + case .horizontal: + HStack(spacing: 4) { + ForEach(0..<5, id: \.self) { _ in Circle().frame(width: 7, height: 7) } + } + case .cards: + LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())], spacing: 4) { + ForEach(0..<6, id: \.self) { _ in RoundedRectangle(cornerRadius: 3).frame(width: 10, height: 12) } + } + case .radial: + ZStack { + ForEach(0..<5, id: \.self) { index in + Circle() + .frame(width: 7, height: 7) + .offset(radialOffset(index: index, total: 5, radius: 15)) + } + } + case .stacked: + VStack(spacing: 4) { + ForEach(0..<4, id: \.self) { _ in RoundedRectangle(cornerRadius: 2).frame(width: 32, height: 7) } + } + } + } + + private func radialOffset(index: Int, total: Int, radius: CGFloat) -> CGSize { + let angle = Double.pi - (Double.pi * Double(index) / Double(total - 1)) + return CGSize(width: radius * CGFloat(cos(angle)), height: -radius * CGFloat(sin(angle)) + 4) + } +} + +// MARK: - Custom Widget Section +struct CustomWidgetSection: View { + @AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system + @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor + @StateObject private var selectedWidget = StupidAssCustomWidgetObservableObject() + + var body: some View { + VStack(spacing: 12) { + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 12) { + ForEach(UserDefaultsStore.getCustomWidgets(), id: \.uuid) { widget in + CustomWidgetView(customWidgetModel: widget) + .frame(width: 60, height: 60) + .cornerRadius(12) + .onTapGesture { + EventLogger.log(event: "show_widget") + selectedWidget.fuckingWrapped = widget.copy() as? CustomWidgetModel + selectedWidget.showFuckingSheet = true + } + } + + // Add button + Button(action: { + EventLogger.log(event: "tap_create_new_widget") + selectedWidget.fuckingWrapped = CustomWidgetModel.randomWidget + selectedWidget.showFuckingSheet = true + }) { + ZStack { + RoundedRectangle(cornerRadius: 12) + .fill(Color(.systemGray5)) + .frame(width: 60, height: 60) + + Image(systemName: "plus") + .font(.system(size: 24, weight: .medium)) + .foregroundColor(.secondary) + } + } + } + } + + Link(destination: URL(string: "https://support.apple.com/guide/iphone/add-widgets-iphb8f1bf206/ios")!) { + HStack(spacing: 6) { + Image(systemName: "questionmark.circle") + .font(.system(size: 14)) + Text("How to add widgets") + .font(.system(size: 14)) + } + .foregroundColor(.accentColor) + } + } + .sheet(isPresented: $selectedWidget.showFuckingSheet) { + if let fuckingWrapped = selectedWidget.fuckingWrapped { + CreateWidgetView(customWidget: fuckingWrapped) + } + } + } +} + +// MARK: - Personality Pack Picker +struct PersonalityPackPickerCompact: View { + @AppStorage(UserDefaultsStore.Keys.personalityPack.rawValue, store: GroupUserDefaults.groupDefaults) private var personalityPack: PersonalityPack = .Default + @AppStorage(UserDefaultsStore.Keys.showNSFW.rawValue, store: GroupUserDefaults.groupDefaults) private var showNSFW: Bool = false + @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor + @State private var showOver18Alert = false + @Environment(\.colorScheme) private var colorScheme + + var body: some View { + VStack(spacing: 8) { + ForEach(PersonalityPack.allCases, id: \.self) { aPack in + Button(action: { + if aPack.rawValue == PersonalityPack.Rude.rawValue && !showNSFW { + showOver18Alert = true + EventLogger.log(event: "show_over_18_alert") + } else { + let impactMed = UIImpactFeedbackGenerator(style: .medium) + impactMed.impactOccurred() + personalityPack = aPack + EventLogger.log(event: "change_personality_pack", withData: ["pack_title": aPack.title()]) + LocalNotification.rescheduleNotifiations() + } + }) { + HStack { + VStack(alignment: .leading, spacing: 4) { + Text(String(aPack.title())) + .font(.system(size: 15, weight: .semibold)) + .foregroundColor(textColor) + + let strings = aPack.randomPushNotificationStrings() + Text(strings.body) + .font(.system(size: 13)) + .foregroundColor(textColor.opacity(0.5)) + .lineLimit(2) + } + + Spacer() + + if personalityPack == aPack { + Image(systemName: "checkmark.circle.fill") + .font(.system(size: 22)) + .foregroundColor(.accentColor) + } + } + .padding(14) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(personalityPack == aPack + ? Color.accentColor.opacity(0.08) + : (colorScheme == .dark ? Color(.systemGray5) : Color(.systemGray6))) + ) + } + .buttonStyle(.plain) + .blur(radius: aPack.rawValue == PersonalityPack.Rude.rawValue && !showNSFW ? 4 : 0) + } + } + .alert(isPresented: $showOver18Alert) { + Alert( + title: Text(String(localized: "customize_view_over18alert_title")), + message: Text(String(localized: "customize_view_over18alert_body")), + primaryButton: .default(Text(String(localized: "customize_view_over18alert_ok"))) { + showNSFW = true + }, + secondaryButton: .cancel(Text(String(localized: "customize_view_over18alert_no"))) { + showNSFW = false + } + ) + } + } +} + +// MARK: - Day Filter Picker +struct DayFilterPickerCompact: View { + @StateObject private var filteredDays = DaysFilterClass.shared + @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor + @Environment(\.colorScheme) private var colorScheme + + let weekdays = [(Calendar.current.shortWeekdaySymbols[0], 1), + (Calendar.current.shortWeekdaySymbols[1], 2), + (Calendar.current.shortWeekdaySymbols[2], 3), + (Calendar.current.shortWeekdaySymbols[3], 4), + (Calendar.current.shortWeekdaySymbols[4], 5), + (Calendar.current.shortWeekdaySymbols[5], 6), + (Calendar.current.shortWeekdaySymbols[6], 7)] + + var body: some View { + VStack(spacing: 14) { + HStack(spacing: 8) { + ForEach(weekdays.indices, id: \.self) { dayIdx in + let day = String(weekdays[dayIdx].0) + let value = weekdays[dayIdx].1 + let isActive = filteredDays.currentFilters.contains(value) + + Button(action: { + if isActive { + filteredDays.removeFilter(filter: value) + } else { + filteredDays.addFilter(newFilter: value) + } + let impactMed = UIImpactFeedbackGenerator(style: .medium) + impactMed.impactOccurred() + }) { + Text(day.prefix(2).uppercased()) + .font(.system(size: 13, weight: .semibold)) + .foregroundColor(isActive ? .white : textColor.opacity(0.5)) + .frame(maxWidth: .infinity) + .frame(height: 40) + .background( + RoundedRectangle(cornerRadius: 10) + .fill(isActive ? Color.accentColor : (colorScheme == .dark ? Color(.systemGray5) : Color(.systemGray6))) + ) + } + .buttonStyle(.plain) + } + } + + Text(String(localized: "day_picker_view_text")) + .font(.system(size: 13)) + .foregroundColor(textColor.opacity(0.5)) + .multilineTextAlignment(.center) + } + } +} + +// MARK: - Subscription Banner +struct SubscriptionBannerView: View { + @Binding var showSubscriptionStore: Bool + @EnvironmentObject var iapManager: IAPManager + @Environment(\.colorScheme) private var colorScheme + + var body: some View { + if iapManager.isSubscribed { + subscribedView + } else { + notSubscribedView + } + } + + private var subscribedView: some View { + HStack(spacing: 12) { + Image(systemName: "checkmark.seal.fill") + .font(.system(size: 28)) + .foregroundColor(.green) + + VStack(alignment: .leading, spacing: 2) { + Text("Premium Active") + .font(.system(size: 16, weight: .semibold)) + + Text("You have full access") + .font(.system(size: 13)) + .foregroundColor(.secondary) + } + + Spacer() + + Button("Manage") { + Task { + await openSubscriptionManagement() + } + } + .font(.system(size: 14, weight: .semibold)) + .foregroundColor(.green) + .padding(.horizontal, 16) + .padding(.vertical, 8) + .background(Capsule().fill(Color.green.opacity(0.15))) + } + .padding(16) + .background( + RoundedRectangle(cornerRadius: 16) + .fill(colorScheme == .dark ? Color(.systemGray6) : .white) + ) + } + + private var notSubscribedView: some View { + Button(action: { + EventLogger.log(event: "customize_subscribe_tapped") + showSubscriptionStore = true + }) { + HStack(spacing: 12) { + Image(systemName: "crown.fill") + .font(.system(size: 28)) + .foregroundColor(.orange) + + VStack(alignment: .leading, spacing: 2) { + Text("Unlock Premium") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(colorScheme == .dark ? .white : .black) + + Text("Month & Year views, Insights & more") + .font(.system(size: 13)) + .foregroundColor(.secondary) + } + + Spacer() + + Image(systemName: "chevron.right") + .font(.system(size: 14, weight: .semibold)) + .foregroundColor(.secondary) + } + .padding(16) + .contentShape(Rectangle()) + .background( + RoundedRectangle(cornerRadius: 16) + .fill( + LinearGradient( + colors: [Color.orange.opacity(0.12), Color.pink.opacity(0.08)], + startPoint: .leading, + endPoint: .trailing + ) + ) + ) + } + .buttonStyle(.plain) + } + + private func openSubscriptionManagement() async { + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { + do { + try await AppStore.showManageSubscriptions(in: windowScene) + } catch { + print("Failed to open subscription management: \(error)") + } } } } @@ -69,9 +753,11 @@ struct CustomizeView_Previews: PreviewProvider { static var previews: some View { Group { CustomizeView() - + .environmentObject(IAPManager()) + CustomizeView() .preferredColorScheme(.dark) + .environmentObject(IAPManager()) } } } diff --git a/Shared/Views/InsightsView/InsightsView.swift b/Shared/Views/InsightsView/InsightsView.swift index 6221bbd..5d0782c 100644 --- a/Shared/Views/InsightsView/InsightsView.swift +++ b/Shared/Views/InsightsView/InsightsView.swift @@ -12,6 +12,7 @@ struct InsightsView: View { @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor @AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default @AppStorage(UserDefaultsStore.Keys.moodImages.rawValue, store: GroupUserDefaults.groupDefaults) private var imagePack: MoodImages = .FontAwesome + @Environment(\.colorScheme) private var colorScheme @StateObject private var viewModel = InsightsViewModel() @EnvironmentObject var iapManager: IAPManager @@ -24,7 +25,7 @@ struct InsightsView: View { // Header HStack { Text("Insights") - .font(.largeTitle.bold()) + .font(.system(size: 28, weight: .bold, design: .rounded)) .foregroundColor(textColor) Spacer() } @@ -38,7 +39,7 @@ struct InsightsView: View { textColor: textColor, moodTint: moodTint, imagePack: imagePack, - theme: theme + colorScheme: colorScheme ) // This Year Section @@ -49,7 +50,7 @@ struct InsightsView: View { textColor: textColor, moodTint: moodTint, imagePack: imagePack, - theme: theme + colorScheme: colorScheme ) // All Time Section @@ -60,7 +61,7 @@ struct InsightsView: View { textColor: textColor, moodTint: moodTint, imagePack: imagePack, - theme: theme + colorScheme: colorScheme ) } .padding(.vertical) @@ -114,7 +115,7 @@ struct InsightsSectionView: View { let textColor: Color let moodTint: MoodTints let imagePack: MoodImages - let theme: Theme + let colorScheme: ColorScheme @State private var isExpanded = true @@ -124,18 +125,18 @@ struct InsightsSectionView: View { Button(action: { withAnimation(.easeInOut(duration: 0.2)) { isExpanded.toggle() } }) { HStack { Image(systemName: icon) - .font(.title3) - .foregroundColor(textColor.opacity(0.7)) + .font(.system(size: 18, weight: .medium)) + .foregroundColor(textColor.opacity(0.6)) Text(title) - .font(.title2.bold()) + .font(.system(size: 20, weight: .bold)) .foregroundColor(textColor) Spacer() Image(systemName: isExpanded ? "chevron.up" : "chevron.down") - .font(.caption.weight(.semibold)) - .foregroundColor(textColor.opacity(0.5)) + .font(.system(size: 12, weight: .semibold)) + .foregroundColor(textColor.opacity(0.4)) } .padding(.horizontal, 16) .padding(.vertical, 14) @@ -144,13 +145,14 @@ struct InsightsSectionView: View { // Insights List (collapsible) if isExpanded { - VStack(spacing: 12) { + VStack(spacing: 10) { ForEach(insights) { insight in InsightCardView( insight: insight, textColor: textColor, moodTint: moodTint, - imagePack: imagePack + imagePack: imagePack, + colorScheme: colorScheme ) } } @@ -161,7 +163,7 @@ struct InsightsSectionView: View { } .background( RoundedRectangle(cornerRadius: 16) - .fill(theme.currentTheme.secondaryBGColor) + .fill(colorScheme == .dark ? Color(.systemGray6) : .white) ) .padding(.horizontal) } @@ -173,12 +175,13 @@ struct InsightCardView: View { let textColor: Color let moodTint: MoodTints let imagePack: MoodImages + let colorScheme: ColorScheme private var accentColor: Color { if let mood = insight.mood { return moodTint.color(forMood: mood) } - return textColor.opacity(0.6) + return .accentColor } var body: some View { @@ -205,11 +208,11 @@ struct InsightCardView: View { // Text Content VStack(alignment: .leading, spacing: 4) { Text(insight.title) - .font(.subheadline.weight(.semibold)) + .font(.system(size: 15, weight: .semibold)) .foregroundColor(textColor) Text(insight.description) - .font(.subheadline) + .font(.system(size: 14)) .foregroundColor(textColor.opacity(0.7)) .fixedSize(horizontal: false, vertical: true) } @@ -219,7 +222,7 @@ struct InsightCardView: View { .padding(14) .background( RoundedRectangle(cornerRadius: 12) - .fill(accentColor.opacity(0.08)) + .fill(colorScheme == .dark ? Color(.systemGray5) : Color(.systemGray6)) ) } }