From dc99a3f1f0d377892b22871c3329b9487500f9a0 Mon Sep 17 00:00:00 2001 From: kutesir Date: Thu, 28 May 2026 20:35:44 +0300 Subject: [PATCH] fix: widget iOS 17 deployment target + register FloatingTabState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Widget extension: 16.0 → 17.0 (containerBackground/widget API require 17) - xcodegen re-run picks up FloatingTabState.swift (was on disk but not registered in project.pbxproj after previous xcodegen run) --- KisaniCal.xcodeproj/project.pbxproj | 8 ++- .../UserInterfaceState.xcuserstate | Bin 0 -> 25582 bytes KisaniCal/Components/FloatingTabState.swift | 52 ++++++++++++++++++ KisaniCal/ContentView.swift | 16 ++++-- KisaniCal/Views/MatrixView.swift | 1 + KisaniCal/Views/SettingsView.swift | 1 + KisaniCal/Views/TodayView.swift | 1 + KisaniCal/Views/WorkoutView.swift | 1 + project.yml | 2 +- 9 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 KisaniCal.xcodeproj/project.xcworkspace/xcuserdata/kutesir.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 KisaniCal/Components/FloatingTabState.swift diff --git a/KisaniCal.xcodeproj/project.pbxproj b/KisaniCal.xcodeproj/project.pbxproj index 9216fb1..02210a5 100644 --- a/KisaniCal.xcodeproj/project.pbxproj +++ b/KisaniCal.xcodeproj/project.pbxproj @@ -26,6 +26,7 @@ BEAFF968632A34C70B11C5AC /* MatrixView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44530A77DF12A17E52AAF34 /* MatrixView.swift */; }; C1B3FC29820FCAF069D2C6FE /* KisaniCalWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C519927190A5CDB3CD4A8 /* KisaniCalWidget.swift */; }; C79C33BE2802E81AA00175CC /* TodayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C786EBC7DF879D64EB28165E /* TodayView.swift */; }; + CBE7295BF5ADE08FE93AFAAF /* FloatingTabState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9100804DB1E61EA882CC54DA /* FloatingTabState.swift */; }; CF130E143FC6FFE2FE853FB6 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3364C849866EAAA5FEB46A1 /* WidgetDataStore.swift */; }; D591A72235A53D4038FBC2B4 /* KisaniCalApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 001F67ADC72FBAEC03EB7E01 /* KisaniCalApp.swift */; }; EF03EC9F974B14D100DD5528 /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D045FE3DEB1D22D908A29F /* NotificationManager.swift */; }; @@ -70,6 +71,7 @@ 768D4E314252E2A90A06CCF2 /* AddExerciseSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddExerciseSheet.swift; sourceTree = ""; }; 825C519927190A5CDB3CD4A8 /* KisaniCalWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KisaniCalWidget.swift; sourceTree = ""; }; 8934E4F21B90C9650F71D0A2 /* WidgetBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetBridge.swift; sourceTree = ""; }; + 9100804DB1E61EA882CC54DA /* FloatingTabState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingTabState.swift; sourceTree = ""; }; 93D045FE3DEB1D22D908A29F /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = ""; }; 9BD1F84B4F45B12CB9B9F1B2 /* KisaniCal.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = KisaniCal.app; sourceTree = BUILT_PRODUCTS_DIR; }; A3364C849866EAAA5FEB46A1 /* WidgetDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDataStore.swift; sourceTree = ""; }; @@ -95,6 +97,7 @@ 21B93C269F283F11B415B18C /* Components */ = { isa = PBXGroup; children = ( + 9100804DB1E61EA882CC54DA /* FloatingTabState.swift */, 23A4491BFA50721082024756 /* SharedComponents.swift */, ); path = Components; @@ -292,6 +295,7 @@ 13E4B9854F595394FC9D5912 /* ContentView.swift in Sources */, A9FF93259AE8FF0ABF69D71A /* DesignTokens.swift in Sources */, 1A22EE21460821170E44B1DF /* ExerciseModels.swift in Sources */, + CBE7295BF5ADE08FE93AFAAF /* FloatingTabState.swift in Sources */, D591A72235A53D4038FBC2B4 /* KisaniCalApp.swift in Sources */, BEAFF968632A34C70B11C5AC /* MatrixView.swift in Sources */, EF03EC9F974B14D100DD5528 /* NotificationManager.swift in Sources */, @@ -420,7 +424,7 @@ CODE_SIGN_STYLE = Automatic; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSExtensionPointIdentifier = "com.apple.widgetkit-extension"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal.widget; SDKROOT = iphoneos; @@ -437,7 +441,7 @@ CODE_SIGN_STYLE = Automatic; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSExtensionPointIdentifier = "com.apple.widgetkit-extension"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.kutesir.KisaniCal.widget; SDKROOT = iphoneos; diff --git a/KisaniCal.xcodeproj/project.xcworkspace/xcuserdata/kutesir.xcuserdatad/UserInterfaceState.xcuserstate b/KisaniCal.xcodeproj/project.xcworkspace/xcuserdata/kutesir.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..077aa3259b5abc4bac2587162b829b1d55359157 GIT binary patch literal 25582 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 I&)UWRABU2gegFUf literal 0 HcmV?d00001 diff --git a/KisaniCal/Components/FloatingTabState.swift b/KisaniCal/Components/FloatingTabState.swift new file mode 100644 index 0000000..f1591d6 --- /dev/null +++ b/KisaniCal/Components/FloatingTabState.swift @@ -0,0 +1,52 @@ +import SwiftUI + +@MainActor +final class FloatingTabState: ObservableObject { + @Published private(set) var isCollapsed = false + private var lastY: CGFloat = 0 + + func report(scrollY: CGFloat) { + let delta = scrollY - lastY + guard abs(delta) > 1.5 else { return } + let shouldCollapse = delta < 0 // content Y decreases → user scrolling down + lastY = scrollY + guard shouldCollapse != isCollapsed else { return } + withAnimation(KisaniSpring.snappy) { + isCollapsed = shouldCollapse + } + } + + func resetOffset() { + lastY = 0 + } +} + +// MARK: — Scroll tracker + +private struct ScrollYKey: PreferenceKey { + static let defaultValue: CGFloat = 0 + static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() } +} + +private struct TabBarScrollModifier: ViewModifier { + @EnvironmentObject private var tabState: FloatingTabState + + func body(content: Content) -> some View { + content + .background( + GeometryReader { geo in + Color.clear + .preference(key: ScrollYKey.self, value: geo.frame(in: .global).minY) + } + ) + .onPreferenceChange(ScrollYKey.self) { y in + tabState.report(scrollY: y) + } + } +} + +extension View { + func trackScrollForTabBar() -> some View { + modifier(TabBarScrollModifier()) + } +} diff --git a/KisaniCal/ContentView.swift b/KisaniCal/ContentView.swift index 9024147..7001d7a 100644 --- a/KisaniCal/ContentView.swift +++ b/KisaniCal/ContentView.swift @@ -11,6 +11,7 @@ struct ContentView: View { @AppStorage("hasOnboarded") private var hasOnboarded = false @State private var showOnboarding = false @State private var selectedTab = 0 + @StateObject private var tabState = FloatingTabState() @State private var iPadSelection: Int? = 0 @State private var calIconImage: Image = ContentView.buildCalIcon() @@ -135,16 +136,19 @@ struct ContentView: View { .tabBarInset() } .tint(AppColors.accent) + .onChange(of: selectedTab) { _ in tabState.resetOffset() } KisaniTabBar( selection: $selectedTab, calIcon: calIconImage, showMatrix: showMatrixTab, - showWorkout: showWorkoutTab + showWorkout: showWorkoutTab, + isCollapsed: tabState.isCollapsed ) .padding(.horizontal, 24) .padding(.bottom, 8) } + .environmentObject(tabState) .onAppear { UITabBar.appearance().isHidden = true } } @@ -191,6 +195,7 @@ struct KisaniTabBar: View { let calIcon: Image var showMatrix: Bool var showWorkout: Bool + var isCollapsed: Bool = false @Environment(\.colorScheme) private var cs private struct Entry: Identifiable { @@ -224,15 +229,15 @@ struct KisaniTabBar: View { } if let img = entry.custom { img - .font(.system(size: 20)) + .font(.system(size: isCollapsed ? 17 : 20)) .foregroundColor(selection == entry.id ? AppColors.accent : AppColors.text(cs)) } else if let icon = entry.sfIcon { Image(systemName: icon) - .font(.system(size: 17, weight: selection == entry.id ? .semibold : .regular)) + .font(.system(size: isCollapsed ? 15 : 17, weight: selection == entry.id ? .semibold : .regular)) .foregroundColor(selection == entry.id ? AppColors.accent : AppColors.text(cs)) } } - .frame(maxWidth: .infinity).frame(height: 50) + .frame(maxWidth: .infinity).frame(height: isCollapsed ? 38 : 50) } .buttonStyle(PressButtonStyle(scale: 0.88)) } @@ -241,8 +246,9 @@ struct KisaniTabBar: View { .background( RoundedRectangle(cornerRadius: 28) .fill(AppColors.surface(cs)) - .shadow(color: .black.opacity(0.10), radius: 20, x: 0, y: 6) + .shadow(color: .black.opacity(isCollapsed ? 0.06 : 0.10), radius: 20, x: 0, y: 6) .shadow(color: .black.opacity(0.04), radius: 4, x: 0, y: 1) ) + .animation(KisaniSpring.snappy, value: isCollapsed) } } diff --git a/KisaniCal/Views/MatrixView.swift b/KisaniCal/Views/MatrixView.swift index 281c99c..0a6f5e6 100644 --- a/KisaniCal/Views/MatrixView.swift +++ b/KisaniCal/Views/MatrixView.swift @@ -128,6 +128,7 @@ struct QuadrantCard: View { // ── Scrollable task list ── ScrollView(showsIndicators: false) { VStack(alignment: .leading, spacing: 0) { + Color.clear.frame(height: 0).trackScrollForTabBar() ForEach(tasks) { task in HStack(alignment: .top, spacing: 6) { RoundedRectangle(cornerRadius: 3) diff --git a/KisaniCal/Views/SettingsView.swift b/KisaniCal/Views/SettingsView.swift index 0fbf864..685650f 100644 --- a/KisaniCal/Views/SettingsView.swift +++ b/KisaniCal/Views/SettingsView.swift @@ -44,6 +44,7 @@ struct SettingsView: View { AppColors.background(cs).ignoresSafeArea() ScrollView(showsIndicators: false) { VStack(spacing: 0) { + Color.clear.frame(height: 0).trackScrollForTabBar() Text("Settings") .font(AppFonts.sans(15, weight: .semibold)) diff --git a/KisaniCal/Views/TodayView.swift b/KisaniCal/Views/TodayView.swift index cf89f39..897183d 100644 --- a/KisaniCal/Views/TodayView.swift +++ b/KisaniCal/Views/TodayView.swift @@ -18,6 +18,7 @@ struct TodayView: View { ScrollView(showsIndicators: false) { VStack(alignment: .leading, spacing: 0) { + Color.clear.frame(height: 0).trackScrollForTabBar() // ── Header ── HStack { diff --git a/KisaniCal/Views/WorkoutView.swift b/KisaniCal/Views/WorkoutView.swift index aeb9033..e842684 100644 --- a/KisaniCal/Views/WorkoutView.swift +++ b/KisaniCal/Views/WorkoutView.swift @@ -710,6 +710,7 @@ struct ManageWorkoutsSheet: View { ScrollView(showsIndicators: false) { VStack(alignment: .leading, spacing: 20) { + Color.clear.frame(height: 0).trackScrollForTabBar() VStack(alignment: .leading, spacing: 8) { Text("PROGRAMS").font(AppFonts.mono(9, weight: .bold)).foregroundColor(AppColors.text3(cs)) diff --git a/project.yml b/project.yml index a6c5f09..bb37048 100644 --- a/project.yml +++ b/project.yml @@ -39,7 +39,7 @@ targets: KisaniCalWidget: type: app-extension platform: iOS - deploymentTarget: "16.0" + deploymentTarget: "17.0" sources: - path: KisaniCalWidget - path: Shared