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 | ||