Admin-Ka iOS 1.0.0 — app native SwiftUI (WKWebView) de la console administration-ka.com
- shell SwiftUI natif enveloppant l'app web live (reste synchronisé) - identité Groupe KA : icône + splash pastille « Ka » orange, fond crème, status bar sombre - WKWebView : cookie de session persistant (reste connecté), pull-to-refresh, barre de progression, liens externes → Safari, écran hors-ligne + réessayer - généré via XcodeGen (project.yml), build simulateur OK (BUILD SUCCEEDED) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
13 changed files +708 −0
added
.gitignore
+6 −0
@@ -0,0 +1,6 @@ | |||||
| 1 | +.DS_Store | ||||
| 2 | +build/ | ||||
| 3 | +DerivedData/ | ||||
| 4 | +*.xcuserstate | ||||
| 5 | +xcuserdata/ | ||||
| 6 | +screenshots/ | ||||
added
AdminKa.xcodeproj/project.pbxproj
+331 −0
@@ -0,0 +1,331 @@ | |||||
| 1 | +// !$*UTF8*$! | ||||
| 2 | +{ | ||||
| 3 | + archiveVersion = 1; | ||||
| 4 | + classes = { | ||||
| 5 | + }; | ||||
| 6 | + objectVersion = 77; | ||||
| 7 | + objects = { | ||||
| 8 | + | ||||
| 9 | +/* Begin PBXBuildFile section */ | ||||
| 10 | + 1CC4EBA58D193E277836B4D5 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2739E070934E8C3D308CD5A /* RootView.swift */; }; | ||||
| 11 | + 20A558D6B8FC5AE82F0E6427 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EC15E5AB22A402E48B8B802 /* WebView.swift */; }; | ||||
| 12 | + 487B17229190CA32181C16ED /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1680D228D3E13F84839372FC /* Theme.swift */; }; | ||||
| 13 | + 4D2A2A6FA8B6C7B1D451F11E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 024D4B21DFAE3435E68D3F6E /* Assets.xcassets */; }; | ||||
| 14 | + C05A68A8575AA602A84238F4 /* AdminKaApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CBC6B9B16C2398EE73269BD /* AdminKaApp.swift */; }; | ||||
| 15 | +/* End PBXBuildFile section */ | ||||
| 16 | + | ||||
| 17 | +/* Begin PBXFileReference section */ | ||||
| 18 | + 024D4B21DFAE3435E68D3F6E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; | ||||
| 19 | + 1680D228D3E13F84839372FC /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; }; | ||||
| 20 | + 7CBC6B9B16C2398EE73269BD /* AdminKaApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdminKaApp.swift; sourceTree = "<group>"; }; | ||||
| 21 | + 7EC15E5AB22A402E48B8B802 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = "<group>"; }; | ||||
| 22 | + 89EB727B6E26717290559869 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; | ||||
| 23 | + A2739E070934E8C3D308CD5A /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = "<group>"; }; | ||||
| 24 | + AA1AA8F42A604E07DEDCDE63 /* AdminKa.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = AdminKa.app; sourceTree = BUILT_PRODUCTS_DIR; }; | ||||
| 25 | +/* End PBXFileReference section */ | ||||
| 26 | + | ||||
| 27 | +/* Begin PBXGroup section */ | ||||
| 28 | + 90F5E72F6AA48CFED030632C /* Sources */ = { | ||||
| 29 | + isa = PBXGroup; | ||||
| 30 | + children = ( | ||||
| 31 | + 7CBC6B9B16C2398EE73269BD /* AdminKaApp.swift */, | ||||
| 32 | + 89EB727B6E26717290559869 /* Info.plist */, | ||||
| 33 | + A2739E070934E8C3D308CD5A /* RootView.swift */, | ||||
| 34 | + 1680D228D3E13F84839372FC /* Theme.swift */, | ||||
| 35 | + 7EC15E5AB22A402E48B8B802 /* WebView.swift */, | ||||
| 36 | + ); | ||||
| 37 | + path = Sources; | ||||
| 38 | + sourceTree = "<group>"; | ||||
| 39 | + }; | ||||
| 40 | + B4F12EC1BBB6B452CD9FE526 = { | ||||
| 41 | + isa = PBXGroup; | ||||
| 42 | + children = ( | ||||
| 43 | + DAFED2B2A69DF6505282D01D /* Resources */, | ||||
| 44 | + 90F5E72F6AA48CFED030632C /* Sources */, | ||||
| 45 | + D36ACF724AF308D7BDA2A549 /* Products */, | ||||
| 46 | + ); | ||||
| 47 | + sourceTree = "<group>"; | ||||
| 48 | + }; | ||||
| 49 | + D36ACF724AF308D7BDA2A549 /* Products */ = { | ||||
| 50 | + isa = PBXGroup; | ||||
| 51 | + children = ( | ||||
| 52 | + AA1AA8F42A604E07DEDCDE63 /* AdminKa.app */, | ||||
| 53 | + ); | ||||
| 54 | + name = Products; | ||||
| 55 | + sourceTree = "<group>"; | ||||
| 56 | + }; | ||||
| 57 | + DAFED2B2A69DF6505282D01D /* Resources */ = { | ||||
| 58 | + isa = PBXGroup; | ||||
| 59 | + children = ( | ||||
| 60 | + 024D4B21DFAE3435E68D3F6E /* Assets.xcassets */, | ||||
| 61 | + ); | ||||
| 62 | + path = Resources; | ||||
| 63 | + sourceTree = "<group>"; | ||||
| 64 | + }; | ||||
| 65 | +/* End PBXGroup section */ | ||||
| 66 | + | ||||
| 67 | +/* Begin PBXNativeTarget section */ | ||||
| 68 | + 8E0C5BDFE3B1E2F7C0127165 /* AdminKa */ = { | ||||
| 69 | + isa = PBXNativeTarget; | ||||
| 70 | + buildConfigurationList = 583958912936F9495C454662 /* Build configuration list for PBXNativeTarget "AdminKa" */; | ||||
| 71 | + buildPhases = ( | ||||
| 72 | + A2AC93E617ED07410C954474 /* Sources */, | ||||
| 73 | + 7771283C46E6761B499F72E7 /* Resources */, | ||||
| 74 | + ); | ||||
| 75 | + buildRules = ( | ||||
| 76 | + ); | ||||
| 77 | + dependencies = ( | ||||
| 78 | + ); | ||||
| 79 | + name = AdminKa; | ||||
| 80 | + packageProductDependencies = ( | ||||
| 81 | + ); | ||||
| 82 | + productName = AdminKa; | ||||
| 83 | + productReference = AA1AA8F42A604E07DEDCDE63 /* AdminKa.app */; | ||||
| 84 | + productType = "com.apple.product-type.application"; | ||||
| 85 | + }; | ||||
| 86 | +/* End PBXNativeTarget section */ | ||||
| 87 | + | ||||
| 88 | +/* Begin PBXProject section */ | ||||
| 89 | + F0E286B46B8531D92B3B311A /* Project object */ = { | ||||
| 90 | + isa = PBXProject; | ||||
| 91 | + attributes = { | ||||
| 92 | + BuildIndependentTargetsInParallel = YES; | ||||
| 93 | + LastUpgradeCheck = 1430; | ||||
| 94 | + TargetAttributes = { | ||||
| 95 | + 8E0C5BDFE3B1E2F7C0127165 = { | ||||
| 96 | + DevelopmentTeam = ""; | ||||
| 97 | + ProvisioningStyle = Automatic; | ||||
| 98 | + }; | ||||
| 99 | + }; | ||||
| 100 | + }; | ||||
| 101 | + buildConfigurationList = 717B4BEBFAACA90E6681012D /* Build configuration list for PBXProject "AdminKa" */; | ||||
| 102 | + developmentRegion = en; | ||||
| 103 | + hasScannedForEncodings = 0; | ||||
| 104 | + knownRegions = ( | ||||
| 105 | + Base, | ||||
| 106 | + en, | ||||
| 107 | + ); | ||||
| 108 | + mainGroup = B4F12EC1BBB6B452CD9FE526; | ||||
| 109 | + minimizedProjectReferenceProxies = 1; | ||||
| 110 | + preferredProjectObjectVersion = 77; | ||||
| 111 | + productRefGroup = D36ACF724AF308D7BDA2A549 /* Products */; | ||||
| 112 | + projectDirPath = ""; | ||||
| 113 | + projectRoot = ""; | ||||
| 114 | + targets = ( | ||||
| 115 | + 8E0C5BDFE3B1E2F7C0127165 /* AdminKa */, | ||||
| 116 | + ); | ||||
| 117 | + }; | ||||
| 118 | +/* End PBXProject section */ | ||||
| 119 | + | ||||
| 120 | +/* Begin PBXResourcesBuildPhase section */ | ||||
| 121 | + 7771283C46E6761B499F72E7 /* Resources */ = { | ||||
| 122 | + isa = PBXResourcesBuildPhase; | ||||
| 123 | + buildActionMask = 2147483647; | ||||
| 124 | + files = ( | ||||
| 125 | + 4D2A2A6FA8B6C7B1D451F11E /* Assets.xcassets in Resources */, | ||||
| 126 | + ); | ||||
| 127 | + runOnlyForDeploymentPostprocessing = 0; | ||||
| 128 | + }; | ||||
| 129 | +/* End PBXResourcesBuildPhase section */ | ||||
| 130 | + | ||||
| 131 | +/* Begin PBXSourcesBuildPhase section */ | ||||
| 132 | + A2AC93E617ED07410C954474 /* Sources */ = { | ||||
| 133 | + isa = PBXSourcesBuildPhase; | ||||
| 134 | + buildActionMask = 2147483647; | ||||
| 135 | + files = ( | ||||
| 136 | + C05A68A8575AA602A84238F4 /* AdminKaApp.swift in Sources */, | ||||
| 137 | + 1CC4EBA58D193E277836B4D5 /* RootView.swift in Sources */, | ||||
| 138 | + 487B17229190CA32181C16ED /* Theme.swift in Sources */, | ||||
| 139 | + 20A558D6B8FC5AE82F0E6427 /* WebView.swift in Sources */, | ||||
| 140 | + ); | ||||
| 141 | + runOnlyForDeploymentPostprocessing = 0; | ||||
| 142 | + }; | ||||
| 143 | +/* End PBXSourcesBuildPhase section */ | ||||
| 144 | + | ||||
| 145 | +/* Begin XCBuildConfiguration section */ | ||||
| 146 | + 1868F3C33EEB2827677E728B /* Release */ = { | ||||
| 147 | + isa = XCBuildConfiguration; | ||||
| 148 | + buildSettings = { | ||||
| 149 | + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||||
| 150 | + CODE_SIGN_IDENTITY = "iPhone Developer"; | ||||
| 151 | + ENABLE_USER_SCRIPT_SANDBOXING = YES; | ||||
| 152 | + INFOPLIST_FILE = Sources/Info.plist; | ||||
| 153 | + LD_RUNPATH_SEARCH_PATHS = ( | ||||
| 154 | + "$(inherited)", | ||||
| 155 | + "@executable_path/Frameworks", | ||||
| 156 | + ); | ||||
| 157 | + PRODUCT_BUNDLE_IDENTIFIER = com.groupeka.adminka; | ||||
| 158 | + SDKROOT = iphoneos; | ||||
| 159 | + TARGETED_DEVICE_FAMILY = "1,2"; | ||||
| 160 | + }; | ||||
| 161 | + name = Release; | ||||
| 162 | + }; | ||||
| 163 | + 3EF528462DA820975843B2FD /* Release */ = { | ||||
| 164 | + isa = XCBuildConfiguration; | ||||
| 165 | + buildSettings = { | ||||
| 166 | + ALWAYS_SEARCH_USER_PATHS = NO; | ||||
| 167 | + CLANG_ANALYZER_NONNULL = YES; | ||||
| 168 | + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; | ||||
| 169 | + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; | ||||
| 170 | + CLANG_CXX_LIBRARY = "libc++"; | ||||
| 171 | + CLANG_ENABLE_MODULES = YES; | ||||
| 172 | + CLANG_ENABLE_OBJC_ARC = YES; | ||||
| 173 | + CLANG_ENABLE_OBJC_WEAK = YES; | ||||
| 174 | + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | ||||
| 175 | + CLANG_WARN_BOOL_CONVERSION = YES; | ||||
| 176 | + CLANG_WARN_COMMA = YES; | ||||
| 177 | + CLANG_WARN_CONSTANT_CONVERSION = YES; | ||||
| 178 | + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | ||||
| 179 | + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | ||||
| 180 | + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; | ||||
| 181 | + CLANG_WARN_EMPTY_BODY = YES; | ||||
| 182 | + CLANG_WARN_ENUM_CONVERSION = YES; | ||||
| 183 | + CLANG_WARN_INFINITE_RECURSION = YES; | ||||
| 184 | + CLANG_WARN_INT_CONVERSION = YES; | ||||
| 185 | + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | ||||
| 186 | + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | ||||
| 187 | + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | ||||
| 188 | + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | ||||
| 189 | + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; | ||||
| 190 | + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | ||||
| 191 | + CLANG_WARN_STRICT_PROTOTYPES = YES; | ||||
| 192 | + CLANG_WARN_SUSPICIOUS_MOVE = YES; | ||||
| 193 | + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; | ||||
| 194 | + CLANG_WARN_UNREACHABLE_CODE = YES; | ||||
| 195 | + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | ||||
| 196 | + CODE_SIGN_STYLE = Automatic; | ||||
| 197 | + COPY_PHASE_STRIP = NO; | ||||
| 198 | + CURRENT_PROJECT_VERSION = 1; | ||||
| 199 | + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; | ||||
| 200 | + DEVELOPMENT_TEAM = ""; | ||||
| 201 | + ENABLE_NS_ASSERTIONS = NO; | ||||
| 202 | + ENABLE_STRICT_OBJC_MSGSEND = YES; | ||||
| 203 | + GCC_C_LANGUAGE_STANDARD = gnu11; | ||||
| 204 | + GCC_NO_COMMON_BLOCKS = YES; | ||||
| 205 | + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | ||||
| 206 | + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | ||||
| 207 | + GCC_WARN_UNDECLARED_SELECTOR = YES; | ||||
| 208 | + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||||
| 209 | + GCC_WARN_UNUSED_FUNCTION = YES; | ||||
| 210 | + GCC_WARN_UNUSED_VARIABLE = YES; | ||||
| 211 | + IPHONEOS_DEPLOYMENT_TARGET = 16.0; | ||||
| 212 | + MARKETING_VERSION = 1.0.0; | ||||
| 213 | + MTL_ENABLE_DEBUG_INFO = NO; | ||||
| 214 | + MTL_FAST_MATH = YES; | ||||
| 215 | + PRODUCT_NAME = "$(TARGET_NAME)"; | ||||
| 216 | + SDKROOT = iphoneos; | ||||
| 217 | + SWIFT_COMPILATION_MODE = wholemodule; | ||||
| 218 | + SWIFT_OPTIMIZATION_LEVEL = "-O"; | ||||
| 219 | + SWIFT_VERSION = 5.0; | ||||
| 220 | + }; | ||||
| 221 | + name = Release; | ||||
| 222 | + }; | ||||
| 223 | + 4180D4646B0316B143DEBBB4 /* Debug */ = { | ||||
| 224 | + isa = XCBuildConfiguration; | ||||
| 225 | + buildSettings = { | ||||
| 226 | + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||||
| 227 | + CODE_SIGN_IDENTITY = "iPhone Developer"; | ||||
| 228 | + ENABLE_USER_SCRIPT_SANDBOXING = YES; | ||||
| 229 | + INFOPLIST_FILE = Sources/Info.plist; | ||||
| 230 | + LD_RUNPATH_SEARCH_PATHS = ( | ||||
| 231 | + "$(inherited)", | ||||
| 232 | + "@executable_path/Frameworks", | ||||
| 233 | + ); | ||||
| 234 | + PRODUCT_BUNDLE_IDENTIFIER = com.groupeka.adminka; | ||||
| 235 | + SDKROOT = iphoneos; | ||||
| 236 | + TARGETED_DEVICE_FAMILY = "1,2"; | ||||
| 237 | + }; | ||||
| 238 | + name = Debug; | ||||
| 239 | + }; | ||||
| 240 | + D5BA178F1D4A548C72B78A88 /* Debug */ = { | ||||
| 241 | + isa = XCBuildConfiguration; | ||||
| 242 | + buildSettings = { | ||||
| 243 | + ALWAYS_SEARCH_USER_PATHS = NO; | ||||
| 244 | + CLANG_ANALYZER_NONNULL = YES; | ||||
| 245 | + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; | ||||
| 246 | + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; | ||||
| 247 | + CLANG_CXX_LIBRARY = "libc++"; | ||||
| 248 | + CLANG_ENABLE_MODULES = YES; | ||||
| 249 | + CLANG_ENABLE_OBJC_ARC = YES; | ||||
| 250 | + CLANG_ENABLE_OBJC_WEAK = YES; | ||||
| 251 | + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | ||||
| 252 | + CLANG_WARN_BOOL_CONVERSION = YES; | ||||
| 253 | + CLANG_WARN_COMMA = YES; | ||||
| 254 | + CLANG_WARN_CONSTANT_CONVERSION = YES; | ||||
| 255 | + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | ||||
| 256 | + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | ||||
| 257 | + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; | ||||
| 258 | + CLANG_WARN_EMPTY_BODY = YES; | ||||
| 259 | + CLANG_WARN_ENUM_CONVERSION = YES; | ||||
| 260 | + CLANG_WARN_INFINITE_RECURSION = YES; | ||||
| 261 | + CLANG_WARN_INT_CONVERSION = YES; | ||||
| 262 | + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | ||||
| 263 | + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | ||||
| 264 | + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | ||||
| 265 | + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | ||||
| 266 | + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; | ||||
| 267 | + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | ||||
| 268 | + CLANG_WARN_STRICT_PROTOTYPES = YES; | ||||
| 269 | + CLANG_WARN_SUSPICIOUS_MOVE = YES; | ||||
| 270 | + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; | ||||
| 271 | + CLANG_WARN_UNREACHABLE_CODE = YES; | ||||
| 272 | + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | ||||
| 273 | + CODE_SIGN_STYLE = Automatic; | ||||
| 274 | + COPY_PHASE_STRIP = NO; | ||||
| 275 | + CURRENT_PROJECT_VERSION = 1; | ||||
| 276 | + DEBUG_INFORMATION_FORMAT = dwarf; | ||||
| 277 | + DEVELOPMENT_TEAM = ""; | ||||
| 278 | + ENABLE_STRICT_OBJC_MSGSEND = YES; | ||||
| 279 | + ENABLE_TESTABILITY = YES; | ||||
| 280 | + GCC_C_LANGUAGE_STANDARD = gnu11; | ||||
| 281 | + GCC_DYNAMIC_NO_PIC = NO; | ||||
| 282 | + GCC_NO_COMMON_BLOCKS = YES; | ||||
| 283 | + GCC_OPTIMIZATION_LEVEL = 0; | ||||
| 284 | + GCC_PREPROCESSOR_DEFINITIONS = ( | ||||
| 285 | + "$(inherited)", | ||||
| 286 | + "DEBUG=1", | ||||
| 287 | + ); | ||||
| 288 | + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | ||||
| 289 | + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | ||||
| 290 | + GCC_WARN_UNDECLARED_SELECTOR = YES; | ||||
| 291 | + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||||
| 292 | + GCC_WARN_UNUSED_FUNCTION = YES; | ||||
| 293 | + GCC_WARN_UNUSED_VARIABLE = YES; | ||||
| 294 | + IPHONEOS_DEPLOYMENT_TARGET = 16.0; | ||||
| 295 | + MARKETING_VERSION = 1.0.0; | ||||
| 296 | + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; | ||||
| 297 | + MTL_FAST_MATH = YES; | ||||
| 298 | + ONLY_ACTIVE_ARCH = YES; | ||||
| 299 | + PRODUCT_NAME = "$(TARGET_NAME)"; | ||||
| 300 | + SDKROOT = iphoneos; | ||||
| 301 | + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; | ||||
| 302 | + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; | ||||
| 303 | + SWIFT_VERSION = 5.0; | ||||
| 304 | + }; | ||||
| 305 | + name = Debug; | ||||
| 306 | + }; | ||||
| 307 | +/* End XCBuildConfiguration section */ | ||||
| 308 | + | ||||
| 309 | +/* Begin XCConfigurationList section */ | ||||
| 310 | + 583958912936F9495C454662 /* Build configuration list for PBXNativeTarget "AdminKa" */ = { | ||||
| 311 | + isa = XCConfigurationList; | ||||
| 312 | + buildConfigurations = ( | ||||
| 313 | + 4180D4646B0316B143DEBBB4 /* Debug */, | ||||
| 314 | + 1868F3C33EEB2827677E728B /* Release */, | ||||
| 315 | + ); | ||||
| 316 | + defaultConfigurationIsVisible = 0; | ||||
| 317 | + defaultConfigurationName = Debug; | ||||
| 318 | + }; | ||||
| 319 | + 717B4BEBFAACA90E6681012D /* Build configuration list for PBXProject "AdminKa" */ = { | ||||
| 320 | + isa = XCConfigurationList; | ||||
| 321 | + buildConfigurations = ( | ||||
| 322 | + D5BA178F1D4A548C72B78A88 /* Debug */, | ||||
| 323 | + 3EF528462DA820975843B2FD /* Release */, | ||||
| 324 | + ); | ||||
| 325 | + defaultConfigurationIsVisible = 0; | ||||
| 326 | + defaultConfigurationName = Debug; | ||||
| 327 | + }; | ||||
| 328 | +/* End XCConfigurationList section */ | ||||
| 329 | + }; | ||||
| 330 | + rootObject = F0E286B46B8531D92B3B311A /* Project object */; | ||||
| 331 | +} | ||||
added
AdminKa.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+7 −0
@@ -0,0 +1,7 @@ | |||||
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||||
| 2 | +<Workspace | ||||
| 3 | + version = "1.0"> | ||||
| 4 | + <FileRef | ||||
| 5 | + location = "self:"> | ||||
| 6 | + </FileRef> | ||||
| 7 | +</Workspace> | ||||
added
Resources/Assets.xcassets/AppIcon.appiconset/Contents.json
+6 −0
@@ -0,0 +1,6 @@ | |||||
| 1 | +{ | ||||
| 2 | + "images" : [ | ||||
| 3 | + { "filename" : "icon-1024.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" } | ||||
| 4 | + ], | ||||
| 5 | + "info" : { "author" : "xcode", "version" : 1 } | ||||
| 6 | +} | ||||
added
Resources/Assets.xcassets/AppIcon.appiconset/icon-1024.png
+0 −0
Binary file not shown.
added
Resources/Assets.xcassets/Contents.json
+1 −0
@@ -0,0 +1 @@ | |||||
| 1 | +{ "info" : { "author" : "xcode", "version" : 1 } } | ||||
added
Resources/Assets.xcassets/LaunchBackground.colorset/Contents.json
+6 −0
@@ -0,0 +1,6 @@ | |||||
| 1 | +{ | ||||
| 2 | + "colors" : [ | ||||
| 3 | + { "color" : { "color-space" : "srgb", "components" : { "alpha" : "1.000", "blue" : "0.925", "green" : "0.945", "red" : "0.949" } }, "idiom" : "universal" } | ||||
| 4 | + ], | ||||
| 5 | + "info" : { "author" : "xcode", "version" : 1 } | ||||
| 6 | +} | ||||
added
Sources/AdminKaApp.swift
+12 −0
@@ -0,0 +1,12 @@ | |||||
| 1 | +import SwiftUI | ||||
| 2 | + | ||||
| 3 | +@main | ||||
| 4 | +struct AdminKaApp: App { | ||||
| 5 | + var body: some Scene { | ||||
| 6 | + WindowGroup { | ||||
| 7 | + RootView() | ||||
| 8 | + .preferredColorScheme(.light) | ||||
| 9 | + .statusBarHidden(false) | ||||
| 10 | + } | ||||
| 11 | + } | ||||
| 12 | +} | ||||
added
Sources/Info.plist
+49 −0
@@ -0,0 +1,49 @@ | |||||
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||||
| 2 | +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||
| 3 | +<plist version="1.0"> | ||||
| 4 | +<dict> | ||||
| 5 | + <key>CFBundleDevelopmentRegion</key> | ||||
| 6 | + <string>$(DEVELOPMENT_LANGUAGE)</string> | ||||
| 7 | + <key>CFBundleDisplayName</key> | ||||
| 8 | + <string>Admin-Ka</string> | ||||
| 9 | + <key>CFBundleExecutable</key> | ||||
| 10 | + <string>$(EXECUTABLE_NAME)</string> | ||||
| 11 | + <key>CFBundleIdentifier</key> | ||||
| 12 | + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | ||||
| 13 | + <key>CFBundleInfoDictionaryVersion</key> | ||||
| 14 | + <string>6.0</string> | ||||
| 15 | + <key>CFBundleName</key> | ||||
| 16 | + <string>$(PRODUCT_NAME)</string> | ||||
| 17 | + <key>CFBundlePackageType</key> | ||||
| 18 | + <string>APPL</string> | ||||
| 19 | + <key>CFBundleShortVersionString</key> | ||||
| 20 | + <string>1.0.0</string> | ||||
| 21 | + <key>CFBundleVersion</key> | ||||
| 22 | + <string>1</string> | ||||
| 23 | + <key>NSAppTransportSecurity</key> | ||||
| 24 | + <dict> | ||||
| 25 | + <key>NSAllowsArbitraryLoads</key> | ||||
| 26 | + <false/> | ||||
| 27 | + </dict> | ||||
| 28 | + <key>UILaunchScreen</key> | ||||
| 29 | + <dict> | ||||
| 30 | + <key>UIColorName</key> | ||||
| 31 | + <string>LaunchBackground</string> | ||||
| 32 | + </dict> | ||||
| 33 | + <key>UIStatusBarStyle</key> | ||||
| 34 | + <string>UIStatusBarStyleDarkContent</string> | ||||
| 35 | + <key>UISupportedInterfaceOrientations</key> | ||||
| 36 | + <array> | ||||
| 37 | + <string>UIInterfaceOrientationPortrait</string> | ||||
| 38 | + </array> | ||||
| 39 | + <key>UISupportedInterfaceOrientations~ipad</key> | ||||
| 40 | + <array> | ||||
| 41 | + <string>UIInterfaceOrientationPortrait</string> | ||||
| 42 | + <string>UIInterfaceOrientationPortraitUpsideDown</string> | ||||
| 43 | + <string>UIInterfaceOrientationLandscapeLeft</string> | ||||
| 44 | + <string>UIInterfaceOrientationLandscapeRight</string> | ||||
| 45 | + </array> | ||||
| 46 | + <key>UIViewControllerBasedStatusBarAppearance</key> | ||||
| 47 | + <false/> | ||||
| 48 | +</dict> | ||||
| 49 | +</plist> | ||||
added
Sources/RootView.swift
+90 −0
@@ -0,0 +1,90 @@ | |||||
| 1 | +import SwiftUI | ||||
| 2 | + | ||||
| 3 | +struct RootView: View { | ||||
| 4 | + @StateObject private var model = WebModel() | ||||
| 5 | + @State private var showSplash = true | ||||
| 6 | + | ||||
| 7 | + var body: some View { | ||||
| 8 | + ZStack { | ||||
| 9 | + Ka.bg.ignoresSafeArea() | ||||
| 10 | + | ||||
| 11 | + WebView(model: model) | ||||
| 12 | + .ignoresSafeArea(.container, edges: .bottom) | ||||
| 13 | + .opacity(model.loaded ? 1 : 0) | ||||
| 14 | + | ||||
| 15 | + // barre de progression fine en haut pendant le chargement | ||||
| 16 | + if !model.loaded && !model.failed { | ||||
| 17 | + VStack(spacing: 0) { | ||||
| 18 | + GeometryReader { geo in | ||||
| 19 | + Rectangle() | ||||
| 20 | + .fill(Ka.orange) | ||||
| 21 | + .frame(width: geo.size.width * max(0.04, model.progress), height: 3) | ||||
| 22 | + .animation(.easeOut(duration: 0.25), value: model.progress) | ||||
| 23 | + } | ||||
| 24 | + .frame(height: 3) | ||||
| 25 | + Spacer() | ||||
| 26 | + } | ||||
| 27 | + } | ||||
| 28 | + | ||||
| 29 | + if showSplash { splash.transition(.opacity) } | ||||
| 30 | + if model.failed { offline } | ||||
| 31 | + } | ||||
| 32 | + .onChange(of: model.loaded) { loaded in | ||||
| 33 | + if loaded { | ||||
| 34 | + DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { | ||||
| 35 | + withAnimation(.easeInOut(duration: 0.4)) { showSplash = false } | ||||
| 36 | + } | ||||
| 37 | + } | ||||
| 38 | + } | ||||
| 39 | + } | ||||
| 40 | + | ||||
| 41 | + private var splash: some View { | ||||
| 42 | + ZStack { | ||||
| 43 | + Ka.bg.ignoresSafeArea() | ||||
| 44 | + VStack(spacing: 18) { | ||||
| 45 | + KaMark(size: 92) | ||||
| 46 | + Text("Admin-Ka") | ||||
| 47 | + .font(.system(size: 26, weight: .heavy, design: .rounded)) | ||||
| 48 | + .foregroundColor(Ka.ink) | ||||
| 49 | + Text("Console Claude Code · Groupe KA") | ||||
| 50 | + .font(.system(size: 13, weight: .semibold, design: .rounded)) | ||||
| 51 | + .foregroundColor(Ka.muted) | ||||
| 52 | + if !model.failed { | ||||
| 53 | + ProgressView().tint(Ka.orange).padding(.top, 6) | ||||
| 54 | + } | ||||
| 55 | + } | ||||
| 56 | + } | ||||
| 57 | + } | ||||
| 58 | + | ||||
| 59 | + private var offline: some View { | ||||
| 60 | + ZStack { | ||||
| 61 | + Ka.bg.ignoresSafeArea() | ||||
| 62 | + VStack(spacing: 16) { | ||||
| 63 | + KaMark(size: 72) | ||||
| 64 | + Text("Hors ligne") | ||||
| 65 | + .font(.system(size: 22, weight: .heavy, design: .rounded)) | ||||
| 66 | + .foregroundColor(Ka.ink) | ||||
| 67 | + Text("Impossible de joindre administration-ka.com") | ||||
| 68 | + .font(.system(size: 14, weight: .medium, design: .rounded)) | ||||
| 69 | + .foregroundColor(Ka.muted) | ||||
| 70 | + .multilineTextAlignment(.center) | ||||
| 71 | + .padding(.horizontal, 40) | ||||
| 72 | + Button { | ||||
| 73 | + showSplash = true | ||||
| 74 | + model.reload() | ||||
| 75 | + } label: { | ||||
| 76 | + Text("Réessayer") | ||||
| 77 | + .font(.system(size: 16, weight: .heavy, design: .rounded)) | ||||
| 78 | + .foregroundColor(Ka.ink) | ||||
| 79 | + .padding(.horizontal, 26).padding(.vertical, 13) | ||||
| 80 | + .background( | ||||
| 81 | + Capsule().fill(Ka.orange) | ||||
| 82 | + .overlay(Capsule().strokeBorder(Ka.ink, lineWidth: 2)) | ||||
| 83 | + ) | ||||
| 84 | + .shadow(color: Ka.ink, radius: 0, x: 3, y: 3) | ||||
| 85 | + } | ||||
| 86 | + .padding(.top, 6) | ||||
| 87 | + } | ||||
| 88 | + } | ||||
| 89 | + } | ||||
| 90 | +} | ||||
added
Sources/Theme.swift
+44 −0
@@ -0,0 +1,44 @@ | |||||
| 1 | +import SwiftUI | ||||
| 2 | + | ||||
| 3 | +// Identité Groupe KA (mêmes valeurs que l'app web) | ||||
| 4 | +enum Ka { | ||||
| 5 | + static let bg = Color(hex: 0xF2F1EC) | ||||
| 6 | + static let card = Color(hex: 0xFCFBF8) | ||||
| 7 | + static let ink = Color(hex: 0x1A1611) | ||||
| 8 | + static let orange = Color(hex: 0xF97316) | ||||
| 9 | + static let muted = Color(hex: 0x6D675C) | ||||
| 10 | + | ||||
| 11 | + static let url = URL(string: "https://www.administration-ka.com")! | ||||
| 12 | +} | ||||
| 13 | + | ||||
| 14 | +extension Color { | ||||
| 15 | + init(hex: UInt, alpha: Double = 1) { | ||||
| 16 | + self.init( | ||||
| 17 | + .sRGB, | ||||
| 18 | + red: Double((hex >> 16) & 0xff) / 255, | ||||
| 19 | + green: Double((hex >> 8) & 0xff) / 255, | ||||
| 20 | + blue: Double(hex & 0xff) / 255, | ||||
| 21 | + opacity: alpha | ||||
| 22 | + ) | ||||
| 23 | + } | ||||
| 24 | +} | ||||
| 25 | + | ||||
| 26 | +// Pastille « Ka » réutilisable (splash + états) | ||||
| 27 | +struct KaMark: View { | ||||
| 28 | + var size: CGFloat = 84 | ||||
| 29 | + var body: some View { | ||||
| 30 | + RoundedRectangle(cornerRadius: size * 0.28, style: .continuous) | ||||
| 31 | + .fill(Ka.orange) | ||||
| 32 | + .overlay( | ||||
| 33 | + RoundedRectangle(cornerRadius: size * 0.28, style: .continuous) | ||||
| 34 | + .strokeBorder(Ka.ink, lineWidth: max(2, size * 0.035)) | ||||
| 35 | + ) | ||||
| 36 | + .overlay( | ||||
| 37 | + Text("Ka") | ||||
| 38 | + .font(.system(size: size * 0.42, weight: .heavy, design: .rounded)) | ||||
| 39 | + .foregroundColor(Ka.ink) | ||||
| 40 | + ) | ||||
| 41 | + .frame(width: size, height: size) | ||||
| 42 | + .shadow(color: Ka.ink.opacity(0.18), radius: 0, x: size * 0.05, y: size * 0.05) | ||||
| 43 | + } | ||||
| 44 | +} | ||||
added
Sources/WebView.swift
+111 −0
@@ -0,0 +1,111 @@ | |||||
| 1 | +import SwiftUI | ||||
| 2 | +import WebKit | ||||
| 3 | +import UIKit | ||||
| 4 | + | ||||
| 5 | +// État partagé entre le WKWebView et l'interface SwiftUI | ||||
| 6 | +final class WebModel: ObservableObject { | ||||
| 7 | + @Published var progress: Double = 0 | ||||
| 8 | + @Published var loaded = false | ||||
| 9 | + @Published var failed = false | ||||
| 10 | + var reloadRequested = false | ||||
| 11 | + var webView: WKWebView? | ||||
| 12 | + | ||||
| 13 | + func reload() { | ||||
| 14 | + failed = false | ||||
| 15 | + loaded = false | ||||
| 16 | + progress = 0 | ||||
| 17 | + if let wv = webView { | ||||
| 18 | + if wv.url == nil { wv.load(URLRequest(url: Ka.url)) } else { wv.reload() } | ||||
| 19 | + } | ||||
| 20 | + } | ||||
| 21 | +} | ||||
| 22 | + | ||||
| 23 | +struct WebView: UIViewRepresentable { | ||||
| 24 | + @ObservedObject var model: WebModel | ||||
| 25 | + | ||||
| 26 | + func makeCoordinator() -> Coordinator { Coordinator(model: model) } | ||||
| 27 | + | ||||
| 28 | + func makeUIView(context: Context) -> WKWebView { | ||||
| 29 | + let cfg = WKWebViewConfiguration() | ||||
| 30 | + cfg.websiteDataStore = .default() // persiste le cookie de session (reste connecté) | ||||
| 31 | + cfg.allowsInlineMediaPlayback = true | ||||
| 32 | + cfg.defaultWebpagePreferences.allowsContentJavaScript = true | ||||
| 33 | + | ||||
| 34 | + let wv = WKWebView(frame: .zero, configuration: cfg) | ||||
| 35 | + wv.navigationDelegate = context.coordinator | ||||
| 36 | + wv.uiDelegate = context.coordinator | ||||
| 37 | + wv.allowsBackForwardNavigationGestures = false | ||||
| 38 | + wv.scrollView.bounces = true | ||||
| 39 | + wv.scrollView.contentInsetAdjustmentBehavior = .never | ||||
| 40 | + wv.isOpaque = false | ||||
| 41 | + wv.backgroundColor = UIColor(Ka.bg) | ||||
| 42 | + wv.scrollView.backgroundColor = UIColor(Ka.bg) | ||||
| 43 | + wv.customUserAgent = "AdminKa-iOS/1.0 (Groupe KA console)" | ||||
| 44 | + | ||||
| 45 | + // pull-to-refresh natif | ||||
| 46 | + let rc = UIRefreshControl() | ||||
| 47 | + rc.tintColor = UIColor(Ka.orange) | ||||
| 48 | + rc.addTarget(context.coordinator, action: #selector(Coordinator.onRefresh(_:)), for: .valueChanged) | ||||
| 49 | + wv.scrollView.refreshControl = rc | ||||
| 50 | + | ||||
| 51 | + context.coordinator.observe(wv) | ||||
| 52 | + model.webView = wv | ||||
| 53 | + wv.load(URLRequest(url: Ka.url)) | ||||
| 54 | + return wv | ||||
| 55 | + } | ||||
| 56 | + | ||||
| 57 | + func updateUIView(_ uiView: WKWebView, context: Context) {} | ||||
| 58 | + | ||||
| 59 | + final class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate { | ||||
| 60 | + let model: WebModel | ||||
| 61 | + private var obs: NSKeyValueObservation? | ||||
| 62 | + init(model: WebModel) { self.model = model } | ||||
| 63 | + | ||||
| 64 | + func observe(_ wv: WKWebView) { | ||||
| 65 | + obs = wv.observe(\.estimatedProgress, options: [.new]) { [weak self] wv, _ in | ||||
| 66 | + DispatchQueue.main.async { self?.model.progress = wv.estimatedProgress } | ||||
| 67 | + } | ||||
| 68 | + } | ||||
| 69 | + | ||||
| 70 | + @objc func onRefresh(_ sender: UIRefreshControl) { | ||||
| 71 | + model.webView?.reload() | ||||
| 72 | + } | ||||
| 73 | + | ||||
| 74 | + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { | ||||
| 75 | + webView.scrollView.refreshControl?.endRefreshing() | ||||
| 76 | + DispatchQueue.main.async { | ||||
| 77 | + withAnimation(.easeOut(duration: 0.35)) { self.model.loaded = true } | ||||
| 78 | + self.model.failed = false | ||||
| 79 | + } | ||||
| 80 | + } | ||||
| 81 | + | ||||
| 82 | + func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { fail(error) } | ||||
| 83 | + func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { fail(error) } | ||||
| 84 | + private func fail(_ error: Error) { | ||||
| 85 | + let ns = error as NSError | ||||
| 86 | + if ns.code == NSURLErrorCancelled { return } | ||||
| 87 | + DispatchQueue.main.async { | ||||
| 88 | + self.model.webView?.scrollView.refreshControl?.endRefreshing() | ||||
| 89 | + self.model.failed = true | ||||
| 90 | + } | ||||
| 91 | + } | ||||
| 92 | + | ||||
| 93 | + // liens externes (target=_blank / http externes) → Safari | ||||
| 94 | + func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, | ||||
| 95 | + for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { | ||||
| 96 | + if let url = navigationAction.request.url { UIApplication.shared.open(url) } | ||||
| 97 | + return nil | ||||
| 98 | + } | ||||
| 99 | + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, | ||||
| 100 | + decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { | ||||
| 101 | + if let url = navigationAction.request.url, let host = url.host, | ||||
| 102 | + navigationAction.navigationType == .linkActivated, | ||||
| 103 | + host != Ka.url.host { | ||||
| 104 | + UIApplication.shared.open(url) | ||||
| 105 | + decisionHandler(.cancel) | ||||
| 106 | + return | ||||
| 107 | + } | ||||
| 108 | + decisionHandler(.allow) | ||||
| 109 | + } | ||||
| 110 | + } | ||||
| 111 | +} | ||||
added
project.yml
+45 −0
@@ -0,0 +1,45 @@ | |||||
| 1 | +name: AdminKa | ||||
| 2 | +options: | ||||
| 3 | + bundleIdPrefix: com.groupeka | ||||
| 4 | + deploymentTarget: | ||||
| 5 | + iOS: "16.0" | ||||
| 6 | + createIntermediateGroups: true | ||||
| 7 | +settings: | ||||
| 8 | + base: | ||||
| 9 | + MARKETING_VERSION: "1.0.0" | ||||
| 10 | + CURRENT_PROJECT_VERSION: "1" | ||||
| 11 | + DEVELOPMENT_TEAM: "" | ||||
| 12 | + CODE_SIGN_STYLE: Automatic | ||||
| 13 | + SWIFT_VERSION: "5.0" | ||||
| 14 | +targets: | ||||
| 15 | + AdminKa: | ||||
| 16 | + type: application | ||||
| 17 | + platform: iOS | ||||
| 18 | + sources: | ||||
| 19 | + - Sources | ||||
| 20 | + - Resources | ||||
| 21 | + info: | ||||
| 22 | + path: Sources/Info.plist | ||||
| 23 | + properties: | ||||
| 24 | + CFBundleDisplayName: Admin-Ka | ||||
| 25 | + CFBundleShortVersionString: "1.0.0" | ||||
| 26 | + CFBundleVersion: "1" | ||||
| 27 | + UILaunchScreen: | ||||
| 28 | + UIColorName: LaunchBackground | ||||
| 29 | + UISupportedInterfaceOrientations: | ||||
| 30 | + - UIInterfaceOrientationPortrait | ||||
| 31 | + UISupportedInterfaceOrientations~ipad: | ||||
| 32 | + - UIInterfaceOrientationPortrait | ||||
| 33 | + - UIInterfaceOrientationPortraitUpsideDown | ||||
| 34 | + - UIInterfaceOrientationLandscapeLeft | ||||
| 35 | + - UIInterfaceOrientationLandscapeRight | ||||
| 36 | + UIStatusBarStyle: UIStatusBarStyleDarkContent | ||||
| 37 | + UIViewControllerBasedStatusBarAppearance: false | ||||
| 38 | + NSAppTransportSecurity: | ||||
| 39 | + NSAllowsArbitraryLoads: false | ||||
| 40 | + settings: | ||||
| 41 | + base: | ||||
| 42 | + PRODUCT_BUNDLE_IDENTIFIER: com.groupeka.adminka | ||||
| 43 | + ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon | ||||
| 44 | + TARGETED_DEVICE_FAMILY: "1,2" | ||||
| 45 | + ENABLE_USER_SCRIPT_SANDBOXING: "YES" | ||||
| 46 | |||||